xref: /aoo41x/main/svx/source/dialog/framelink.cxx (revision cdf0e10c)
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             rResult.mnOffs1 = (!rLFromTR.Secn() && !rLFromBR.Secn() && (rLFromT.GetWidth() == rLFromB.GetWidth())) ?
389                 // don't overdraw vertical borders with equal width
390                 lclGetBehindEnd( rLFromT ) :
391                 // take leftmost start of both secondary lines (#46488#)
392                 rResult.mnOffs1 = std::min( lclGetSecnBeg( rLFromT ), lclGetSecnBeg( rLFromB ) );
393 
394         // single border with equal width coming from left
395         else if( !rLFromL.Secn() && (rLFromL.Prim() == rBorder.Prim()) )
396             // draw to connection point
397             rResult.mnOffs1 = 0;
398 
399         // single border coming from left
400         else if( !rLFromL.Secn() && rLFromL.Prim() )
401         {
402             if( rLFromL.Prim() == rBorder.Prim() )
403                 // draw to reference position, if from left has equal width
404                 rResult.mnOffs1 = 0;
405             else
406                 rResult.mnOffs1 = (rLFromL < rBorder) ?
407                     // take leftmost start of both frame borders, if from left is thinner
408                     std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
409                     // do not overdraw vertical, if from left is thicker
410                     std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
411         }
412 
413         // no border coming from left
414         else if( !rLFromL.Prim() )
415             // don't overdraw vertical borders with equal width
416             rResult.mnOffs1 = (rLFromT.GetWidth() == rLFromB.GetWidth()) ?
417                 lclGetBehindEnd( rLFromT ) :
418                 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) );
419 
420         // double frame border coming from left and from top
421         else if( rLFromT.Secn() )
422             // do not overdraw the vertical double frame border
423             rResult.mnOffs1 = lclGetBehindEnd( rLFromT );
424 
425         // double frame border coming from left and from bottom
426         else if( rLFromB.Secn() )
427             // do not overdraw the vertical double frame border
428             rResult.mnOffs1 = lclGetBehindEnd( rLFromB );
429 
430         // double frame border coming from left, both vertical frame borders are single or off
431         else
432             // draw from leftmost start of both frame borders, if from left is not thicker
433             rResult.mnOffs1 = (rLFromL <= rBorder) ?
434                 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
435                 std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
436 
437         // bottom-left point is equal to top-left point (results in rectangle)
438         rResult.mnOffs2 = rResult.mnOffs1;
439     }
440 }
441 
442 /** Calculates X offsets for the left end of a primary horizontal line.
443 
444     See DrawHorFrameBorder() function for a description of all parameters.
445 
446     @param rResult
447         (out-param) The contained values (sub units) specify offsets for the
448         X coordinates of the left end of the primary line.
449  */
450 void lclLinkLeftEnd_Prim(
451         LineEndResult& rResult, const Style& rBorder,
452         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )
453 {
454     // double diagonal frame border coming from top right
455     if( rLFromTR.Secn() )
456     {
457         // draw from where secondary diagonal line meets the own primary
458         rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
459         rResult.mnOffs2 = GetBLDiagOffset( lclGetPrimEnd( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
460     }
461 
462     // no or single diagonal frame border - ignore it
463     else
464     {
465         // double frame border coming from top
466         if( rLFromT.Secn() )
467             // draw from left edge of secondary vertical
468             rResult.mnOffs1 = lclGetSecnBeg( rLFromT );
469 
470         // double frame border coming from left (from top is not double)
471         else if( rLFromL.Secn() )
472             // do not overdraw single frame border coming from top
473             rResult.mnOffs1 = (rLFromL.GetWidth() == rBorder.GetWidth()) ?
474                 0 : lclGetBehindEnd( rLFromT );
475 
476         // double frame border coming from bottom (from top and from left are not double)
477         else if( rLFromB.Secn() )
478             // draw from left edge of primary vertical from bottom
479             rResult.mnOffs1 = lclGetBeg( rLFromB );
480 
481         // no other frame border is double
482         else
483             // do not overdraw vertical frame borders
484             rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
485 
486         // bottom-left point is equal to top-left point (results in rectangle)
487         rResult.mnOffs2 = rResult.mnOffs1;
488     }
489 }
490 
491 /** Calculates X offsets for the left end of a secondary horizontal line.
492 
493     See DrawHorFrameBorder() function for a description of all parameters.
494 
495     @param rResult
496         (out-param) The contained values (sub units) specify offsets for the
497         X coordinates of the left end of the secondary line.
498  */
499 void lclLinkLeftEnd_Secn(
500         LineEndResult& rResult, const Style& rBorder,
501         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
502 {
503     /*  Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */
504     lclLinkLeftEnd_Prim( rResult, rBorder.Mirror(), rLFromBR, rLFromB, rLFromL.Mirror(), rLFromT, rLFromTR );
505     rResult.Swap();
506 }
507 
508 // ----------------------------------------------------------------------------
509 // Linking of horizontal frame border ends.
510 
511 /** Calculates X offsets for the left end of a horizontal frame border.
512 
513     This function can be used for single and double frame borders.
514     See DrawHorFrameBorder() function for a description of all parameters.
515 
516     @param rResult
517         (out-param) The contained values (sub units) specify offsets for the
518         X coordinates of the left end of the line(s) in the frame border.
519  */
520 void lclLinkLeftEnd(
521         BorderEndResult& rResult, const Style& rBorder,
522         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
523 {
524     if( rBorder.Secn() )
525     {
526         // current frame border is double
527         lclLinkLeftEnd_Prim( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
528         lclLinkLeftEnd_Secn( rResult.maSecn, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
529     }
530     else if( rBorder.Prim() )
531     {
532         // current frame border is single
533         lclLinkLeftEnd_Single( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
534     }
535     else
536     {
537         DBG_ERRORFILE( "lclLinkLeftEnd - called for invisible frame style" );
538     }
539 }
540 
541 /** Calculates X offsets for the right end of a horizontal frame border.
542 
543     This function can be used for single and double frame borders.
544     See DrawHorFrameBorder() function for a description of all parameters.
545 
546     @param rResult
547         (out-param) The contained values (sub units) specify offsets for the
548         X coordinates of the right end of the line(s) in the frame border.
549  */
550 void lclLinkRightEnd(
551         BorderEndResult& rResult, const Style& rBorder,
552         const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
553 {
554     /*  Recycle lclLinkLeftEnd() function with mirrored vertical borders. */
555     lclLinkLeftEnd( rResult, rBorder, rRFromTL.Mirror(), rRFromT.Mirror(), rRFromR, rRFromB.Mirror(), rRFromBL.Mirror() );
556     rResult.Negate();
557 }
558 
559 // ----------------------------------------------------------------------------
560 // Linking of horizontal and vertical frame borders.
561 
562 /** Calculates X offsets for all line ends of a horizontal frame border.
563 
564     This function can be used for single and double frame borders.
565     See DrawHorFrameBorder() function for a description of all parameters.
566 
567     @param rResult
568         (out-param) The contained values (sub units) specify offsets for the
569         X coordinates of both ends of the line(s) in the frame border. To get
570         the actual X coordinates to draw the lines, these offsets have to be
571         added to the X coordinates of the reference points of the frame border
572         (the offsets may be negative).
573  */
574 void lclLinkHorFrameBorder(
575         BorderResult& rResult, const Style& rBorder,
576         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
577         const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
578 {
579     lclLinkLeftEnd( rResult.maBeg, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
580     lclLinkRightEnd( rResult.maEnd, rBorder, rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
581 }
582 
583 /** Calculates Y offsets for all line ends of a vertical frame border.
584 
585     This function can be used for single and double frame borders.
586     See DrawVerFrameBorder() function for a description of all parameters.
587 
588     @param rResult
589         (out-param) The contained values (sub units) specify offsets for the
590         Y coordinates of both ends of the line(s) in the frame border. To get
591         the actual Y coordinates to draw the lines, these offsets have to be
592         added to the Y coordinates of the reference points of the frame border
593         (the offsets may be negative).
594  */
595 void lclLinkVerFrameBorder(
596         BorderResult& rResult, const Style& rBorder,
597         const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
598         const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR )
599 {
600     /*  Recycle lclLinkHorFrameBorder() function with correct parameters. The
601         frame border is virtually mirrored at the top-left to bottom-right
602         diagonal. rTFromBR and rBFromTL are mirrored to process their primary
603         and secondary lines correctly. */
604     lclLinkHorFrameBorder( rResult, rBorder,
605         rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR.Mirror(),
606         rBFromTL.Mirror(), rBFromL, rBFromB, rBFromR, rBFromTR );
607 }
608 
609 // ============================================================================
610 
611 #if 0
612 //  Not used anymore, but not deleted for possible future usage.
613 
614 /** Returns the relative Y offset of the intercept point of 2 diagonal borders.
615 
616     @param nTLBROffs
617         Width offset (sub units) across the top-left to bottom-right frame border.
618     @param fTLBRAngle
619         Inner angle between horizontal and top-left to bottom-right frame border.
620     @param nBLTROffs
621         Width offset (sub units) across the bottom-left to top-right frame border.
622     @param fBLTRAngle
623         Inner angle between horizontal and bottom-left to top-right frame border.
624     @return
625         Offset (sub units) relative to the Y position of the centered intercept
626         point of both diagonal frame borders.
627  */
628 long lclGetDiagDiagOffset( long nTLBROffs, double fTLBRAngle, long nBLTROffs, double fBLTRAngle )
629 {
630     double fASin = sin( fTLBRAngle );
631     double fACos = cos( fTLBRAngle );
632     double fAX = -nTLBROffs * fASin;
633     double fAY = nTLBROffs * fACos;
634     double fRAX = fACos;
635     double fRAY = fASin;
636 
637     double fBSin = sin( fBLTRAngle );
638     double fBCos = cos( fBLTRAngle );
639     double fBX = nBLTROffs * fBSin;
640     double fBY = nBLTROffs * fBCos;
641     double fRBX = fBCos;
642     double fRBY = -fBSin;
643 
644     double fKA = (fRBX * (fBY - fAY) - fRBY * (fBX - fAX)) / (fRBX * fRAY - fRAX * fRBY);
645     return lclD2L( fAY + fKA * fRAY );
646 }
647 #endif
648 
649 // ----------------------------------------------------------------------------
650 // Linking of diagonal frame borders.
651 
652 /** Calculates clipping offsets for a top-left to bottom-right frame border.
653 
654     This function can be used for single and double frame borders.
655     See DrawDiagFrameBorders() function for a description of all parameters.
656 
657     @param rResult
658         (out-param) The contained values (sub units) specify offsets for all
659         borders of the reference rectangle containing the diagonal frame border.
660  */
661 void lclLinkTLBRFrameBorder(
662         DiagBorderResult& rResult, const Style& rBorder,
663         const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL )
664 {
665     bool bIsDbl = rBorder.Secn() != 0;
666 
667     rResult.maPrim.mnLClip = lclGetBehindEnd( rTLFromB );
668     rResult.maPrim.mnRClip = (bIsDbl && rBRFromT.Secn()) ? lclGetEnd( rBRFromT ) : lclGetBeforeBeg( rBRFromT );
669     rResult.maPrim.mnTClip = (bIsDbl && rTLFromR.Secn()) ? lclGetBeg( rTLFromR ) : lclGetBehindEnd( rTLFromR );
670     rResult.maPrim.mnBClip = lclGetBeforeBeg( rBRFromL );
671 
672     if( bIsDbl )
673     {
674         rResult.maSecn.mnLClip = rTLFromB.Secn() ? lclGetBeg( rTLFromB ) : lclGetBehindEnd( rTLFromB );
675         rResult.maSecn.mnRClip = lclGetBeforeBeg( rBRFromT );
676         rResult.maSecn.mnTClip = lclGetBehindEnd( rTLFromR );
677         rResult.maSecn.mnBClip = rBRFromL.Secn() ? lclGetEnd( rBRFromL ) : lclGetBeforeBeg( rBRFromL );
678     }
679 }
680 
681 /** Calculates clipping offsets for a bottom-left to top-right frame border.
682 
683     This function can be used for single and double frame borders.
684     See DrawDiagFrameBorders() function for a description of all parameters.
685 
686     @param rResult
687         (out-param) The contained values (sub units) specify offsets for all
688         borders of the reference rectangle containing the diagonal frame border.
689  */
690 void lclLinkBLTRFrameBorder(
691         DiagBorderResult& rResult, const Style& rBorder,
692         const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
693 {
694     bool bIsDbl = rBorder.Secn() != 0;
695 
696     rResult.maPrim.mnLClip = lclGetBehindEnd( rBLFromT );
697     rResult.maPrim.mnRClip = (bIsDbl && rTRFromB.Secn()) ? lclGetEnd( rTRFromB ) : lclGetBeforeBeg( rTRFromB );
698     rResult.maPrim.mnTClip = lclGetBehindEnd( rTRFromL );
699     rResult.maPrim.mnBClip = (bIsDbl && rBLFromR.Secn()) ? lclGetEnd( rBLFromR ) : lclGetBeforeBeg( rBLFromR );
700 
701     if( bIsDbl )
702     {
703         rResult.maSecn.mnLClip = rBLFromT.Secn() ? lclGetBeg( rBLFromT ) : lclGetBehindEnd( rBLFromT );
704         rResult.maSecn.mnRClip = lclGetBeforeBeg( rTRFromB );
705         rResult.maSecn.mnTClip = rTRFromL.Secn() ? lclGetBeg( rTRFromL ) : lclGetBehindEnd( rTRFromL );
706         rResult.maSecn.mnBClip = lclGetBeforeBeg( rBLFromR );
707     }
708 }
709 
710 /** Calculates clipping offsets for both diagonal frame borders.
711 
712     This function can be used for single and double frame borders.
713     See DrawDiagFrameBorders() function for a description of all parameters.
714 
715     @param rResult
716         (out-param) The contained values (sub units) specify offsets for all
717         borders of the reference rectangle containing the diagonal frame
718         borders.
719  */
720 void lclLinkDiagFrameBorders(
721         DiagBordersResult& rResult, const Style& rTLBR, const Style& rBLTR,
722         const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
723         const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
724 {
725     lclLinkTLBRFrameBorder( rResult.maTLBR, rTLBR, rTLFromB, rTLFromR, rBRFromT, rBRFromL );
726     lclLinkBLTRFrameBorder( rResult.maBLTR, rBLTR, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
727 }
728 
729 // ============================================================================
730 // Drawing functions
731 // ============================================================================
732 
733 // ----------------------------------------------------------------------------
734 // Simple helper functions
735 
736 /** Converts sub units to OutputDevice map units. */
737 inline long lclToMapUnit( long nSubUnits )
738 {
739     return ((nSubUnits < 0) ? (nSubUnits - 127) : (nSubUnits + 128)) / 256;
740 }
741 
742 /** Converts a point in sub units to an OutputDevice point. */
743 inline Point lclToMapUnit( long nSubXPos, long nSubYPos )
744 {
745     return Point( lclToMapUnit( nSubXPos ), lclToMapUnit( nSubYPos ) );
746 }
747 
748 /** Returns a polygon constructed from a vector of points. */
749 inline Polygon lclCreatePolygon( const PointVec& rPoints )
750 {
751     return Polygon( static_cast< sal_uInt16 >( rPoints.size() ), &rPoints[ 0 ] );
752 }
753 
754 /** Returns a polygon constructed from the four passed points. */
755 Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 )
756 {
757     PointVec aPoints;
758     aPoints.reserve( 4 );
759     aPoints.push_back( rP1 );
760     aPoints.push_back( rP2 );
761     aPoints.push_back( rP3 );
762     aPoints.push_back( rP4 );
763     return lclCreatePolygon( aPoints );
764 }
765 
766 /** Returns a polygon constructed from the five passed points. */
767 Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4, const Point& rP5 )
768 {
769     PointVec aPoints;
770     aPoints.reserve( 5 );
771     aPoints.push_back( rP1 );
772     aPoints.push_back( rP2 );
773     aPoints.push_back( rP3 );
774     aPoints.push_back( rP4 );
775     aPoints.push_back( rP5 );
776     return lclCreatePolygon( aPoints );
777 }
778 
779 /** Returns a polygon constructed from the two passed line positions. */
780 inline Polygon lclCreatePolygon( const LinePoints& rPoints1, const LinePoints& rPoints2 )
781 {
782     return lclCreatePolygon( rPoints1.maBeg, rPoints1.maEnd, rPoints2.maEnd, rPoints2.maBeg );
783 }
784 
785 /** Sets the color of the passed frame style to the output device.
786 
787     Sets the line color and fill color in the output device.
788 
789     @param rDev
790         The output device the color has to be set to. The old colors are pushed
791         onto the device's stack and can be restored with a call to
792         OutputDevice::Pop(). Please take care about the correct calling order
793         of Pop() if this function is used with other functions pushing
794         something onto the stack.
795     @param rStyle
796         The border style that contains the line color to be set to the device.
797  */
798 void lclSetColorToOutDev( OutputDevice& rDev, const Style& rStyle, const Color* pForceColor )
799 {
800     rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
801     rDev.SetLineColor( pForceColor ? *pForceColor : rStyle.GetColor() );
802     rDev.SetFillColor( pForceColor ? *pForceColor : rStyle.GetColor() );
803 }
804 
805 // ----------------------------------------------------------------------------
806 // Generic drawing functions.
807 
808 /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */
809 void lclDrawThinLine( OutputDevice& rDev, const Point& rBeg, const Point& rEnd, bool bDotted )
810 {
811 #if SVX_FRAME_USE_LINEINFO
812     if( bDotted && (rBeg != rEnd) )
813     {
814 // using LineInfo for dotted lines looks ugly and does not work well for diagonal lines
815         LineInfo aLineInfo( LINE_DASH, 1 );
816         aLineInfo.SetDotCount( 1 );
817         aLineInfo.SetDotLen( 1 );
818         aLineInfo.SetDistance( 3 );
819         rDev.DrawLine( rBeg, rEnd, aLineInfo );
820     }
821 #else
822     Point aBeg( rDev.LogicToPixel( rBeg ) );
823     Point aEnd( rDev.LogicToPixel( rEnd ) );
824     if( bDotted && (aBeg != aEnd) )
825     {
826         bool bHor = Abs( aEnd.X() - aBeg.X() ) > Abs( aEnd.Y() - aBeg.Y() );
827         const Point& rBegPos( bHor ? ((aBeg.X() < aEnd.X()) ? aBeg : aEnd) : ((aBeg.Y() < aEnd.Y()) ? aBeg : aEnd ) );
828         const Point& rEndPos( (rBegPos == aBeg) ? aEnd : aBeg );
829 
830         long nAlongBeg = bHor ? rBegPos.X() : rBegPos.Y();
831         long nAcrssBeg = bHor ? rBegPos.Y() : rBegPos.X();
832         long nAlongSize = (bHor ? rEndPos.X() : rEndPos.Y()) - nAlongBeg;
833         long nAcrssSize = (bHor ? rEndPos.Y() : rEndPos.X()) - nAcrssBeg;
834         double fGradient = static_cast< double >( nAcrssSize ) / nAlongSize;
835 
836         PointVec aPoints;
837         aPoints.reserve( (nAlongSize + 1) / 2 );
838         for( long nAlongIdx = 0; nAlongIdx <= nAlongSize; nAlongIdx += 2 )
839         {
840             long nAl = nAlongBeg + nAlongIdx;
841             long nAc = nAcrssBeg + lclD2L( fGradient * nAlongIdx );
842             aPoints.push_back( Point( bHor ? nAl : nAc, bHor ? nAc : nAl ) );
843         }
844 
845         rDev.Push( PUSH_MAPMODE );
846         rDev.SetMapMode( MAP_PIXEL );
847         rDev.DrawPixel( lclCreatePolygon( aPoints ) );
848         rDev.Pop(); // map mode
849     }
850 #endif
851     else
852         rDev.DrawLine( rBeg, rEnd );
853 }
854 
855 /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */
856 inline void lclDrawThinLine( OutputDevice& rDev, const LinePoints& rPoints, bool bDotted )
857 {
858     lclDrawThinLine( rDev, rPoints.maBeg, rPoints.maEnd, bDotted );
859 }
860 
861 /** Draws a polygon with four points into the passed output device. */
862 inline void lclDrawPolygon( OutputDevice& rDev, const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 )
863 {
864     rDev.DrawPolygon( lclCreatePolygon( rP1, rP2, rP3, rP4 ) );
865 }
866 
867 /** Draws a polygon specified by two borders into the passed output device. */
868 inline void lclDrawPolygon( OutputDevice& rDev, const LinePoints& rPoints1, const LinePoints& rPoints2 )
869 {
870     rDev.DrawPolygon( lclCreatePolygon( rPoints1, rPoints2 ) );
871 }
872 
873 // ============================================================================
874 // Drawing of horizontal frame borders.
875 
876 /** Draws a horizontal thin or thick line into the passed output device.
877 
878     The X coordinates of the edges of the line are adjusted according to the
879     passed LineEndResult structs. A one pixel wide line can be drawn dotted.
880  */
881 void lclDrawHorLine(
882         OutputDevice& rDev,
883         const Point& rLPos, const LineEndResult& rLRes,
884         const Point& rRPos, const LineEndResult& rRRes,
885         long nTOffs, long nBOffs, bool bDotted )
886 {
887     LinePoints aTPoints( rLPos + lclToMapUnit( rLRes.mnOffs1, nTOffs ), rRPos + lclToMapUnit( rRRes.mnOffs1, nTOffs ) );
888     if( nTOffs == nBOffs )
889         lclDrawThinLine( rDev, aTPoints, bDotted );
890     else
891     {
892         LinePoints aBPoints( rLPos + lclToMapUnit( rLRes.mnOffs2, nBOffs ), rRPos + lclToMapUnit( rRRes.mnOffs2, nBOffs ) );
893         lclDrawPolygon( rDev, aTPoints, aBPoints );
894     }
895 }
896 
897 /** Draws a horizontal frame border into the passed output device.
898 
899     @param rLPos
900         The top-left or bottom-left reference point of the diagonal frame border.
901     @param rRPos
902         The top-right or bottom-right reference point of the diagonal frame border.
903     @param rBorder
904         The frame style used to draw the border.
905     @param rResult
906         The X coordinates of the edges of all lines of the frame border are
907         adjusted according to the offsets contained here.
908  */
909 void lclDrawHorFrameBorder(
910         OutputDevice& rDev, const Point& rLPos, const Point& rRPos,
911         const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
912 {
913     DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" );
914     DBG_ASSERT( rLPos.X() <= rRPos.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" );
915     DBG_ASSERT( rLPos.Y() == rRPos.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" );
916     if( rLPos.X() <= rRPos.X() )
917     {
918         lclSetColorToOutDev( rDev, rBorder, pForceColor );
919         lclDrawHorLine( rDev, rLPos, rResult.maBeg.maPrim, rRPos, rResult.maEnd.maPrim,
920             lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
921         if( rBorder.Secn() )
922             lclDrawHorLine( rDev, rLPos, rResult.maBeg.maSecn, rRPos, rResult.maEnd.maSecn,
923                 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
924         rDev.Pop(); // colors
925     }
926 }
927 
928 // ----------------------------------------------------------------------------
929 // Drawing of vertical frame borders.
930 
931 /** Draws a vertical thin or thick line into the passed output device.
932 
933     The Y coordinates of the edges of the line are adjusted according to the
934     passed LineEndResult structs. A one pixel wide line can be drawn dotted.
935  */
936 void lclDrawVerLine(
937         OutputDevice& rDev,
938         const Point& rTPos, const LineEndResult& rTRes,
939         const Point& rBPos, const LineEndResult& rBRes,
940         long nLOffs, long nROffs, bool bDotted )
941 {
942     LinePoints aLPoints( rTPos + lclToMapUnit( nLOffs, rTRes.mnOffs1 ), rBPos + lclToMapUnit( nLOffs, rBRes.mnOffs1 ) );
943     if( nLOffs == nROffs )
944         lclDrawThinLine( rDev, aLPoints, bDotted );
945     else
946     {
947         LinePoints aRPoints( rTPos + lclToMapUnit( nROffs, rTRes.mnOffs2 ), rBPos + lclToMapUnit( nROffs, rBRes.mnOffs2 ) );
948         lclDrawPolygon( rDev, aLPoints, aRPoints );
949     }
950 }
951 
952 /** Draws a vertical frame border into the passed output device.
953 
954     @param rTPos
955         The top-left or top-right reference point of the diagonal frame border.
956     @param rBPos
957         The bottom-left or bottom-right reference point of the diagonal frame border.
958     @param rBorder
959         The frame style used to draw the border.
960     @param rResult
961         The Y coordinates of the edges of all lines of the frame border are
962         adjusted according to the offsets contained here.
963  */
964 void lclDrawVerFrameBorder(
965         OutputDevice& rDev, const Point& rTPos, const Point& rBPos,
966         const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
967 {
968     DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" );
969     DBG_ASSERT( rTPos.Y() <= rBPos.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" );
970     DBG_ASSERT( rTPos.X() == rBPos.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" );
971     if( rTPos.Y() <= rBPos.Y() )
972     {
973         lclSetColorToOutDev( rDev, rBorder, pForceColor );
974         lclDrawVerLine( rDev, rTPos, rResult.maBeg.maPrim, rBPos, rResult.maEnd.maPrim,
975             lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
976         if( rBorder.Secn() )
977             lclDrawVerLine( rDev, rTPos, rResult.maBeg.maSecn, rBPos, rResult.maEnd.maSecn,
978                 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
979         rDev.Pop(); // colors
980     }
981 }
982 
983 // ============================================================================
984 // Drawing of diagonal frame borders, incudes clipping functions.
985 
986 /** Returns the drawing coordinates for a diagonal thin line.
987 
988     This function can be used for top-left to bottom-right and for bottom-left
989     to top-right lines.
990 
991     @param rRect
992         The reference rectangle of the diagonal frame border.
993     @param bTLBR
994         true = top-left to bottom-right; false = bottom-left to top-right.
995     @param nDiagOffs
996         Width offset (sub units) across the diagonal frame border.
997     @return
998         A struct containg start and end position of the diagonal line.
999  */
1000 LinePoints lclGetDiagLineEnds( const Rectangle& rRect, bool bTLBR, long nDiagOffs )
1001 {
1002     LinePoints aPoints( rRect, bTLBR );
1003     bool bVert = rRect.GetWidth() < rRect.GetHeight();
1004     double fAngle = bVert ? GetVerDiagAngle( rRect ) : GetHorDiagAngle( rRect );
1005     // vertical top-left to bottom-right borders are handled mirrored
1006     if( bVert && bTLBR )
1007         nDiagOffs = -nDiagOffs;
1008     long nTOffs = bTLBR ? GetTLDiagOffset( 0, nDiagOffs, fAngle ) : GetTRDiagOffset( 0, nDiagOffs, fAngle );
1009     long nBOffs = bTLBR ? GetBRDiagOffset( 0, nDiagOffs, fAngle ) : GetBLDiagOffset( 0, nDiagOffs, fAngle );
1010     // vertical bottom-left to top-right borders are handled with exchanged end points
1011     if( bVert && !bTLBR )
1012         std::swap( nTOffs, nBOffs );
1013     (bVert ? aPoints.maBeg.Y() : aPoints.maBeg.X()) += lclToMapUnit( nTOffs );
1014     (bVert ? aPoints.maEnd.Y() : aPoints.maEnd.X()) += lclToMapUnit( nBOffs );
1015     return aPoints;
1016 }
1017 
1018 // ----------------------------------------------------------------------------
1019 // Clipping functions for diagonal frame borders.
1020 
1021 /** Limits the clipping region to the inner area of a rectange.
1022 
1023     Takes the values from the passed DiagLineResult struct into account. They
1024     may specify to not clip one or more borders of a rectangle.
1025 
1026     @param rDev
1027         The output device with the clipping region to be modified. The old
1028         clipping region is pushed onto the device's stack and can be restored
1029         with a call to OutputDevice::Pop(). Please take care about the correct
1030         calling order of Pop() if this function is used with other functions
1031         pushing something onto the stack.
1032     @param rRect
1033         The reference rectangle of the diagonal frame borders.
1034     @param rResult
1035         The result struct containing modifies for each border of the reference
1036         rectangle.
1037  */
1038 void lclPushDiagClipRect( OutputDevice& rDev, const Rectangle& rRect, const DiagLineResult& rResult )
1039 {
1040     // PixelToLogic() regards internal offset of the output device
1041     Rectangle aClipRect( rRect );
1042     aClipRect.Left()   += lclToMapUnit( rResult.mnLClip );
1043     aClipRect.Top()    += lclToMapUnit( rResult.mnTClip );
1044     aClipRect.Right()  += lclToMapUnit( rResult.mnRClip );
1045     aClipRect.Bottom() += lclToMapUnit( rResult.mnBClip );
1046     // output device would adjust the rectangle -> invalidate it before
1047     if( (aClipRect.GetWidth() < 1) ||(aClipRect.GetHeight() < 1) )
1048         aClipRect.SetEmpty();
1049 
1050     rDev.Push( PUSH_CLIPREGION );
1051     rDev.IntersectClipRegion( aClipRect );
1052 }
1053 
1054 /** Excludes inner area of a crossing double frame border from clipping region.
1055 
1056     This function is used to modify the clipping region so that it excludes the
1057     inner free area of a double diagonal frame border. This makes it possible
1058     to draw a diagonal frame border in one step without taking care of the
1059     crossing double frame border.
1060 
1061     @param rDev
1062         The output device with the clipping region to be modified. The old
1063         clipping region is pushed onto the device's stack and can be restored
1064         with a call to OutputDevice::Pop(). Please take care about the correct
1065         calling order of Pop() if this function is used with other functions
1066         pushing something onto the stack.
1067     @param rRect
1068         The reference rectangle of the diagonal frame borders.
1069     @param bTLBR
1070         The orientation of the processed frame border (not the orientation of
1071         the crossing frame border).
1072     @param bCrossStyle
1073         The style of the crossing frame border. Must be a double frame style.
1074  */
1075 void lclPushCrossingClipRegion( OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, const Style& rCrossStyle )
1076 {
1077     DBG_ASSERT( rCrossStyle.Secn(), "lclGetCrossingClipRegion - use only for double styles" );
1078     LinePoints aLPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetPrimEnd( rCrossStyle ) ) );
1079     LinePoints aRPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetSecnBeg( rCrossStyle ) ) );
1080 
1081     Region aClipReg;
1082     if( bTLBR )
1083     {
1084         aClipReg = lclCreatePolygon(
1085             aLPoints.maBeg, aLPoints.maEnd, rRect.BottomRight(), rRect.BottomLeft(), rRect.TopLeft() );
1086         aClipReg.Union( lclCreatePolygon(
1087             aRPoints.maBeg, aRPoints.maEnd, rRect.BottomRight(), rRect.TopRight(), rRect.TopLeft() ) );
1088     }
1089     else
1090     {
1091         aClipReg = lclCreatePolygon(
1092             aLPoints.maBeg, aLPoints.maEnd, rRect.BottomLeft(), rRect.TopLeft(), rRect.TopRight() );
1093         aClipReg.Union( lclCreatePolygon(
1094             aRPoints.maBeg, aRPoints.maEnd, rRect.BottomLeft(), rRect.BottomRight(), rRect.TopRight() ) );
1095     }
1096 
1097     rDev.Push( PUSH_CLIPREGION );
1098     rDev.IntersectClipRegion( aClipReg );
1099 }
1100 
1101 // ----------------------------------------------------------------------------
1102 // Drawing functions for diagonal frame borders.
1103 
1104 /** Draws a diagonal thin or thick line into the passed output device.
1105 
1106     The clipping region of the output device is modified according to the
1107     passed DiagLineResult struct. A one pixel wide line can be drawn dotted.
1108  */
1109 void lclDrawDiagLine(
1110         OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1111         const DiagLineResult& rResult, long nDiagOffs1, long nDiagOffs2, bool bDotted )
1112 {
1113     lclPushDiagClipRect( rDev, rRect, rResult );
1114     LinePoints aLPoints( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs1 ) );
1115     if( nDiagOffs1 == nDiagOffs2 )
1116         lclDrawThinLine( rDev, aLPoints, bDotted );
1117     else
1118         lclDrawPolygon( rDev, aLPoints, lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs2 ) );
1119     rDev.Pop(); // clipping region
1120 }
1121 
1122 /** Draws a diagonal frame border into the passed output device.
1123 
1124     The lines of the frame border are drawn interrupted, if the style of the
1125     crossing frame border is double.
1126 
1127     @param rRect
1128         The reference rectangle of the diagonal frame border.
1129     @param bTLBR
1130         The orientation of the diagonal frame border.
1131     @param rBorder
1132         The frame style used to draw the border.
1133     @param rResult
1134         Offsets (sub units) to modify the clipping region of the output device.
1135     @param rCrossStyle
1136         Style of the crossing diagonal frame border.
1137  */
1138 void lclDrawDiagFrameBorder(
1139         OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1140         const Style& rBorder, const DiagBorderResult& rResult, const Style& rCrossStyle,
1141         const Color* pForceColor, bool bDiagDblClip )
1142 {
1143     DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" );
1144 
1145     bool bClip = bDiagDblClip && rCrossStyle.Secn();
1146     if( bClip )
1147         lclPushCrossingClipRegion( rDev, rRect, bTLBR, rCrossStyle );
1148 
1149     lclSetColorToOutDev( rDev, rBorder, pForceColor );
1150     lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maPrim, lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
1151     if( rBorder.Secn() )
1152         lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
1153     rDev.Pop(); // colors
1154 
1155     if( bClip )
1156         rDev.Pop(); // clipping region
1157 }
1158 
1159 /** Draws both diagonal frame borders into the passed output device.
1160 
1161     The lines of each frame border is drawn interrupted, if the style of the
1162     other crossing frame border is double.
1163 
1164     @param rRect
1165         The reference rectangle of the diagonal frame borders.
1166     @param rTLBR
1167         The frame style of the top-left to bottom-right frame border.
1168     @param rBLTR
1169         The frame style of the bottom-left to top-right frame border.
1170     @param rResult
1171         Offsets (sub units) to modify the clipping region of the output device.
1172  */
1173 void lclDrawDiagFrameBorders(
1174         OutputDevice& rDev, const Rectangle& rRect,
1175         const Style& rTLBR, const Style& rBLTR, const DiagBordersResult& rResult,
1176         const Color* pForceColor, bool bDiagDblClip )
1177 {
1178     DBG_ASSERT( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" );
1179     if( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1) )
1180     {
1181         bool bDrawTLBR = rTLBR.Prim() != 0;
1182         bool bDrawBLTR = rBLTR.Prim() != 0;
1183         bool bFirstDrawBLTR = rTLBR.Secn() != 0;
1184 
1185         if( bDrawBLTR && bFirstDrawBLTR )
1186             lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1187         if( bDrawTLBR )
1188             lclDrawDiagFrameBorder( rDev, rRect, true, rTLBR, rResult.maTLBR, rBLTR, pForceColor, bDiagDblClip );
1189         if( bDrawBLTR && !bFirstDrawBLTR )
1190             lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1191     }
1192 }
1193 
1194 // ============================================================================
1195 
1196 } // namespace
1197 
1198 // ============================================================================
1199 // Classes
1200 // ============================================================================
1201 
1202 #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth )
1203 
1204 void Style::Clear()
1205 {
1206     Set( Color(), 0, 0, 0 );
1207 }
1208 
1209 void Style::Set( sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS )
1210 {
1211     /*  nP  nD  nS  ->  mnPrim  mnDist  mnSecn
1212         --------------------------------------
1213         any any 0       nP      0       0
1214         0   any >0      nS      0       0
1215         >0  0   >0      nP      0       0
1216         >0  >0  >0      nP      nD      nS
1217      */
1218     mnPrim = nP ? nP : nS;
1219     mnDist = (nP && nS) ? nD : 0;
1220     mnSecn = (nP && nD) ? nS : 0;
1221 }
1222 
1223 void Style::Set( const Color& rColor, sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS )
1224 {
1225     maColor = rColor;
1226     Set( nP, nD, nS );
1227 }
1228 
1229 void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots )
1230 {
1231     maColor = rBorder.GetColor();
1232 
1233     sal_uInt16 nPrim = rBorder.GetOutWidth();
1234     sal_uInt16 nDist = rBorder.GetDistance();
1235     sal_uInt16 nSecn = rBorder.GetInWidth();
1236 
1237     if( !nSecn )    // no or single frame border
1238     {
1239         Set( SCALEVALUE( nPrim ), 0, 0 );
1240         mbDotted = bUseDots && (0 < nPrim) && (nPrim < 10);
1241     }
1242     else
1243     {
1244         Set( SCALEVALUE( nPrim ), SCALEVALUE( nDist ), SCALEVALUE( nSecn ) );
1245         mbDotted = false;
1246         // Enlarge the style if distance is too small due to rounding losses.
1247         sal_uInt16 nPixWidth = SCALEVALUE( nPrim + nDist + nSecn );
1248         if( nPixWidth > GetWidth() )
1249             mnDist = nPixWidth - mnPrim - mnSecn;
1250         // Shrink the style if it is too thick for the control.
1251         while( GetWidth() > nMaxWidth )
1252         {
1253             // First decrease space between lines.
1254             if( mnDist )
1255                 --mnDist;
1256             // Still too thick? Decrease the line widths.
1257             if( GetWidth() > nMaxWidth )
1258             {
1259                 if( mnPrim && (mnPrim == mnSecn) )
1260                 {
1261                     // Both lines equal - decrease both to keep symmetry.
1262                     --mnPrim;
1263                     --mnSecn;
1264                 }
1265                 else
1266                 {
1267                     // Decrease each line for itself
1268                     if( mnPrim )
1269                         --mnPrim;
1270                     if( (GetWidth() > nMaxWidth) && mnSecn )
1271                         --mnSecn;
1272                 }
1273             }
1274         }
1275     }
1276 }
1277 
1278 void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots )
1279 {
1280     if( pBorder )
1281         Set( *pBorder, fScale, nMaxWidth, bUseDots );
1282     else
1283     {
1284         Clear();
1285         mbDotted = false;
1286     }
1287 }
1288 
1289 Style& Style::ScaleSelf( double fScale, sal_uInt16 nMaxWidth )
1290 {
1291     Set( SCALEVALUE( mnPrim ), SCALEVALUE( mnDist ), SCALEVALUE( mnSecn ) );
1292     return *this;
1293 }
1294 
1295 Style Style::Scale( double fScale, sal_uInt16 nMaxWidth ) const
1296 {
1297     return Style( *this ).ScaleSelf( fScale, nMaxWidth );
1298 }
1299 
1300 Style& Style::MirrorSelf()
1301 {
1302     if( mnSecn )
1303         std::swap( mnPrim, mnSecn );
1304     if( meRefMode != REFMODE_CENTERED )
1305         meRefMode = (meRefMode == REFMODE_BEGIN) ? REFMODE_END : REFMODE_BEGIN;
1306     return *this;
1307 }
1308 
1309 Style Style::Mirror() const
1310 {
1311     return Style( *this ).MirrorSelf();
1312 }
1313 
1314 bool operator==( const Style& rL, const Style& rR )
1315 {
1316     return (rL.Prim() == rR.Prim()) && (rL.Dist() == rR.Dist()) && (rL.Secn() == rR.Secn()) &&
1317         (rL.GetColor() == rR.GetColor()) && (rL.GetRefMode() == rR.GetRefMode()) && (rL.Dotted() == rR.Dotted());
1318 }
1319 
1320 bool operator<( const Style& rL, const Style& rR )
1321 {
1322     // different total widths -> rL<rR, if rL is thinner
1323     sal_uInt16 nLW = rL.GetWidth();
1324     sal_uInt16 nRW = rR.GetWidth();
1325     if( nLW != nRW ) return nLW < nRW;
1326 
1327     // one line double, the other single -> rL<rR, if rL is single
1328     if( (rL.Secn() == 0) != (rR.Secn() == 0) ) return rL.Secn() == 0;
1329 
1330     // both lines double with different distances -> rL<rR, if distance of rL greater
1331     if( (rL.Secn() && rR.Secn()) && (rL.Dist() != rR.Dist()) ) return rL.Dist() > rR.Dist();
1332 
1333     // both lines single and 1 unit thick, only one is dotted -> rL<rR, if rL is dotted
1334     if( (nLW == 1) && (rL.Dotted() != rR.Dotted()) ) return rL.Dotted();
1335 
1336     // seem to be equal
1337     return false;
1338 }
1339 
1340 #undef SCALEVALUE
1341 
1342 // ============================================================================
1343 // Various helper functions
1344 // ============================================================================
1345 
1346 double GetHorDiagAngle( long nWidth, long nHeight )
1347 {
1348     return atan2( static_cast< double >( Abs( nHeight ) ), static_cast< double >( Abs( nWidth ) ) );
1349 }
1350 
1351 // ============================================================================
1352 
1353 long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1354 {
1355     return lclD2L( nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1356 }
1357 
1358 long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1359 {
1360     return lclD2L( -nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1361 }
1362 
1363 long GetBRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1364 {
1365     return -lclD2L( -nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1366 }
1367 
1368 long GetTRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1369 {
1370     return -lclD2L( nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1371 }
1372 
1373 // ============================================================================
1374 
1375 bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
1376         const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
1377         const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
1378 {
1379     return      // returns 1 AND (2a OR 2b)
1380         // 1) only, if both frame borders are equal
1381         (rLBorder == rRBorder)
1382         &&
1383         (
1384             (
1385                 // 2a) if the borders are not double, at least one of the vertical must not be double
1386                 !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn())
1387             )
1388             ||
1389             (
1390                 // 2b) if the borders are double, all other borders must not be double
1391                 rLBorder.Secn() &&
1392                 !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() &&
1393                 !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn()
1394             )
1395         );
1396 }
1397 
1398 // ============================================================================
1399 // Drawing functions
1400 // ============================================================================
1401 
1402 void DrawHorFrameBorder( OutputDevice& rDev,
1403         const Point& rLPos, const Point& rRPos, const Style& rBorder,
1404         const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
1405         const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL,
1406         const Color* pForceColor )
1407 {
1408     if( rBorder.Prim() )
1409     {
1410         BorderResult aResult;
1411         lclLinkHorFrameBorder( aResult, rBorder,
1412             rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR,
1413             rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
1414         lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, aResult, pForceColor );
1415     }
1416 }
1417 
1418 void DrawHorFrameBorder( OutputDevice& rDev,
1419         const Point& rLPos, const Point& rRPos, const Style& rBorder,
1420         const Style& rLFromT, const Style& rLFromL, const Style& rLFromB,
1421         const Style& rRFromT, const Style& rRFromR, const Style& rRFromB,
1422         const Color* pForceColor )
1423 {
1424     /*  Recycle complex version of the DrawHorFrameBorder() function with empty diagonals. */
1425     const DiagStyle aNoStyle;
1426     DrawHorFrameBorder(
1427         rDev, rLPos, rRPos, rBorder,
1428         aNoStyle, rLFromT, rLFromL, rLFromB, aNoStyle,
1429         aNoStyle, rRFromT, rRFromR, rRFromB, aNoStyle,
1430         pForceColor );
1431 }
1432 
1433 void DrawHorFrameBorder( OutputDevice& rDev,
1434         const Point& rLPos, const Point& rRPos, const Style& rBorder, const Color* pForceColor )
1435 {
1436     if( rBorder.Prim() )
1437         lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, BorderResult(), pForceColor );
1438 }
1439 
1440 // ----------------------------------------------------------------------------
1441 
1442 void DrawVerFrameBorder( OutputDevice& rDev,
1443         const Point& rTPos, const Point& rBPos, const Style& rBorder,
1444         const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
1445         const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR,
1446         const Color* pForceColor )
1447 {
1448     if( rBorder.Prim() )
1449     {
1450         BorderResult aResult;
1451         lclLinkVerFrameBorder( aResult, rBorder,
1452             rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR,
1453             rBFromTL, rBFromL, rBFromB, rBFromR, rBFromTR );
1454         lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, aResult, pForceColor );
1455     }
1456 }
1457 
1458 void DrawVerFrameBorder( OutputDevice& rDev,
1459         const Point& rTPos, const Point& rBPos, const Style& rBorder,
1460         const Style& rTFromL, const Style& rTFromT, const Style& rTFromR,
1461         const Style& rBFromL, const Style& rBFromB, const Style& rBFromR,
1462         const Color* pForceColor )
1463 {
1464     /*  Recycle complex version of the DrawVerFrameBorder() function with empty diagonals. */
1465     const DiagStyle aNoStyle;
1466     DrawVerFrameBorder(
1467         rDev, rTPos, rBPos, rBorder,
1468         aNoStyle, rTFromL, rTFromT, rTFromR, aNoStyle,
1469         aNoStyle, rBFromL, rBFromB, rBFromR, aNoStyle,
1470         pForceColor );
1471 }
1472 
1473 void DrawVerFrameBorder( OutputDevice& rDev,
1474         const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor )
1475 {
1476     if( rBorder.Prim() )
1477         lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, BorderResult(), pForceColor );
1478 }
1479 
1480 // ----------------------------------------------------------------------------
1481 
1482 void DrawVerFrameBorderSlanted( OutputDevice& rDev,
1483         const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor )
1484 {
1485     DBG_ASSERT( rTPos.Y() < rBPos.Y(), "svx::frame::DrawVerFrameBorderSlanted - wrong order of line ends" );
1486     if( rBorder.Prim() && (rTPos.Y() < rBPos.Y()) )
1487     {
1488         if( rTPos.X() == rBPos.X() )
1489         {
1490             DrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, pForceColor );
1491         }
1492         else
1493         {
1494             const LineEndResult aRes;
1495 
1496             Style aScaled( rBorder );
1497             aScaled.ScaleSelf( 1.0 / cos( GetVerDiagAngle( rTPos, rBPos ) ) );
1498 
1499             lclSetColorToOutDev( rDev, aScaled, pForceColor );
1500             lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes,
1501                 lclGetBeg( aScaled ), lclGetPrimEnd( aScaled ), aScaled.Dotted() );
1502             if( aScaled.Secn() )
1503                 lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes,
1504                     lclGetSecnBeg( aScaled ), lclGetEnd( aScaled ), aScaled.Dotted() );
1505             rDev.Pop(); // colors
1506         }
1507     }
1508 }
1509 
1510 // ============================================================================
1511 
1512 void DrawDiagFrameBorders(
1513         OutputDevice& rDev, const Rectangle& rRect, const Style& rTLBR, const Style& rBLTR,
1514         const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
1515         const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL,
1516         const Color* pForceColor, bool bDiagDblClip )
1517 {
1518     if( rTLBR.Prim() || rBLTR.Prim() )
1519     {
1520         DiagBordersResult aResult;
1521         lclLinkDiagFrameBorders( aResult, rTLBR, rBLTR,
1522             rTLFromB, rTLFromR, rBRFromT, rBRFromL, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
1523         lclDrawDiagFrameBorders( rDev, rRect, rTLBR, rBLTR, aResult, pForceColor, bDiagDblClip );
1524     }
1525 }
1526 
1527 // ============================================================================
1528 
1529 } // namespace frame
1530 } // namespace svx
1531 
1532