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