xref: /aoo42x/main/svx/source/dialog/framelink.cxx (revision 2baf5de7)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include <svx/framelink.hxx>
31 
32 #include <math.h>
33 #include <vcl/outdev.hxx>
34 #include <editeng/borderline.hxx>
35 
36 // ----------------------------------------------------------------------------
37 
38 /** Define to select the drawing mode of thin dotted lines.
39 
40     0 = Draw lines using an own implementation (recommended). Draws always
41         little dots in an appropriate distance.
42     1 = Draw dotted lines using vcl/LineInfo. Results in dashed lines instead
43         of dotted lines, which may look ugly for diagonal lines.
44  */
45 #define SVX_FRAME_USE_LINEINFO 0
46 
47 // ----------------------------------------------------------------------------
48 
49 #if SVX_FRAME_USE_LINEINFO
50 #include <vcl/lineinfo.hxx>
51 #endif
52 
53 namespace svx {
54 namespace frame {
55 
56 // ============================================================================
57 // ============================================================================
58 
59 namespace {
60 
61 typedef std::vector< Point > PointVec;
62 
63 // ----------------------------------------------------------------------------
64 // Link result structs for horizontal and vertical lines and borders.
65 
66 /** Result struct used by the horizontal/vertical frame link functions.
67 
68     This struct is used to return coordinate offsets for one end of a single
69     line in a frame border, i.e. the left end of the primary line of a
70     horizontal frame border.
71 
72     1) Usage for horizontal lines
73 
74     If this struct is returned by the lclLinkHorFrameBorder() function, each
75     member refers to the X coordinate of one edge of a single line end in a
76     horizontal frame border. They specify an offset to modify this coordinate
77     when the line is painted. The values in this struct may change a
78     rectangular line shape into a line with slanted left or right border, which
79     is used to connect the line with diagonal lines.
80 
81     Usage for a left line end:          Usage for a right line end:
82                 mnOffs1                         mnOffs1
83                 <------->                       <------->
84                     +-------------------------------+
85                     | the original horizontal line  |
86                     +-------------------------------+
87                 <------->                       <------->
88                 mnOffs2                         mnOffs2
89 
90     2) Usage for vertical lines
91 
92     If this struct is returned by the lclLinkVerFrameBorder() function, each
93     member refers to the Y coordinate of one edge of a single line end in a
94     vertical frame border. They specify an offset to modify this coordinate
95     when the line is painted. The values in this struct may change a
96     rectangular line shape into a line with slanted top or bottom border, which
97     is used to connect the line with diagonal lines.
98 
99     Usage for a top line end:       mnOffs1 ^               ^ mnOffs2
100                                             |   +-------+   |
101                                             v   |       |   v
102                                                 |       |
103                                                 |       |
104                 the original vertical line ---> |       |
105                                                 |       |
106                                                 |       |
107                                             ^   |       |   ^
108                                             |   +-------+   |
109     Usage for a bottom line end:    mnOffs1 v               v mnOffs2
110  */
111 struct LineEndResult
112 {
113     long                mnOffs1;    /// Offset for top or left edge, dependent of context.
114     long                mnOffs2;    /// Offset for bottom or right edge, dependent of context
115 
116     inline explicit     LineEndResult() : mnOffs1( 0 ), mnOffs2( 0 ) {}
117 
118     inline void         Swap() { std::swap( mnOffs1, mnOffs2 ); }
119     inline void         Negate() { mnOffs1 = -mnOffs1; mnOffs2 = -mnOffs2; }
120 };
121 
122 /** Result struct used by the horizontal/vertical frame link functions.
123 
124     This struct contains the linking results for one end of a frame border,
125     including both the primary and secondary line ends.
126  */
127 struct BorderEndResult
128 {
129     LineEndResult       maPrim;     /// Result for primary line.
130     LineEndResult       maSecn;     /// Result for secondary line.
131 
132     inline void         Negate() { maPrim.Negate(); maSecn.Negate(); }
133 };
134 
135 /** Result struct used by the horizontal/vertical frame link functions.
136 
137     This struct contains the linking results for both frame border ends, and
138     therefore for the complete frame border.
139  */
140 struct BorderResult
141 {
142     BorderEndResult     maBeg;      /// Result for begin of border line (left or top end).
143     BorderEndResult     maEnd;      /// Result for end of border line (right or bottom end).
144 };
145 
146 // ----------------------------------------------------------------------------
147 // Link result structs for diagonal lines and borders.
148 
149 /** Result struct used by the diagonal frame link functions.
150 
151     This struct contains the linking results for one line of a diagonal frame
152     border.
153  */
154 struct DiagLineResult
155 {
156     long                mnLClip;    /// Offset for left border of clipping rectangle.
157     long                mnRClip;    /// Offset for right border of clipping rectangle.
158     long                mnTClip;    /// Offset for top border of clipping rectangle.
159     long                mnBClip;    /// Offset for bottom border of clipping rectangle.
160 
161     inline explicit     DiagLineResult() : mnLClip( 0 ), mnRClip( 0 ), mnTClip( 0 ), mnBClip( 0 ) {}
162 };
163 
164 /** Result struct used by the diagonal frame link functions.
165 
166     This struct contains the linking results for one diagonal frame border.
167  */
168 struct DiagBorderResult
169 {
170     DiagLineResult      maPrim;     /// Result for primary line.
171     DiagLineResult      maSecn;     /// Result for secondary line.
172 };
173 
174 /** Result struct used by the diagonal frame link functions.
175 
176     This struct contains the linking results for both diagonal frame borders.
177  */
178 struct DiagBordersResult
179 {
180     DiagBorderResult    maTLBR;     /// Result for top-left to bottom-right frame border.
181     DiagBorderResult    maBLTR;     /// Result for bottom-left to top-right frame border.
182 };
183 
184 // ----------------------------------------------------------------------------
185 
186 /** A helper struct containing two points of a line.
187  */
188 struct LinePoints
189 {
190     Point               maBeg;      /// Start position of the line.
191     Point               maEnd;      /// End position of the line.
192 
193     explicit            LinePoints( const Point& rBeg, const Point& rEnd ) :
194                             maBeg( rBeg ), maEnd( rEnd ) {}
195     explicit            LinePoints( const Rectangle& rRect, bool bTLBR ) :
196                             maBeg( bTLBR ? rRect.TopLeft() : rRect.TopRight() ),
197                             maEnd( bTLBR ? rRect.BottomRight() : rRect.BottomLeft() ) {}
198 };
199 
200 // ============================================================================
201 
202 /** Rounds and casts a double value to a long value. */
203 inline long lclD2L( double fValue )
204 {
205     return static_cast< long >( (fValue < 0.0) ? (fValue - 0.5) : (fValue + 0.5) );
206 }
207 
208 /** Converts a width in twips to a width in another map unit (specified by fScale). */
209 sal_uInt16 lclScaleValue( long nValue, double fScale, sal_uInt16 nMaxWidth )
210 {
211     // convert any width except 0 to at least 1 unit
212     // #i61324# 1 twip must scale to 1/100mm
213     return nValue ? static_cast< sal_uInt16 >( std::min< long >( std::max(
214         static_cast< long >( nValue * fScale ), 1L ), nMaxWidth ) ) : 0;
215 }
216 
217 // ----------------------------------------------------------------------------
218 // Line width offset calculation.
219 
220 /** Returns the start offset of the single/primary line across the frame border.
221 
222     All following lclGet*Beg() and lclGet*End() functions return sub units to
223     increase the computational accuracy, where 256 sub units are equal to
224     1 map unit of the used OutputDevice.
225 
226     The following pictures show the upper end of a vertical frame border and
227     illustrates the return values of all following lclGet*Beg() and lclGet*End()
228     functions. The first picture shows a single frame border, the second picture
229     shows a double frame border.
230 
231     The functions regard the reference point handling mode of the passed border
232     style.
233     REFMODE_CENTERED:
234         All returned offsets are relative to the middle position of the frame
235         border (offsets left of the middle are returned negative, offsets right
236         of the middle are returned positive).
237     REFMODE_BEGIN:
238         All returned offsets are relative to the begin of the frame border
239         (lclGetBeg() always returns 0).
240     REFMODE_END:
241         All returned offsets are relative to the end of the frame border
242         (lclGetEnd() always returns 0).
243 
244                                                         |<- lclGetEnd()
245                        |<- lclGetBeforeBeg()            |<- lclGetPrimEnd()
246                        |                                |
247                        ||<- lclGetBeg()                 ||<- lclGetBehindEnd()
248                        ||                               ||
249                        |#################################|
250        direction of |   #################################
251           the frame |   #################################
252           border is |   #################################
253            vertical |   #################################
254                     v   #################################
255                                         |
256                                         |<- middle of the frame border
257 
258 
259                                          lclGetDistEnd() ->||<- lclGetSecnBeg()
260                                                            ||
261           lclGetBeg() ->|   lclGetDistBeg() ->|            ||           |<- lclGetEnd()
262                         |                     |            ||           |
263     lclGetBeforeBeg()->||  lclGetPrimEnd() ->||            ||           ||<- lclGetBehindEnd()
264                        ||                    ||            ||           ||
265                        |######################|            |#############|
266        direction of |   ######################              #############
267           the frame |   ######################              #############
268           border is |   ######################              #############
269            vertical |   ######################  |           #############
270                     v   ######################  |           #############
271                         primary line            |           secondary line
272                                                 |
273                                                 |<- middle of the frame border
274 
275     @return
276         The start offset of the single/primary line relative to the reference
277         position of the frame border (sub units; 0 for invisible or one pixel
278         wide single frame styles).
279  */
280 long lclGetBeg( const Style& rBorder )
281 {
282     long nPos = 0;
283     switch( rBorder.GetRefMode() )
284     {
285         case REFMODE_CENTERED:  if( rBorder.Prim() ) nPos = -128 * (rBorder.GetWidth() - 1); break;
286         case REFMODE_END:       if( rBorder.Prim() ) nPos = -256 * (rBorder.GetWidth() - 1); break;
287         case REFMODE_BEGIN:     break;
288     }
289     return nPos;
290 }
291 
292 /** Returns the end offset of the single/secondary line across the frame border.
293     @descr  See description of lclGetBeg() for an illustration.
294     @return  The end offset of the single/secondary line relative to the
295     reference position of the frame border (sub units; 0 for invisible or one
296     pixel wide single frame styles). */
297 long lclGetEnd( const Style& rBorder )
298 {
299     long nPos = 0;
300     switch( rBorder.GetRefMode() )
301     {
302         case REFMODE_CENTERED:  if( rBorder.Prim() ) nPos = 128 * (rBorder.GetWidth() - 1); break;
303         case REFMODE_BEGIN:     if( rBorder.Prim() ) nPos = 256 * (rBorder.GetWidth() - 1); break;
304         case REFMODE_END:     break;
305     }
306     return nPos;
307 }
308 
309 /** Returns the end offset of the primary line across the frame border.
310     @descr  See description of lclGetBeg() for an illustration.
311     @return  The end offset of the primary line relative to the reference
312     position of the frame border (sub units; the end of the primary line in a
313     double frame style, otherwise the same as lclGetEnd()). */
314 inline long lclGetPrimEnd( const Style& rBorder )
315 { return rBorder.Prim() ? (lclGetBeg( rBorder ) + 256 * (rBorder.Prim() - 1)) : 0; }
316 
317 /** Returns the start offset of the secondary line across the frame border.
318     @descr  See description of lclGetBeg() for an illustration.
319     @return  The start offset of the secondary line relative to the reference
320     position of the frame border (sub units; 0 for single/invisible border
321     styles). */
322 inline long lclGetSecnBeg( const Style& rBorder )
323 { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * (rBorder.Secn() - 1)) : 0; }
324 
325 /** Returns the start offset of the distance space across the frame border.
326     @descr  See description of lclGetBeg() for an illustration.
327     @return  The start offset of the distance space relative to the reference
328     position of the frame border (sub units; 0 for single/invisible border
329     styles). */
330 inline long lclGetDistBeg( const Style& rBorder )
331 { return rBorder.Secn() ? (lclGetBeg( rBorder ) + 256 * rBorder.Prim()) : 0; }
332 
333 /** Returns the end offset of the distance space across the frame border.
334     @descr  See description of lclGetBeg() for an illustration.
335     @return  The end offset of the distance space relative to the reference
336     position of the frame border (sub units; 0 for single/invisible border
337     styles). */
338 inline long lclGetDistEnd( const Style& rBorder )
339 { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * rBorder.Secn()) : 0; }
340 
341 /** Returns the offset before start of single/primary line across the frame border.
342     @descr  See description of lclGetBeg() for an illustration.
343     @return  The offset directly before start of single/primary line relative
344     to the reference position of the frame border (sub units; a value one less
345     than lclGetBeg() for visible frame styles, or 0 for invisible frame style). */
346 inline long lclGetBeforeBeg( const Style& rBorder )
347 { return rBorder.Prim() ? (lclGetBeg( rBorder ) - 256) : 0; }
348 
349 /** Returns the offset behind end of single/secondary line across the frame border.
350     @descr  See description of lclGetBeg() for an illustration.
351     @return  The offset directly behind end of single/secondary line relative
352     to the reference position of the frame border (sub units; a value one
353     greater than lclGetEnd() for visible frame styles, or 0 for invisible frame
354     style). */
355 inline long lclGetBehindEnd( const Style& rBorder )
356 { return rBorder.Prim() ? (lclGetEnd( rBorder ) + 256) : 0; }
357 
358 // ============================================================================
359 // Linking functions
360 // ============================================================================
361 
362 // ----------------------------------------------------------------------------
363 // Linking of single horizontal line ends.
364 
365 /** Calculates X offsets for the left end of a single horizontal frame border.
366 
367     See DrawHorFrameBorder() function for a description of all parameters.
368 
369     @param rResult
370         (out-param) The contained values (sub units) specify offsets for the
371         X coordinates of the left line end.
372  */
373 void lclLinkLeftEnd_Single(
374         LineEndResult& rResult, const Style& rBorder,
375         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
376 {
377     // both vertical and diagonal frame borders are double
378     if( rLFromT.Secn() && rLFromB.Secn() && rLFromTR.Secn() && rLFromBR.Secn() )
379     {
380         // take left position of upper and lower secondary start
381         rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
382         rResult.mnOffs2 = GetTLDiagOffset( lclGetEnd( rBorder ), lclGetSecnBeg( rLFromBR ), rLFromBR.GetAngle() );
383     }
384     else
385     {
386         // both vertical frame borders are double
387         if( rLFromT.Secn() && rLFromB.Secn() )
388 		{
389             rResult.mnOffs1 = (!rLFromTR.Secn() && !rLFromBR.Secn() && (rLFromT.GetWidth() == rLFromB.GetWidth())) ?
390                 // don't overdraw vertical borders with equal width
391                 lclGetBehindEnd( rLFromT ) :
392                 // take leftmost start of both secondary lines (#46488#)
393                 std::min( lclGetSecnBeg( rLFromT ), lclGetSecnBeg( rLFromB ) );
394 		}
395 
396         // single border with equal width coming from left
397         else if( !rLFromL.Secn() && (rLFromL.Prim() == rBorder.Prim()) )
398             // draw to connection point
399             rResult.mnOffs1 = 0;
400 
401         // single border coming from left
402         else if( !rLFromL.Secn() && rLFromL.Prim() )
403         {
404             if( rLFromL.Prim() == rBorder.Prim() )
405                 // draw to reference position, if from left has equal width
406                 rResult.mnOffs1 = 0;
407             else
408                 rResult.mnOffs1 = (rLFromL < rBorder) ?
409                     // take leftmost start of both frame borders, if from left is thinner
410                     std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
411                     // do not overdraw vertical, if from left is thicker
412                     std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
413         }
414 
415         // no border coming from left
416         else if( !rLFromL.Prim() )
417             // don't overdraw vertical borders with equal width
418             rResult.mnOffs1 = (rLFromT.GetWidth() == rLFromB.GetWidth()) ?
419                 lclGetBehindEnd( rLFromT ) :
420                 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) );
421 
422         // double frame border coming from left and from top
423         else if( rLFromT.Secn() )
424             // do not overdraw the vertical double frame border
425             rResult.mnOffs1 = lclGetBehindEnd( rLFromT );
426 
427         // double frame border coming from left and from bottom
428         else if( rLFromB.Secn() )
429             // do not overdraw the vertical double frame border
430             rResult.mnOffs1 = lclGetBehindEnd( rLFromB );
431 
432         // double frame border coming from left, both vertical frame borders are single or off
433         else
434             // draw from leftmost start of both frame borders, if from left is not thicker
435             rResult.mnOffs1 = (rLFromL <= rBorder) ?
436                 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
437                 std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
438 
439         // bottom-left point is equal to top-left point (results in rectangle)
440         rResult.mnOffs2 = rResult.mnOffs1;
441     }
442 }
443 
444 /** Calculates X offsets for the left end of a primary horizontal line.
445 
446     See DrawHorFrameBorder() function for a description of all parameters.
447 
448     @param rResult
449         (out-param) The contained values (sub units) specify offsets for the
450         X coordinates of the left end of the primary line.
451  */
452 void lclLinkLeftEnd_Prim(
453         LineEndResult& rResult, const Style& rBorder,
454         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )
455 {
456     // double diagonal frame border coming from top right
457     if( rLFromTR.Secn() )
458     {
459         // draw from where secondary diagonal line meets the own primary
460         rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
461         rResult.mnOffs2 = GetBLDiagOffset( lclGetPrimEnd( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
462     }
463 
464     // no or single diagonal frame border - ignore it
465     else
466     {
467         // double frame border coming from top
468         if( rLFromT.Secn() )
469             // draw from left edge of secondary vertical
470             rResult.mnOffs1 = lclGetSecnBeg( rLFromT );
471 
472         // double frame border coming from left (from top is not double)
473         else if( rLFromL.Secn() )
474             // do not overdraw single frame border coming from top
475             rResult.mnOffs1 = (rLFromL.GetWidth() == rBorder.GetWidth()) ?
476                 0 : lclGetBehindEnd( rLFromT );
477 
478         // double frame border coming from bottom (from top and from left are not double)
479         else if( rLFromB.Secn() )
480             // draw from left edge of primary vertical from bottom
481             rResult.mnOffs1 = lclGetBeg( rLFromB );
482 
483         // no other frame border is double
484         else
485             // do not overdraw vertical frame borders
486             rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
487 
488         // bottom-left point is equal to top-left point (results in rectangle)
489         rResult.mnOffs2 = rResult.mnOffs1;
490     }
491 }
492 
493 /** Calculates X offsets for the left end of a secondary horizontal line.
494 
495     See DrawHorFrameBorder() function for a description of all parameters.
496 
497     @param rResult
498         (out-param) The contained values (sub units) specify offsets for the
499         X coordinates of the left end of the secondary line.
500  */
501 void lclLinkLeftEnd_Secn(
502         LineEndResult& rResult, const Style& rBorder,
503         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
504 {
505     /*  Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */
506     lclLinkLeftEnd_Prim( rResult, rBorder.Mirror(), rLFromBR, rLFromB, rLFromL.Mirror(), rLFromT, rLFromTR );
507     rResult.Swap();
508 }
509 
510 // ----------------------------------------------------------------------------
511 // Linking of horizontal frame border ends.
512 
513 /** Calculates X offsets for the left end of a horizontal frame border.
514 
515     This function can be used for single and double frame borders.
516     See DrawHorFrameBorder() function for a description of all parameters.
517 
518     @param rResult
519         (out-param) The contained values (sub units) specify offsets for the
520         X coordinates of the left end of the line(s) in the frame border.
521  */
522 void lclLinkLeftEnd(
523         BorderEndResult& rResult, const Style& rBorder,
524         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
525 {
526     if( rBorder.Secn() )
527     {
528         // current frame border is double
529         lclLinkLeftEnd_Prim( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
530         lclLinkLeftEnd_Secn( rResult.maSecn, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
531     }
532     else if( rBorder.Prim() )
533     {
534         // current frame border is single
535         lclLinkLeftEnd_Single( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
536     }
537     else
538     {
539         DBG_ERRORFILE( "lclLinkLeftEnd - called for invisible frame style" );
540     }
541 }
542 
543 /** Calculates X offsets for the right end of a horizontal frame border.
544 
545     This function can be used for single and double frame borders.
546     See DrawHorFrameBorder() function for a description of all parameters.
547 
548     @param rResult
549         (out-param) The contained values (sub units) specify offsets for the
550         X coordinates of the right end of the line(s) in the frame border.
551  */
552 void lclLinkRightEnd(
553         BorderEndResult& rResult, const Style& rBorder,
554         const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
555 {
556     /*  Recycle lclLinkLeftEnd() function with mirrored vertical borders. */
557     lclLinkLeftEnd( rResult, rBorder, rRFromTL.Mirror(), rRFromT.Mirror(), rRFromR, rRFromB.Mirror(), rRFromBL.Mirror() );
558     rResult.Negate();
559 }
560 
561 // ----------------------------------------------------------------------------
562 // Linking of horizontal and vertical frame borders.
563 
564 /** Calculates X offsets for all line ends of a horizontal frame border.
565 
566     This function can be used for single and double frame borders.
567     See DrawHorFrameBorder() function for a description of all parameters.
568 
569     @param rResult
570         (out-param) The contained values (sub units) specify offsets for the
571         X coordinates of both ends of the line(s) in the frame border. To get
572         the actual X coordinates to draw the lines, these offsets have to be
573         added to the X coordinates of the reference points of the frame border
574         (the offsets may be negative).
575  */
576 void lclLinkHorFrameBorder(
577         BorderResult& rResult, const Style& rBorder,
578         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
579         const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
580 {
581     lclLinkLeftEnd( rResult.maBeg, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
582     lclLinkRightEnd( rResult.maEnd, rBorder, rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
583 }
584 
585 /** Calculates Y offsets for all line ends of a vertical frame border.
586 
587     This function can be used for single and double frame borders.
588     See DrawVerFrameBorder() function for a description of all parameters.
589 
590     @param rResult
591         (out-param) The contained values (sub units) specify offsets for the
592         Y coordinates of both ends of the line(s) in the frame border. To get
593         the actual Y coordinates to draw the lines, these offsets have to be
594         added to the Y coordinates of the reference points of the frame border
595         (the offsets may be negative).
596  */
597 void lclLinkVerFrameBorder(
598         BorderResult& rResult, const Style& rBorder,
599         const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
600         const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR )
601 {
602     /*  Recycle lclLinkHorFrameBorder() function with correct parameters. The
603         frame border is virtually mirrored at the top-left to bottom-right
604         diagonal. rTFromBR and rBFromTL are mirrored to process their primary
605         and secondary lines correctly. */
606     lclLinkHorFrameBorder( rResult, rBorder,
607         rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR.Mirror(),
608         rBFromTL.Mirror(), rBFromL, rBFromB, rBFromR, rBFromTR );
609 }
610 
611 // ============================================================================
612 
613 #if 0
614 //  Not used anymore, but not deleted for possible future usage.
615 
616 /** Returns the relative Y offset of the intercept point of 2 diagonal borders.
617 
618     @param nTLBROffs
619         Width offset (sub units) across the top-left to bottom-right frame border.
620     @param fTLBRAngle
621         Inner angle between horizontal and top-left to bottom-right frame border.
622     @param nBLTROffs
623         Width offset (sub units) across the bottom-left to top-right frame border.
624     @param fBLTRAngle
625         Inner angle between horizontal and bottom-left to top-right frame border.
626     @return
627         Offset (sub units) relative to the Y position of the centered intercept
628         point of both diagonal frame borders.
629  */
630 long lclGetDiagDiagOffset( long nTLBROffs, double fTLBRAngle, long nBLTROffs, double fBLTRAngle )
631 {
632     double fASin = sin( fTLBRAngle );
633     double fACos = cos( fTLBRAngle );
634     double fAX = -nTLBROffs * fASin;
635     double fAY = nTLBROffs * fACos;
636     double fRAX = fACos;
637     double fRAY = fASin;
638 
639     double fBSin = sin( fBLTRAngle );
640     double fBCos = cos( fBLTRAngle );
641     double fBX = nBLTROffs * fBSin;
642     double fBY = nBLTROffs * fBCos;
643     double fRBX = fBCos;
644     double fRBY = -fBSin;
645 
646     double fKA = (fRBX * (fBY - fAY) - fRBY * (fBX - fAX)) / (fRBX * fRAY - fRAX * fRBY);
647     return lclD2L( fAY + fKA * fRAY );
648 }
649 #endif
650 
651 // ----------------------------------------------------------------------------
652 // Linking of diagonal frame borders.
653 
654 /** Calculates clipping offsets for a top-left to bottom-right frame border.
655 
656     This function can be used for single and double frame borders.
657     See DrawDiagFrameBorders() function for a description of all parameters.
658 
659     @param rResult
660         (out-param) The contained values (sub units) specify offsets for all
661         borders of the reference rectangle containing the diagonal frame border.
662  */
663 void lclLinkTLBRFrameBorder(
664         DiagBorderResult& rResult, const Style& rBorder,
665         const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL )
666 {
667     bool bIsDbl = rBorder.Secn() != 0;
668 
669     rResult.maPrim.mnLClip = lclGetBehindEnd( rTLFromB );
670     rResult.maPrim.mnRClip = (bIsDbl && rBRFromT.Secn()) ? lclGetEnd( rBRFromT ) : lclGetBeforeBeg( rBRFromT );
671     rResult.maPrim.mnTClip = (bIsDbl && rTLFromR.Secn()) ? lclGetBeg( rTLFromR ) : lclGetBehindEnd( rTLFromR );
672     rResult.maPrim.mnBClip = lclGetBeforeBeg( rBRFromL );
673 
674     if( bIsDbl )
675     {
676         rResult.maSecn.mnLClip = rTLFromB.Secn() ? lclGetBeg( rTLFromB ) : lclGetBehindEnd( rTLFromB );
677         rResult.maSecn.mnRClip = lclGetBeforeBeg( rBRFromT );
678         rResult.maSecn.mnTClip = lclGetBehindEnd( rTLFromR );
679         rResult.maSecn.mnBClip = rBRFromL.Secn() ? lclGetEnd( rBRFromL ) : lclGetBeforeBeg( rBRFromL );
680     }
681 }
682 
683 /** Calculates clipping offsets for a bottom-left to top-right frame border.
684 
685     This function can be used for single and double frame borders.
686     See DrawDiagFrameBorders() function for a description of all parameters.
687 
688     @param rResult
689         (out-param) The contained values (sub units) specify offsets for all
690         borders of the reference rectangle containing the diagonal frame border.
691  */
692 void lclLinkBLTRFrameBorder(
693         DiagBorderResult& rResult, const Style& rBorder,
694         const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
695 {
696     bool bIsDbl = rBorder.Secn() != 0;
697 
698     rResult.maPrim.mnLClip = lclGetBehindEnd( rBLFromT );
699     rResult.maPrim.mnRClip = (bIsDbl && rTRFromB.Secn()) ? lclGetEnd( rTRFromB ) : lclGetBeforeBeg( rTRFromB );
700     rResult.maPrim.mnTClip = lclGetBehindEnd( rTRFromL );
701     rResult.maPrim.mnBClip = (bIsDbl && rBLFromR.Secn()) ? lclGetEnd( rBLFromR ) : lclGetBeforeBeg( rBLFromR );
702 
703     if( bIsDbl )
704     {
705         rResult.maSecn.mnLClip = rBLFromT.Secn() ? lclGetBeg( rBLFromT ) : lclGetBehindEnd( rBLFromT );
706         rResult.maSecn.mnRClip = lclGetBeforeBeg( rTRFromB );
707         rResult.maSecn.mnTClip = rTRFromL.Secn() ? lclGetBeg( rTRFromL ) : lclGetBehindEnd( rTRFromL );
708         rResult.maSecn.mnBClip = lclGetBeforeBeg( rBLFromR );
709     }
710 }
711 
712 /** Calculates clipping offsets for both diagonal frame borders.
713 
714     This function can be used for single and double frame borders.
715     See DrawDiagFrameBorders() function for a description of all parameters.
716 
717     @param rResult
718         (out-param) The contained values (sub units) specify offsets for all
719         borders of the reference rectangle containing the diagonal frame
720         borders.
721  */
722 void lclLinkDiagFrameBorders(
723         DiagBordersResult& rResult, const Style& rTLBR, const Style& rBLTR,
724         const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
725         const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
726 {
727     lclLinkTLBRFrameBorder( rResult.maTLBR, rTLBR, rTLFromB, rTLFromR, rBRFromT, rBRFromL );
728     lclLinkBLTRFrameBorder( rResult.maBLTR, rBLTR, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
729 }
730 
731 // ============================================================================
732 // Drawing functions
733 // ============================================================================
734 
735 // ----------------------------------------------------------------------------
736 // Simple helper functions
737 
738 /** Converts sub units to OutputDevice map units. */
739 inline long lclToMapUnit( long nSubUnits )
740 {
741     return ((nSubUnits < 0) ? (nSubUnits - 127) : (nSubUnits + 128)) / 256;
742 }
743 
744 /** Converts a point in sub units to an OutputDevice point. */
745 inline Point lclToMapUnit( long nSubXPos, long nSubYPos )
746 {
747     return Point( lclToMapUnit( nSubXPos ), lclToMapUnit( nSubYPos ) );
748 }
749 
750 /** Returns a polygon constructed from a vector of points. */
751 inline Polygon lclCreatePolygon( const PointVec& rPoints )
752 {
753     return Polygon( static_cast< sal_uInt16 >( rPoints.size() ), &rPoints[ 0 ] );
754 }
755 
756 /** Returns a polygon constructed from the four passed points. */
757 Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 )
758 {
759     PointVec aPoints;
760     aPoints.reserve( 4 );
761     aPoints.push_back( rP1 );
762     aPoints.push_back( rP2 );
763     aPoints.push_back( rP3 );
764     aPoints.push_back( rP4 );
765     return lclCreatePolygon( aPoints );
766 }
767 
768 /** Returns a polygon constructed from the five passed points. */
769 Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4, const Point& rP5 )
770 {
771     PointVec aPoints;
772     aPoints.reserve( 5 );
773     aPoints.push_back( rP1 );
774     aPoints.push_back( rP2 );
775     aPoints.push_back( rP3 );
776     aPoints.push_back( rP4 );
777     aPoints.push_back( rP5 );
778     return lclCreatePolygon( aPoints );
779 }
780 
781 /** Returns a polygon constructed from the two passed line positions. */
782 inline Polygon lclCreatePolygon( const LinePoints& rPoints1, const LinePoints& rPoints2 )
783 {
784     return lclCreatePolygon( rPoints1.maBeg, rPoints1.maEnd, rPoints2.maEnd, rPoints2.maBeg );
785 }
786 
787 /** Sets the color of the passed frame style to the output device.
788 
789     Sets the line color and fill color in the output device.
790 
791     @param rDev
792         The output device the color has to be set to. The old colors are pushed
793         onto the device's stack and can be restored with a call to
794         OutputDevice::Pop(). Please take care about the correct calling order
795         of Pop() if this function is used with other functions pushing
796         something onto the stack.
797     @param rStyle
798         The border style that contains the line color to be set to the device.
799  */
800 void lclSetColorToOutDev( OutputDevice& rDev, const Style& rStyle, const Color* pForceColor )
801 {
802     rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
803     rDev.SetLineColor( pForceColor ? *pForceColor : rStyle.GetColor() );
804     rDev.SetFillColor( pForceColor ? *pForceColor : rStyle.GetColor() );
805 }
806 
807 // ----------------------------------------------------------------------------
808 // Generic drawing functions.
809 
810 /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */
811 void lclDrawThinLine( OutputDevice& rDev, const Point& rBeg, const Point& rEnd, bool bDotted )
812 {
813 #if SVX_FRAME_USE_LINEINFO
814     if( bDotted && (rBeg != rEnd) )
815     {
816 // using LineInfo for dotted lines looks ugly and does not work well for diagonal lines
817         LineInfo aLineInfo( LINE_DASH, 1 );
818         aLineInfo.SetDotCount( 1 );
819         aLineInfo.SetDotLen( 1 );
820         aLineInfo.SetDistance( 3 );
821         rDev.DrawLine( rBeg, rEnd, aLineInfo );
822     }
823 #else
824     Point aBeg( rDev.LogicToPixel( rBeg ) );
825     Point aEnd( rDev.LogicToPixel( rEnd ) );
826     if( bDotted && (aBeg != aEnd) )
827     {
828         bool bHor = Abs( aEnd.X() - aBeg.X() ) > Abs( aEnd.Y() - aBeg.Y() );
829         const Point& rBegPos( bHor ? ((aBeg.X() < aEnd.X()) ? aBeg : aEnd) : ((aBeg.Y() < aEnd.Y()) ? aBeg : aEnd ) );
830         const Point& rEndPos( (rBegPos == aBeg) ? aEnd : aBeg );
831 
832         long nAlongBeg = bHor ? rBegPos.X() : rBegPos.Y();
833         long nAcrssBeg = bHor ? rBegPos.Y() : rBegPos.X();
834         long nAlongSize = (bHor ? rEndPos.X() : rEndPos.Y()) - nAlongBeg;
835         long nAcrssSize = (bHor ? rEndPos.Y() : rEndPos.X()) - nAcrssBeg;
836         double fGradient = static_cast< double >( nAcrssSize ) / nAlongSize;
837 
838         PointVec aPoints;
839         aPoints.reserve( (nAlongSize + 1) / 2 );
840         for( long nAlongIdx = 0; nAlongIdx <= nAlongSize; nAlongIdx += 2 )
841         {
842             long nAl = nAlongBeg + nAlongIdx;
843             long nAc = nAcrssBeg + lclD2L( fGradient * nAlongIdx );
844             aPoints.push_back( Point( bHor ? nAl : nAc, bHor ? nAc : nAl ) );
845         }
846 
847         rDev.Push( PUSH_MAPMODE );
848         rDev.SetMapMode( MAP_PIXEL );
849         rDev.DrawPixel( lclCreatePolygon( aPoints ) );
850         rDev.Pop(); // map mode
851     }
852 #endif
853     else
854         rDev.DrawLine( rBeg, rEnd );
855 }
856 
857 /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */
858 inline void lclDrawThinLine( OutputDevice& rDev, const LinePoints& rPoints, bool bDotted )
859 {
860     lclDrawThinLine( rDev, rPoints.maBeg, rPoints.maEnd, bDotted );
861 }
862 
863 /** Draws a polygon with four points into the passed output device. */
864 inline void lclDrawPolygon( OutputDevice& rDev, const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 )
865 {
866     rDev.DrawPolygon( lclCreatePolygon( rP1, rP2, rP3, rP4 ) );
867 }
868 
869 /** Draws a polygon specified by two borders into the passed output device. */
870 inline void lclDrawPolygon( OutputDevice& rDev, const LinePoints& rPoints1, const LinePoints& rPoints2 )
871 {
872     rDev.DrawPolygon( lclCreatePolygon( rPoints1, rPoints2 ) );
873 }
874 
875 // ============================================================================
876 // Drawing of horizontal frame borders.
877 
878 /** Draws a horizontal thin or thick line into the passed output device.
879 
880     The X coordinates of the edges of the line are adjusted according to the
881     passed LineEndResult structs. A one pixel wide line can be drawn dotted.
882  */
883 void lclDrawHorLine(
884         OutputDevice& rDev,
885         const Point& rLPos, const LineEndResult& rLRes,
886         const Point& rRPos, const LineEndResult& rRRes,
887         long nTOffs, long nBOffs, bool bDotted )
888 {
889     LinePoints aTPoints( rLPos + lclToMapUnit( rLRes.mnOffs1, nTOffs ), rRPos + lclToMapUnit( rRRes.mnOffs1, nTOffs ) );
890     if( nTOffs == nBOffs )
891         lclDrawThinLine( rDev, aTPoints, bDotted );
892     else
893     {
894         LinePoints aBPoints( rLPos + lclToMapUnit( rLRes.mnOffs2, nBOffs ), rRPos + lclToMapUnit( rRRes.mnOffs2, nBOffs ) );
895         lclDrawPolygon( rDev, aTPoints, aBPoints );
896     }
897 }
898 
899 /** Draws a horizontal frame border into the passed output device.
900 
901     @param rLPos
902         The top-left or bottom-left reference point of the diagonal frame border.
903     @param rRPos
904         The top-right or bottom-right reference point of the diagonal frame border.
905     @param rBorder
906         The frame style used to draw the border.
907     @param rResult
908         The X coordinates of the edges of all lines of the frame border are
909         adjusted according to the offsets contained here.
910  */
911 void lclDrawHorFrameBorder(
912         OutputDevice& rDev, const Point& rLPos, const Point& rRPos,
913         const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
914 {
915     DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" );
916     DBG_ASSERT( rLPos.X() <= rRPos.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" );
917     DBG_ASSERT( rLPos.Y() == rRPos.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" );
918     if( rLPos.X() <= rRPos.X() )
919     {
920         lclSetColorToOutDev( rDev, rBorder, pForceColor );
921         lclDrawHorLine( rDev, rLPos, rResult.maBeg.maPrim, rRPos, rResult.maEnd.maPrim,
922             lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
923         if( rBorder.Secn() )
924             lclDrawHorLine( rDev, rLPos, rResult.maBeg.maSecn, rRPos, rResult.maEnd.maSecn,
925                 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
926         rDev.Pop(); // colors
927     }
928 }
929 
930 // ----------------------------------------------------------------------------
931 // Drawing of vertical frame borders.
932 
933 /** Draws a vertical thin or thick line into the passed output device.
934 
935     The Y coordinates of the edges of the line are adjusted according to the
936     passed LineEndResult structs. A one pixel wide line can be drawn dotted.
937  */
938 void lclDrawVerLine(
939         OutputDevice& rDev,
940         const Point& rTPos, const LineEndResult& rTRes,
941         const Point& rBPos, const LineEndResult& rBRes,
942         long nLOffs, long nROffs, bool bDotted )
943 {
944     LinePoints aLPoints( rTPos + lclToMapUnit( nLOffs, rTRes.mnOffs1 ), rBPos + lclToMapUnit( nLOffs, rBRes.mnOffs1 ) );
945     if( nLOffs == nROffs )
946         lclDrawThinLine( rDev, aLPoints, bDotted );
947     else
948     {
949         LinePoints aRPoints( rTPos + lclToMapUnit( nROffs, rTRes.mnOffs2 ), rBPos + lclToMapUnit( nROffs, rBRes.mnOffs2 ) );
950         lclDrawPolygon( rDev, aLPoints, aRPoints );
951     }
952 }
953 
954 /** Draws a vertical frame border into the passed output device.
955 
956     @param rTPos
957         The top-left or top-right reference point of the diagonal frame border.
958     @param rBPos
959         The bottom-left or bottom-right reference point of the diagonal frame border.
960     @param rBorder
961         The frame style used to draw the border.
962     @param rResult
963         The Y coordinates of the edges of all lines of the frame border are
964         adjusted according to the offsets contained here.
965  */
966 void lclDrawVerFrameBorder(
967         OutputDevice& rDev, const Point& rTPos, const Point& rBPos,
968         const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
969 {
970     DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" );
971     DBG_ASSERT( rTPos.Y() <= rBPos.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" );
972     DBG_ASSERT( rTPos.X() == rBPos.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" );
973     if( rTPos.Y() <= rBPos.Y() )
974     {
975         lclSetColorToOutDev( rDev, rBorder, pForceColor );
976         lclDrawVerLine( rDev, rTPos, rResult.maBeg.maPrim, rBPos, rResult.maEnd.maPrim,
977             lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
978         if( rBorder.Secn() )
979             lclDrawVerLine( rDev, rTPos, rResult.maBeg.maSecn, rBPos, rResult.maEnd.maSecn,
980                 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
981         rDev.Pop(); // colors
982     }
983 }
984 
985 // ============================================================================
986 // Drawing of diagonal frame borders, incudes clipping functions.
987 
988 /** Returns the drawing coordinates for a diagonal thin line.
989 
990     This function can be used for top-left to bottom-right and for bottom-left
991     to top-right lines.
992 
993     @param rRect
994         The reference rectangle of the diagonal frame border.
995     @param bTLBR
996         true = top-left to bottom-right; false = bottom-left to top-right.
997     @param nDiagOffs
998         Width offset (sub units) across the diagonal frame border.
999     @return
1000         A struct containg start and end position of the diagonal line.
1001  */
1002 LinePoints lclGetDiagLineEnds( const Rectangle& rRect, bool bTLBR, long nDiagOffs )
1003 {
1004     LinePoints aPoints( rRect, bTLBR );
1005     bool bVert = rRect.GetWidth() < rRect.GetHeight();
1006     double fAngle = bVert ? GetVerDiagAngle( rRect ) : GetHorDiagAngle( rRect );
1007     // vertical top-left to bottom-right borders are handled mirrored
1008     if( bVert && bTLBR )
1009         nDiagOffs = -nDiagOffs;
1010     long nTOffs = bTLBR ? GetTLDiagOffset( 0, nDiagOffs, fAngle ) : GetTRDiagOffset( 0, nDiagOffs, fAngle );
1011     long nBOffs = bTLBR ? GetBRDiagOffset( 0, nDiagOffs, fAngle ) : GetBLDiagOffset( 0, nDiagOffs, fAngle );
1012     // vertical bottom-left to top-right borders are handled with exchanged end points
1013     if( bVert && !bTLBR )
1014         std::swap( nTOffs, nBOffs );
1015     (bVert ? aPoints.maBeg.Y() : aPoints.maBeg.X()) += lclToMapUnit( nTOffs );
1016     (bVert ? aPoints.maEnd.Y() : aPoints.maEnd.X()) += lclToMapUnit( nBOffs );
1017     return aPoints;
1018 }
1019 
1020 // ----------------------------------------------------------------------------
1021 // Clipping functions for diagonal frame borders.
1022 
1023 /** Limits the clipping region to the inner area of a rectange.
1024 
1025     Takes the values from the passed DiagLineResult struct into account. They
1026     may specify to not clip one or more borders of a rectangle.
1027 
1028     @param rDev
1029         The output device with the clipping region to be modified. The old
1030         clipping region is pushed onto the device's stack and can be restored
1031         with a call to OutputDevice::Pop(). Please take care about the correct
1032         calling order of Pop() if this function is used with other functions
1033         pushing something onto the stack.
1034     @param rRect
1035         The reference rectangle of the diagonal frame borders.
1036     @param rResult
1037         The result struct containing modifies for each border of the reference
1038         rectangle.
1039  */
1040 void lclPushDiagClipRect( OutputDevice& rDev, const Rectangle& rRect, const DiagLineResult& rResult )
1041 {
1042     // PixelToLogic() regards internal offset of the output device
1043     Rectangle aClipRect( rRect );
1044     aClipRect.Left()   += lclToMapUnit( rResult.mnLClip );
1045     aClipRect.Top()    += lclToMapUnit( rResult.mnTClip );
1046     aClipRect.Right()  += lclToMapUnit( rResult.mnRClip );
1047     aClipRect.Bottom() += lclToMapUnit( rResult.mnBClip );
1048     // output device would adjust the rectangle -> invalidate it before
1049     if( (aClipRect.GetWidth() < 1) ||(aClipRect.GetHeight() < 1) )
1050         aClipRect.SetEmpty();
1051 
1052     rDev.Push( PUSH_CLIPREGION );
1053     rDev.IntersectClipRegion( aClipRect );
1054 }
1055 
1056 /** Excludes inner area of a crossing double frame border from clipping region.
1057 
1058     This function is used to modify the clipping region so that it excludes the
1059     inner free area of a double diagonal frame border. This makes it possible
1060     to draw a diagonal frame border in one step without taking care of the
1061     crossing double frame border.
1062 
1063     @param rDev
1064         The output device with the clipping region to be modified. The old
1065         clipping region is pushed onto the device's stack and can be restored
1066         with a call to OutputDevice::Pop(). Please take care about the correct
1067         calling order of Pop() if this function is used with other functions
1068         pushing something onto the stack.
1069     @param rRect
1070         The reference rectangle of the diagonal frame borders.
1071     @param bTLBR
1072         The orientation of the processed frame border (not the orientation of
1073         the crossing frame border).
1074     @param bCrossStyle
1075         The style of the crossing frame border. Must be a double frame style.
1076  */
1077 void lclPushCrossingClipRegion( OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, const Style& rCrossStyle )
1078 {
1079     DBG_ASSERT( rCrossStyle.Secn(), "lclGetCrossingClipRegion - use only for double styles" );
1080     LinePoints aLPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetPrimEnd( rCrossStyle ) ) );
1081     LinePoints aRPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetSecnBeg( rCrossStyle ) ) );
1082 
1083     Region aClipReg;
1084     if( bTLBR )
1085     {
1086         aClipReg = lclCreatePolygon(
1087             aLPoints.maBeg, aLPoints.maEnd, rRect.BottomRight(), rRect.BottomLeft(), rRect.TopLeft() );
1088         aClipReg.Union( lclCreatePolygon(
1089             aRPoints.maBeg, aRPoints.maEnd, rRect.BottomRight(), rRect.TopRight(), rRect.TopLeft() ) );
1090     }
1091     else
1092     {
1093         aClipReg = lclCreatePolygon(
1094             aLPoints.maBeg, aLPoints.maEnd, rRect.BottomLeft(), rRect.TopLeft(), rRect.TopRight() );
1095         aClipReg.Union( lclCreatePolygon(
1096             aRPoints.maBeg, aRPoints.maEnd, rRect.BottomLeft(), rRect.BottomRight(), rRect.TopRight() ) );
1097     }
1098 
1099     rDev.Push( PUSH_CLIPREGION );
1100     rDev.IntersectClipRegion( aClipReg );
1101 }
1102 
1103 // ----------------------------------------------------------------------------
1104 // Drawing functions for diagonal frame borders.
1105 
1106 /** Draws a diagonal thin or thick line into the passed output device.
1107 
1108     The clipping region of the output device is modified according to the
1109     passed DiagLineResult struct. A one pixel wide line can be drawn dotted.
1110  */
1111 void lclDrawDiagLine(
1112         OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1113         const DiagLineResult& rResult, long nDiagOffs1, long nDiagOffs2, bool bDotted )
1114 {
1115     lclPushDiagClipRect( rDev, rRect, rResult );
1116     LinePoints aLPoints( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs1 ) );
1117     if( nDiagOffs1 == nDiagOffs2 )
1118         lclDrawThinLine( rDev, aLPoints, bDotted );
1119     else
1120         lclDrawPolygon( rDev, aLPoints, lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs2 ) );
1121     rDev.Pop(); // clipping region
1122 }
1123 
1124 /** Draws a diagonal frame border into the passed output device.
1125 
1126     The lines of the frame border are drawn interrupted, if the style of the
1127     crossing frame border is double.
1128 
1129     @param rRect
1130         The reference rectangle of the diagonal frame border.
1131     @param bTLBR
1132         The orientation of the diagonal frame border.
1133     @param rBorder
1134         The frame style used to draw the border.
1135     @param rResult
1136         Offsets (sub units) to modify the clipping region of the output device.
1137     @param rCrossStyle
1138         Style of the crossing diagonal frame border.
1139  */
1140 void lclDrawDiagFrameBorder(
1141         OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1142         const Style& rBorder, const DiagBorderResult& rResult, const Style& rCrossStyle,
1143         const Color* pForceColor, bool bDiagDblClip )
1144 {
1145     DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" );
1146 
1147     bool bClip = bDiagDblClip && rCrossStyle.Secn();
1148     if( bClip )
1149         lclPushCrossingClipRegion( rDev, rRect, bTLBR, rCrossStyle );
1150 
1151     lclSetColorToOutDev( rDev, rBorder, pForceColor );
1152     lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maPrim, lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
1153     if( rBorder.Secn() )
1154         lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
1155     rDev.Pop(); // colors
1156 
1157     if( bClip )
1158         rDev.Pop(); // clipping region
1159 }
1160 
1161 /** Draws both diagonal frame borders into the passed output device.
1162 
1163     The lines of each frame border is drawn interrupted, if the style of the
1164     other crossing frame border is double.
1165 
1166     @param rRect
1167         The reference rectangle of the diagonal frame borders.
1168     @param rTLBR
1169         The frame style of the top-left to bottom-right frame border.
1170     @param rBLTR
1171         The frame style of the bottom-left to top-right frame border.
1172     @param rResult
1173         Offsets (sub units) to modify the clipping region of the output device.
1174  */
1175 void lclDrawDiagFrameBorders(
1176         OutputDevice& rDev, const Rectangle& rRect,
1177         const Style& rTLBR, const Style& rBLTR, const DiagBordersResult& rResult,
1178         const Color* pForceColor, bool bDiagDblClip )
1179 {
1180     DBG_ASSERT( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" );
1181     if( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1) )
1182     {
1183         bool bDrawTLBR = rTLBR.Prim() != 0;
1184         bool bDrawBLTR = rBLTR.Prim() != 0;
1185         bool bFirstDrawBLTR = rTLBR.Secn() != 0;
1186 
1187         if( bDrawBLTR && bFirstDrawBLTR )
1188             lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1189         if( bDrawTLBR )
1190             lclDrawDiagFrameBorder( rDev, rRect, true, rTLBR, rResult.maTLBR, rBLTR, pForceColor, bDiagDblClip );
1191         if( bDrawBLTR && !bFirstDrawBLTR )
1192             lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1193     }
1194 }
1195 
1196 // ============================================================================
1197 
1198 } // namespace
1199 
1200 // ============================================================================
1201 // Classes
1202 // ============================================================================
1203 
1204 #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth )
1205 
1206 void Style::Clear()
1207 {
1208     Set( Color(), 0, 0, 0 );
1209 }
1210 
1211 void Style::Set( sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS )
1212 {
1213     /*  nP  nD  nS  ->  mnPrim  mnDist  mnSecn
1214         --------------------------------------
1215         any any 0       nP      0       0
1216         0   any >0      nS      0       0
1217         >0  0   >0      nP      0       0
1218         >0  >0  >0      nP      nD      nS
1219      */
1220     mnPrim = nP ? nP : nS;
1221     mnDist = (nP && nS) ? nD : 0;
1222     mnSecn = (nP && nD) ? nS : 0;
1223 }
1224 
1225 void Style::Set( const Color& rColor, sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS )
1226 {
1227     maColor = rColor;
1228     Set( nP, nD, nS );
1229 }
1230 
1231 void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots )
1232 {
1233     maColor = rBorder.GetColor();
1234 
1235     sal_uInt16 nPrim = rBorder.GetOutWidth();
1236     sal_uInt16 nDist = rBorder.GetDistance();
1237     sal_uInt16 nSecn = rBorder.GetInWidth();
1238 
1239     if( !nSecn )    // no or single frame border
1240     {
1241         Set( SCALEVALUE( nPrim ), 0, 0 );
1242         mbDotted = bUseDots && (0 < nPrim) && (nPrim < 10);
1243     }
1244     else
1245     {
1246         Set( SCALEVALUE( nPrim ), SCALEVALUE( nDist ), SCALEVALUE( nSecn ) );
1247         mbDotted = false;
1248         // Enlarge the style if distance is too small due to rounding losses.
1249         sal_uInt16 nPixWidth = SCALEVALUE( nPrim + nDist + nSecn );
1250         if( nPixWidth > GetWidth() )
1251             mnDist = nPixWidth - mnPrim - mnSecn;
1252         // Shrink the style if it is too thick for the control.
1253         while( GetWidth() > nMaxWidth )
1254         {
1255             // First decrease space between lines.
1256             if( mnDist )
1257                 --mnDist;
1258             // Still too thick? Decrease the line widths.
1259             if( GetWidth() > nMaxWidth )
1260             {
1261                 if( mnPrim && (mnPrim == mnSecn) )
1262                 {
1263                     // Both lines equal - decrease both to keep symmetry.
1264                     --mnPrim;
1265                     --mnSecn;
1266                 }
1267                 else
1268                 {
1269                     // Decrease each line for itself
1270                     if( mnPrim )
1271                         --mnPrim;
1272                     if( (GetWidth() > nMaxWidth) && mnSecn )
1273                         --mnSecn;
1274                 }
1275             }
1276         }
1277     }
1278 }
1279 
1280 void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots )
1281 {
1282     if( pBorder )
1283         Set( *pBorder, fScale, nMaxWidth, bUseDots );
1284     else
1285     {
1286         Clear();
1287         mbDotted = false;
1288     }
1289 }
1290 
1291 Style& Style::ScaleSelf( double fScale, sal_uInt16 nMaxWidth )
1292 {
1293     Set( SCALEVALUE( mnPrim ), SCALEVALUE( mnDist ), SCALEVALUE( mnSecn ) );
1294     return *this;
1295 }
1296 
1297 Style Style::Scale( double fScale, sal_uInt16 nMaxWidth ) const
1298 {
1299     return Style( *this ).ScaleSelf( fScale, nMaxWidth );
1300 }
1301 
1302 Style& Style::MirrorSelf()
1303 {
1304     if( mnSecn )
1305         std::swap( mnPrim, mnSecn );
1306     if( meRefMode != REFMODE_CENTERED )
1307         meRefMode = (meRefMode == REFMODE_BEGIN) ? REFMODE_END : REFMODE_BEGIN;
1308     return *this;
1309 }
1310 
1311 Style Style::Mirror() const
1312 {
1313     return Style( *this ).MirrorSelf();
1314 }
1315 
1316 bool operator==( const Style& rL, const Style& rR )
1317 {
1318     return (rL.Prim() == rR.Prim()) && (rL.Dist() == rR.Dist()) && (rL.Secn() == rR.Secn()) &&
1319         (rL.GetColor() == rR.GetColor()) && (rL.GetRefMode() == rR.GetRefMode()) && (rL.Dotted() == rR.Dotted());
1320 }
1321 
1322 bool operator<( const Style& rL, const Style& rR )
1323 {
1324     // different total widths -> rL<rR, if rL is thinner
1325     sal_uInt16 nLW = rL.GetWidth();
1326     sal_uInt16 nRW = rR.GetWidth();
1327     if( nLW != nRW ) return nLW < nRW;
1328 
1329     // one line double, the other single -> rL<rR, if rL is single
1330     if( (rL.Secn() == 0) != (rR.Secn() == 0) ) return rL.Secn() == 0;
1331 
1332     // both lines double with different distances -> rL<rR, if distance of rL greater
1333     if( (rL.Secn() && rR.Secn()) && (rL.Dist() != rR.Dist()) ) return rL.Dist() > rR.Dist();
1334 
1335     // both lines single and 1 unit thick, only one is dotted -> rL<rR, if rL is dotted
1336     if( (nLW == 1) && (rL.Dotted() != rR.Dotted()) ) return rL.Dotted();
1337 
1338     // seem to be equal
1339     return false;
1340 }
1341 
1342 #undef SCALEVALUE
1343 
1344 // ============================================================================
1345 // Various helper functions
1346 // ============================================================================
1347 
1348 double GetHorDiagAngle( long nWidth, long nHeight )
1349 {
1350     return atan2( static_cast< double >( Abs( nHeight ) ), static_cast< double >( Abs( nWidth ) ) );
1351 }
1352 
1353 // ============================================================================
1354 
1355 long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1356 {
1357     return lclD2L( nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1358 }
1359 
1360 long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1361 {
1362     return lclD2L( -nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1363 }
1364 
1365 long GetBRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1366 {
1367     return -lclD2L( -nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1368 }
1369 
1370 long GetTRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1371 {
1372     return -lclD2L( nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1373 }
1374 
1375 // ============================================================================
1376 
1377 bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
1378         const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
1379         const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
1380 {
1381     return      // returns 1 AND (2a OR 2b)
1382         // 1) only, if both frame borders are equal
1383         (rLBorder == rRBorder)
1384         &&
1385         (
1386             (
1387                 // 2a) if the borders are not double, at least one of the vertical must not be double
1388                 !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn())
1389             )
1390             ||
1391             (
1392                 // 2b) if the borders are double, all other borders must not be double
1393                 rLBorder.Secn() &&
1394                 !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() &&
1395                 !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn()
1396             )
1397         );
1398 }
1399 
1400 // ============================================================================
1401 // Drawing functions
1402 // ============================================================================
1403 
1404 void DrawHorFrameBorder( OutputDevice& rDev,
1405         const Point& rLPos, const Point& rRPos, const Style& rBorder,
1406         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
1407         const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL,
1408         const Color* pForceColor )
1409 {
1410     if( rBorder.Prim() )
1411     {
1412         BorderResult aResult;
1413         lclLinkHorFrameBorder( aResult, rBorder,
1414             rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR,
1415             rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
1416         lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, aResult, pForceColor );
1417     }
1418 }
1419 
1420 void DrawHorFrameBorder( OutputDevice& rDev,
1421         const Point& rLPos, const Point& rRPos, const Style& rBorder,
1422         const Style& rLFromT, const Style& rLFromL, const Style& rLFromB,
1423         const Style& rRFromT, const Style& rRFromR, const Style& rRFromB,
1424         const Color* pForceColor )
1425 {
1426     /*  Recycle complex version of the DrawHorFrameBorder() function with empty diagonals. */
1427     const DiagStyle aNoStyle;
1428     DrawHorFrameBorder(
1429         rDev, rLPos, rRPos, rBorder,
1430         aNoStyle, rLFromT, rLFromL, rLFromB, aNoStyle,
1431         aNoStyle, rRFromT, rRFromR, rRFromB, aNoStyle,
1432         pForceColor );
1433 }
1434 
1435 void DrawHorFrameBorder( OutputDevice& rDev,
1436         const Point& rLPos, const Point& rRPos, const Style& rBorder, const Color* pForceColor )
1437 {
1438     if( rBorder.Prim() )
1439         lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, BorderResult(), pForceColor );
1440 }
1441 
1442 // ----------------------------------------------------------------------------
1443 
1444 void DrawVerFrameBorder( OutputDevice& rDev,
1445         const Point& rTPos, const Point& rBPos, const Style& rBorder,
1446         const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
1447         const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR,
1448         const Color* pForceColor )
1449 {
1450     if( rBorder.Prim() )
1451     {
1452         BorderResult aResult;
1453         lclLinkVerFrameBorder( aResult, rBorder,
1454             rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR,
1455             rBFromTL, rBFromL, rBFromB, rBFromR, rBFromTR );
1456         lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, aResult, pForceColor );
1457     }
1458 }
1459 
1460 void DrawVerFrameBorder( OutputDevice& rDev,
1461         const Point& rTPos, const Point& rBPos, const Style& rBorder,
1462         const Style& rTFromL, const Style& rTFromT, const Style& rTFromR,
1463         const Style& rBFromL, const Style& rBFromB, const Style& rBFromR,
1464         const Color* pForceColor )
1465 {
1466     /*  Recycle complex version of the DrawVerFrameBorder() function with empty diagonals. */
1467     const DiagStyle aNoStyle;
1468     DrawVerFrameBorder(
1469         rDev, rTPos, rBPos, rBorder,
1470         aNoStyle, rTFromL, rTFromT, rTFromR, aNoStyle,
1471         aNoStyle, rBFromL, rBFromB, rBFromR, aNoStyle,
1472         pForceColor );
1473 }
1474 
1475 void DrawVerFrameBorder( OutputDevice& rDev,
1476         const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor )
1477 {
1478     if( rBorder.Prim() )
1479         lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, BorderResult(), pForceColor );
1480 }
1481 
1482 // ----------------------------------------------------------------------------
1483 
1484 void DrawVerFrameBorderSlanted( OutputDevice& rDev,
1485         const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor )
1486 {
1487     DBG_ASSERT( rTPos.Y() < rBPos.Y(), "svx::frame::DrawVerFrameBorderSlanted - wrong order of line ends" );
1488     if( rBorder.Prim() && (rTPos.Y() < rBPos.Y()) )
1489     {
1490         if( rTPos.X() == rBPos.X() )
1491         {
1492             DrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, pForceColor );
1493         }
1494         else
1495         {
1496             const LineEndResult aRes;
1497 
1498             Style aScaled( rBorder );
1499             aScaled.ScaleSelf( 1.0 / cos( GetVerDiagAngle( rTPos, rBPos ) ) );
1500 
1501             lclSetColorToOutDev( rDev, aScaled, pForceColor );
1502             lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes,
1503                 lclGetBeg( aScaled ), lclGetPrimEnd( aScaled ), aScaled.Dotted() );
1504             if( aScaled.Secn() )
1505                 lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes,
1506                     lclGetSecnBeg( aScaled ), lclGetEnd( aScaled ), aScaled.Dotted() );
1507             rDev.Pop(); // colors
1508         }
1509     }
1510 }
1511 
1512 // ============================================================================
1513 
1514 void DrawDiagFrameBorders(
1515         OutputDevice& rDev, const Rectangle& rRect, const Style& rTLBR, const Style& rBLTR,
1516         const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
1517         const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL,
1518         const Color* pForceColor, bool bDiagDblClip )
1519 {
1520     if( rTLBR.Prim() || rBLTR.Prim() )
1521     {
1522         DiagBordersResult aResult;
1523         lclLinkDiagFrameBorders( aResult, rTLBR, rBLTR,
1524             rTLFromB, rTLFromR, rBRFromT, rBRFromL, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
1525         lclDrawDiagFrameBorders( rDev, rRect, rTLBR, rBLTR, aResult, pForceColor, bDiagDblClip );
1526     }
1527 }
1528 
1529 // ============================================================================
1530 
1531 } // namespace frame
1532 } // namespace svx
1533 
1534