fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / svx / source / dialog / framelink.cxx
blobe7e93b8a74c49cb170d308d6527edd629933f8b1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <cstdlib>
24 #include <svx/framelink.hxx>
26 #include <math.h>
27 #include <vcl/outdev.hxx>
28 #include <tools/gen.hxx>
29 #include <editeng/borderline.hxx>
30 #include <svtools/borderhelper.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
35 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx>
39 using namespace ::com::sun::star;
40 using namespace editeng;
42 namespace svx {
43 namespace frame {
47 namespace {
49 typedef std::vector< Point > PointVec;
52 // Link result structs for horizontal and vertical lines and borders.
54 /** Result struct used by the horizontal/vertical frame link functions.
56 This struct is used to return coordinate offsets for one end of a single
57 line in a frame border, i.e. the left end of the primary line of a
58 horizontal frame border.
60 1) Usage for horizontal lines
62 If this struct is returned by the lclLinkHorFrameBorder() function, each
63 member refers to the X coordinate of one edge of a single line end in a
64 horizontal frame border. They specify an offset to modify this coordinate
65 when the line is painted. The values in this struct may change a
66 rectangular line shape into a line with slanted left or right border, which
67 is used to connect the line with diagonal lines.
69 Usage for a left line end: Usage for a right line end:
70 mnOffs1 mnOffs1
71 <-------> <------->
72 +-------------------------------+
73 | the original horizontal line |
74 +-------------------------------+
75 <-------> <------->
76 mnOffs2 mnOffs2
78 2) Usage for vertical lines
80 If this struct is returned by the lclLinkVerFrameBorder() function, each
81 member refers to the Y coordinate of one edge of a single line end in a
82 vertical frame border. They specify an offset to modify this coordinate
83 when the line is painted. The values in this struct may change a
84 rectangular line shape into a line with slanted top or bottom border, which
85 is used to connect the line with diagonal lines.
87 Usage for a top line end: mnOffs1 ^ ^ mnOffs2
88 | +-------+ |
89 v | | v
90 | |
91 | |
92 the original vertical line ---> | |
93 | |
94 | |
95 ^ | | ^
96 | +-------+ |
97 Usage for a bottom line end: mnOffs1 v v mnOffs2
99 struct LineEndResult
101 long mnOffs1; /// Offset for top or left edge, dependent of context.
102 long mnOffs2; /// Offset for bottom or right edge, dependent of context
104 inline explicit LineEndResult() : mnOffs1( 0 ), mnOffs2( 0 ) {}
106 inline void Swap() { std::swap( mnOffs1, mnOffs2 ); }
107 inline void Negate() { mnOffs1 = -mnOffs1; mnOffs2 = -mnOffs2; }
110 /** Result struct used by the horizontal/vertical frame link functions.
112 This struct contains the linking results for one end of a frame border,
113 including both the primary and secondary line ends.
115 struct BorderEndResult
117 LineEndResult maPrim; /// Result for primary line.
118 LineEndResult maSecn; /// Result for secondary line.
119 LineEndResult maGap; /// Result for gap line.
121 inline void Negate() { maPrim.Negate(); maSecn.Negate(); maGap.Negate(); }
124 /** Result struct used by the horizontal/vertical frame link functions.
126 This struct contains the linking results for both frame border ends, and
127 therefore for the complete frame border.
129 struct BorderResult
131 BorderEndResult maBeg; /// Result for begin of border line (left or top end).
132 BorderEndResult maEnd; /// Result for end of border line (right or bottom end).
136 // Link result structs for diagonal lines and borders.
138 /** Result struct used by the diagonal frame link functions.
140 This struct contains the linking results for one line of a diagonal frame
141 border.
143 struct DiagLineResult
145 long mnLClip; /// Offset for left border of clipping rectangle.
146 long mnRClip; /// Offset for right border of clipping rectangle.
147 long mnTClip; /// Offset for top border of clipping rectangle.
148 long mnBClip; /// Offset for bottom border of clipping rectangle.
150 inline explicit DiagLineResult() : mnLClip( 0 ), mnRClip( 0 ), mnTClip( 0 ), mnBClip( 0 ) {}
153 /** Result struct used by the diagonal frame link functions.
155 This struct contains the linking results for one diagonal frame border.
157 struct DiagBorderResult
159 DiagLineResult maPrim; /// Result for primary line.
160 DiagLineResult maSecn; /// Result for secondary line.
163 /** Result struct used by the diagonal frame link functions.
165 This struct contains the linking results for both diagonal frame borders.
167 struct DiagBordersResult
169 DiagBorderResult maTLBR; /// Result for top-left to bottom-right frame border.
170 DiagBorderResult maBLTR; /// Result for bottom-left to top-right frame border.
175 /** A helper struct containing two points of a line.
177 struct LinePoints
179 Point maBeg; /// Start position of the line.
180 Point maEnd; /// End position of the line.
182 explicit LinePoints( const Point& rBeg, const Point& rEnd ) :
183 maBeg( rBeg ), maEnd( rEnd ) {}
184 explicit LinePoints( const Rectangle& rRect, bool bTLBR ) :
185 maBeg( bTLBR ? rRect.TopLeft() : rRect.TopRight() ),
186 maEnd( bTLBR ? rRect.BottomRight() : rRect.BottomLeft() ) {}
191 /** Rounds and casts a double value to a long value. */
192 inline long lclD2L( double fValue )
194 return static_cast< long >( (fValue < 0.0) ? (fValue - 0.5) : (fValue + 0.5) );
197 /** Converts a width in twips to a width in another map unit (specified by fScale). */
198 double lclScaleValue( double nValue, double fScale, sal_uInt16 nMaxWidth )
200 return std::min<double>(nValue * fScale, nMaxWidth);
204 // Line width offset calculation.
206 /** Returns the start offset of the single/primary line across the frame border.
208 All following lclGet*Beg() and lclGet*End() functions return sub units to
209 increase the computational accuracy, where 256 sub units are equal to
210 1 map unit of the used OutputDevice.
212 The following pictures show the upper end of a vertical frame border and
213 illustrates the return values of all following lclGet*Beg() and lclGet*End()
214 functions. The first picture shows a single frame border, the second picture
215 shows a double frame border.
217 The functions regard the reference point handling mode of the passed border
218 style.
219 REFMODE_CENTERED:
220 All returned offsets are relative to the middle position of the frame
221 border (offsets left of the middle are returned negative, offsets right
222 of the middle are returned positive).
223 REFMODE_BEGIN:
224 All returned offsets are relative to the begin of the frame border
225 (lclGetBeg() always returns 0).
226 REFMODE_END:
227 All returned offsets are relative to the end of the frame border
228 (lclGetEnd() always returns 0).
230 |<- lclGetEnd()
231 |<- lclGetBeforeBeg() |<- lclGetPrimEnd()
233 ||<- lclGetBeg() ||<- lclGetBehindEnd()
234 || ||
235 |#################################|
236 direction of | #################################
237 the frame | #################################
238 border is | #################################
239 vertical | #################################
240 v #################################
242 |<- middle of the frame border
244 lclGetDistEnd() ->||<- lclGetSecnBeg()
246 lclGetBeg() ->| lclGetDistBeg() ->| || |<- lclGetEnd()
247 | | || |
248 lclGetBeforeBeg()->|| lclGetPrimEnd() ->|| || ||<- lclGetBehindEnd()
249 || || || ||
250 |######################| |#############|
251 direction of | ###################### #############
252 the frame | ###################### #############
253 border is | ###################### #############
254 vertical | ###################### | #############
255 v ###################### | #############
256 primary line | secondary line
258 |<- middle of the frame border
260 @return
261 The start offset of the single/primary line relative to the reference
262 position of the frame border (sub units; 0 for invisible or one pixel
263 wide single frame styles).
265 long lclGetBeg( const Style& rBorder )
267 long nPos = 0;
268 switch( rBorder.GetRefMode() )
270 case REFMODE_CENTERED: if( rBorder.Prim() ) nPos = -128 * (rBorder.GetWidth() - 1); break;
271 case REFMODE_END: if( rBorder.Prim() ) nPos = -256 * (rBorder.GetWidth() - 1); break;
272 case REFMODE_BEGIN: break;
274 return nPos;
277 /** Returns the end offset of the single/secondary line across the frame border.
278 @descr See description of lclGetBeg() for an illustration.
279 @return The end offset of the single/secondary line relative to the
280 reference position of the frame border (sub units; 0 for invisible or one
281 pixel wide single frame styles). */
282 long lclGetEnd( const Style& rBorder )
284 long nPos = 0;
285 switch( rBorder.GetRefMode() )
287 case REFMODE_CENTERED: if( rBorder.Prim() ) nPos = 128 * (rBorder.GetWidth() - 1); break;
288 case REFMODE_BEGIN: if( rBorder.Prim() ) nPos = 256 * (rBorder.GetWidth() - 1); break;
289 case REFMODE_END: break;
291 return nPos;
294 /** Returns the end offset of the primary line across the frame border.
295 @descr See description of lclGetBeg() for an illustration.
296 @return The end offset of the primary line relative to the reference
297 position of the frame border (sub units; the end of the primary line in a
298 double frame style, otherwise the same as lclGetEnd()). */
299 inline long lclGetPrimEnd( const Style& rBorder )
300 { return rBorder.Prim() ? (lclGetBeg( rBorder ) + 256 * (rBorder.Prim() - 1)) : 0; }
302 /** Returns the start offset of the secondary line across the frame border.
303 @descr See description of lclGetBeg() for an illustration.
304 @return The start offset of the secondary line relative to the reference
305 position of the frame border (sub units; 0 for single/invisible border
306 styles). */
307 inline long lclGetSecnBeg( const Style& rBorder )
308 { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * (rBorder.Secn() - 1)) : 0; }
310 /** Returns the start offset of the distance space across the frame border.
311 @descr See description of lclGetBeg() for an illustration.
312 @return The start offset of the distance space relative to the reference
313 position of the frame border (sub units; 0 for single/invisible border
314 styles). */
315 inline long lclGetDistBeg( const Style& rBorder )
316 { return rBorder.Secn() ? (lclGetBeg( rBorder ) + 256 * rBorder.Prim()) : 0; }
318 /** Returns the end offset of the distance space across the frame border.
319 @descr See description of lclGetBeg() for an illustration.
320 @return The end offset of the distance space relative to the reference
321 position of the frame border (sub units; 0 for single/invisible border
322 styles). */
323 inline long lclGetDistEnd( const Style& rBorder )
324 { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * rBorder.Secn()) : 0; }
326 /** Returns the offset before start of single/primary line across the frame border.
327 @descr See description of lclGetBeg() for an illustration.
328 @return The offset directly before start of single/primary line relative
329 to the reference position of the frame border (sub units; a value one less
330 than lclGetBeg() for visible frame styles, or 0 for invisible frame style). */
331 inline long lclGetBeforeBeg( const Style& rBorder )
332 { return rBorder.Prim() ? (lclGetBeg( rBorder ) - 256) : 0; }
334 /** Returns the offset behind end of single/secondary line across the frame border.
335 @descr See description of lclGetBeg() for an illustration.
336 @return The offset directly behind end of single/secondary line relative
337 to the reference position of the frame border (sub units; a value one
338 greater than lclGetEnd() for visible frame styles, or 0 for invisible frame
339 style). */
340 inline long lclGetBehindEnd( const Style& rBorder )
341 { return rBorder.Prim() ? (lclGetEnd( rBorder ) + 256) : 0; }
344 // Linking functions
348 // Linking of single horizontal line ends.
350 /** Calculates X offsets for the left end of a single horizontal frame border.
352 See DrawHorFrameBorder() function for a description of all parameters.
354 @param rResult
355 (out-param) The contained values (sub units) specify offsets for the
356 X coordinates of the left line end.
358 void lclLinkLeftEnd_Single(
359 LineEndResult& rResult, const Style& rBorder,
360 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
362 // both vertical and diagonal frame borders are double
363 if( rLFromT.Secn() && rLFromB.Secn() && rLFromTR.Secn() && rLFromBR.Secn() )
365 // take left position of upper and lower secondary start
366 rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
367 rResult.mnOffs2 = GetTLDiagOffset( lclGetEnd( rBorder ), lclGetSecnBeg( rLFromBR ), rLFromBR.GetAngle() );
369 else
371 // both vertical frame borders are double
372 if( rLFromT.Secn() && rLFromB.Secn() )
374 rResult.mnOffs1 = (!rLFromTR.Secn() && !rLFromBR.Secn() && (rLFromT.GetWidth() == rLFromB.GetWidth())) ?
375 // don't overdraw vertical borders with equal width
376 lclGetBehindEnd( rLFromT ) :
377 // take leftmost start of both secondary lines (#46488#)
378 std::min( lclGetSecnBeg( rLFromT ), lclGetSecnBeg( rLFromB ) );
381 // single border with equal width coming from left
382 else if( !rLFromL.Secn() && (rLFromL.Prim() == rBorder.Prim()) )
383 // draw to connection point
384 rResult.mnOffs1 = 0;
386 // single border coming from left
387 else if( !rLFromL.Secn() && rLFromL.Prim() )
389 if( rLFromL.Prim() == rBorder.Prim() )
390 // draw to reference position, if from left has equal width
391 rResult.mnOffs1 = 0;
392 else
393 rResult.mnOffs1 = (rLFromL < rBorder) ?
394 // take leftmost start of both frame borders, if from left is thinner
395 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
396 // do not overdraw vertical, if from left is thicker
397 std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
400 // no border coming from left
401 else if( !rLFromL.Prim() )
402 // don't overdraw vertical borders with equal width
403 rResult.mnOffs1 = (rLFromT.GetWidth() == rLFromB.GetWidth()) ?
404 lclGetBehindEnd( rLFromT ) :
405 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) );
407 // double frame border coming from left and from top
408 else if( rLFromT.Secn() )
409 // do not overdraw the vertical double frame border
410 rResult.mnOffs1 = lclGetBehindEnd( rLFromT );
412 // double frame border coming from left and from bottom
413 else if( rLFromB.Secn() )
414 // do not overdraw the vertical double frame border
415 rResult.mnOffs1 = lclGetBehindEnd( rLFromB );
417 // double frame border coming from left, both vertical frame borders are single or off
418 else
419 // draw from leftmost start of both frame borders, if from left is not thicker
420 rResult.mnOffs1 = (rLFromL <= rBorder) ?
421 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
422 std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
424 // bottom-left point is equal to top-left point (results in rectangle)
425 rResult.mnOffs2 = rResult.mnOffs1;
429 /** Calculates X offsets for the left end of a primary horizontal line.
431 See DrawHorFrameBorder() function for a description of all parameters.
433 @param rResult
434 (out-param) The contained values (sub units) specify offsets for the
435 X coordinates of the left end of the primary line.
437 void lclLinkLeftEnd_Prim(
438 LineEndResult& rResult, const Style& rBorder,
439 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )
441 // double diagonal frame border coming from top right
442 if( rLFromTR.Secn() )
444 // draw from where secondary diagonal line meets the own primary
445 rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
446 rResult.mnOffs2 = GetBLDiagOffset( lclGetPrimEnd( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
449 // no or single diagonal frame border - ignore it
450 else
452 // double frame border coming from top
453 if( rLFromT.Secn() )
454 // draw from left edge of secondary vertical
455 rResult.mnOffs1 = lclGetSecnBeg( rLFromT );
457 // double frame border coming from left (from top is not double)
458 else if( rLFromL.Secn() )
459 // do not overdraw single frame border coming from top
460 rResult.mnOffs1 = (rLFromL.GetWidth() == rBorder.GetWidth()) ?
461 0 : lclGetBehindEnd( rLFromT );
463 // double frame border coming from bottom (from top and from left are not double)
464 else if( rLFromB.Secn() )
465 // draw from left edge of primary vertical from bottom
466 rResult.mnOffs1 = lclGetBeg( rLFromB );
468 // no other frame border is double
469 else
470 // do not overdraw vertical frame borders
471 rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
473 // bottom-left point is equal to top-left point (results in rectangle)
474 rResult.mnOffs2 = rResult.mnOffs1;
478 /** Calculates X offsets for the left end of a secondary horizontal line.
480 See DrawHorFrameBorder() function for a description of all parameters.
482 @param rResult
483 (out-param) The contained values (sub units) specify offsets for the
484 X coordinates of the left end of the secondary line.
486 void lclLinkLeftEnd_Secn(
487 LineEndResult& rResult, const Style& rBorder,
488 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
490 /* Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */
491 lclLinkLeftEnd_Prim( rResult, rBorder.Mirror(), rLFromBR, rLFromB, rLFromL.Mirror(), rLFromT, rLFromTR );
492 rResult.Swap();
495 void lclLinkLeftEnd_Gap(
496 LineEndResult& rResult, const Style& rBorder,
497 const DiagStyle& /*rLFromTR*/, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )
500 if ( rLFromT.Secn() )
501 rResult.mnOffs1 = lclGetDistBeg( rLFromT );
502 else if ( rLFromL.Secn( ) )
503 rResult.mnOffs1 = ( rLFromL.GetWidth() == rBorder.GetWidth() )?
504 0 : lclGetBehindEnd( rLFromT );
505 else if ( rLFromB.Secn( ) )
506 rResult.mnOffs1 = lclGetDistBeg( rLFromB );
507 else
508 rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
510 rResult.mnOffs2 = rResult.mnOffs1;
513 // Linking of horizontal frame border ends.
515 /** Calculates X offsets for the left end of a horizontal frame border.
517 This function can be used for single and double frame borders.
518 See DrawHorFrameBorder() function for a description of all parameters.
520 @param rResult
521 (out-param) The contained values (sub units) specify offsets for the
522 X coordinates of the left end of the line(s) in the frame border.
524 void lclLinkLeftEnd(
525 BorderEndResult& rResult, const Style& rBorder,
526 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
528 if( rBorder.Secn() )
530 // current frame border is double
531 lclLinkLeftEnd_Prim( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
532 lclLinkLeftEnd_Secn( rResult.maSecn, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
533 lclLinkLeftEnd_Gap( rResult.maGap, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
535 else if( rBorder.Prim() )
537 // current frame border is single
538 lclLinkLeftEnd_Single( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
540 else
542 SAL_WARN( "svx.dialog", "lclLinkLeftEnd - called for invisible frame style" );
546 /** Calculates X offsets for the right end of a horizontal frame border.
548 This function can be used for single and double frame borders.
549 See DrawHorFrameBorder() function for a description of all parameters.
551 @param rResult
552 (out-param) The contained values (sub units) specify offsets for the
553 X coordinates of the right end of the line(s) in the frame border.
555 void lclLinkRightEnd(
556 BorderEndResult& rResult, const Style& rBorder,
557 const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
559 /* Recycle lclLinkLeftEnd() function with mirrored vertical borders. */
560 lclLinkLeftEnd( rResult, rBorder, rRFromTL.Mirror(), rRFromT.Mirror(), rRFromR, rRFromB.Mirror(), rRFromBL.Mirror() );
561 rResult.Negate();
565 // Linking of horizontal and vertical frame borders.
567 /** Calculates X offsets for all line ends of a horizontal frame border.
569 This function can be used for single and double frame borders.
570 See DrawHorFrameBorder() function for a description of all parameters.
572 @param rResult
573 (out-param) The contained values (sub units) specify offsets for the
574 X coordinates of both ends of the line(s) in the frame border. To get
575 the actual X coordinates to draw the lines, these offsets have to be
576 added to the X coordinates of the reference points of the frame border
577 (the offsets may be negative).
579 void lclLinkHorFrameBorder(
580 BorderResult& rResult, const Style& rBorder,
581 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
582 const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
584 lclLinkLeftEnd( rResult.maBeg, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
585 lclLinkRightEnd( rResult.maEnd, rBorder, rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
588 /** Calculates Y offsets for all line ends of a vertical frame border.
590 This function can be used for single and double frame borders.
591 See DrawVerFrameBorder() function for a description of all parameters.
593 @param rResult
594 (out-param) The contained values (sub units) specify offsets for the
595 Y coordinates of both ends of the line(s) in the frame border. To get
596 the actual Y coordinates to draw the lines, these offsets have to be
597 added to the Y coordinates of the reference points of the frame border
598 (the offsets may be negative).
600 void lclLinkVerFrameBorder(
601 BorderResult& rResult, const Style& rBorder,
602 const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
603 const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR )
605 /* Recycle lclLinkHorFrameBorder() function with correct parameters. The
606 frame border is virtually mirrored at the top-left to bottom-right
607 diagonal. rTFromBR and rBFromTL are mirrored to process their primary
608 and secondary lines correctly. */
609 lclLinkHorFrameBorder( rResult, rBorder,
610 rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR.Mirror(),
611 rBFromTL.Mirror(), rBFromL, rBFromB, rBFromR, rBFromTR );
617 // Linking of diagonal frame borders.
619 /** Calculates clipping offsets for a top-left to bottom-right frame border.
621 This function can be used for single and double frame borders.
622 See DrawDiagFrameBorders() function for a description of all parameters.
624 @param rResult
625 (out-param) The contained values (sub units) specify offsets for all
626 borders of the reference rectangle containing the diagonal frame border.
628 void lclLinkTLBRFrameBorder(
629 DiagBorderResult& rResult, const Style& rBorder,
630 const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL )
632 bool bIsDbl = rBorder.Secn() != 0;
634 rResult.maPrim.mnLClip = lclGetBehindEnd( rTLFromB );
635 rResult.maPrim.mnRClip = (bIsDbl && rBRFromT.Secn()) ? lclGetEnd( rBRFromT ) : lclGetBeforeBeg( rBRFromT );
636 rResult.maPrim.mnTClip = (bIsDbl && rTLFromR.Secn()) ? lclGetBeg( rTLFromR ) : lclGetBehindEnd( rTLFromR );
637 rResult.maPrim.mnBClip = lclGetBeforeBeg( rBRFromL );
639 if( bIsDbl )
641 rResult.maSecn.mnLClip = rTLFromB.Secn() ? lclGetBeg( rTLFromB ) : lclGetBehindEnd( rTLFromB );
642 rResult.maSecn.mnRClip = lclGetBeforeBeg( rBRFromT );
643 rResult.maSecn.mnTClip = lclGetBehindEnd( rTLFromR );
644 rResult.maSecn.mnBClip = rBRFromL.Secn() ? lclGetEnd( rBRFromL ) : lclGetBeforeBeg( rBRFromL );
648 /** Calculates clipping offsets for a bottom-left to top-right frame border.
650 This function can be used for single and double frame borders.
651 See DrawDiagFrameBorders() function for a description of all parameters.
653 @param rResult
654 (out-param) The contained values (sub units) specify offsets for all
655 borders of the reference rectangle containing the diagonal frame border.
657 void lclLinkBLTRFrameBorder(
658 DiagBorderResult& rResult, const Style& rBorder,
659 const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
661 bool bIsDbl = rBorder.Secn() != 0;
663 rResult.maPrim.mnLClip = lclGetBehindEnd( rBLFromT );
664 rResult.maPrim.mnRClip = (bIsDbl && rTRFromB.Secn()) ? lclGetEnd( rTRFromB ) : lclGetBeforeBeg( rTRFromB );
665 rResult.maPrim.mnTClip = lclGetBehindEnd( rTRFromL );
666 rResult.maPrim.mnBClip = (bIsDbl && rBLFromR.Secn()) ? lclGetEnd( rBLFromR ) : lclGetBeforeBeg( rBLFromR );
668 if( bIsDbl )
670 rResult.maSecn.mnLClip = rBLFromT.Secn() ? lclGetBeg( rBLFromT ) : lclGetBehindEnd( rBLFromT );
671 rResult.maSecn.mnRClip = lclGetBeforeBeg( rTRFromB );
672 rResult.maSecn.mnTClip = rTRFromL.Secn() ? lclGetBeg( rTRFromL ) : lclGetBehindEnd( rTRFromL );
673 rResult.maSecn.mnBClip = lclGetBeforeBeg( rBLFromR );
677 /** Calculates clipping offsets for both diagonal frame borders.
679 This function can be used for single and double frame borders.
680 See DrawDiagFrameBorders() function for a description of all parameters.
682 @param rResult
683 (out-param) The contained values (sub units) specify offsets for all
684 borders of the reference rectangle containing the diagonal frame
685 borders.
687 void lclLinkDiagFrameBorders(
688 DiagBordersResult& rResult, const Style& rTLBR, const Style& rBLTR,
689 const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
690 const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
692 lclLinkTLBRFrameBorder( rResult.maTLBR, rTLBR, rTLFromB, rTLFromR, rBRFromT, rBRFromL );
693 lclLinkBLTRFrameBorder( rResult.maBLTR, rBLTR, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
697 // Drawing functions
701 // Simple helper functions
703 /** Converts sub units to OutputDevice map units. */
704 inline long lclToMapUnit( long nSubUnits )
706 return ((nSubUnits < 0) ? (nSubUnits - 127) : (nSubUnits + 128)) / 256;
709 /** Converts a point in sub units to an OutputDevice point. */
710 inline Point lclToMapUnit( long nSubXPos, long nSubYPos )
712 return Point( lclToMapUnit( nSubXPos ), lclToMapUnit( nSubYPos ) );
715 /** Returns a polygon constructed from a vector of points. */
716 inline Polygon lclCreatePolygon( const PointVec& rPoints )
718 return Polygon( static_cast< sal_uInt16 >( rPoints.size() ), &rPoints[ 0 ] );
721 /** Returns a polygon constructed from the five passed points. */
722 vcl::Region lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4, const Point& rP5 )
724 PointVec aPoints;
725 aPoints.reserve( 5 );
726 aPoints.push_back( rP1 );
727 aPoints.push_back( rP2 );
728 aPoints.push_back( rP3 );
729 aPoints.push_back( rP4 );
730 aPoints.push_back( rP5 );
731 return vcl::Region(lclCreatePolygon(aPoints));
734 /** Sets the color of the passed frame style to the output device.
736 Sets the line color and fill color in the output device.
738 @param rDev
739 The output device the color has to be set to. The old colors are pushed
740 onto the device's stack and can be restored with a call to
741 OutputDevice::Pop(). Please take care about the correct calling order
742 of Pop() if this function is used with other functions pushing
743 something onto the stack.
744 @param rStyle
745 The border style that contains the line color to be set to the device.
747 void lclSetColorToOutDev( OutputDevice& rDev, const Color& rColor, const Color* pForceColor )
749 rDev.Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
750 rDev.SetLineColor( pForceColor ? *pForceColor : rColor );
751 rDev.SetFillColor( pForceColor ? *pForceColor : rColor );
756 // Drawing of horizontal frame borders.
758 /** Draws a horizontal thin or thick line into the passed output device.
760 The X coordinates of the edges of the line are adjusted according to the
761 passed LineEndResult structs. A one pixel wide line can be drawn dotted.
763 void lclDrawHorLine(
764 OutputDevice& rDev,
765 const Point& rLPos, const LineEndResult& rLRes,
766 const Point& rRPos, const LineEndResult& rRRes,
767 long nTOffs, long nBOffs, SvxBorderStyle nDashing )
769 LinePoints aTPoints( rLPos + lclToMapUnit( rLRes.mnOffs1, nTOffs ), rRPos + lclToMapUnit( rRRes.mnOffs1, nTOffs ) );
770 LinePoints aBPoints( rLPos + lclToMapUnit( rLRes.mnOffs2, nBOffs ), rRPos + lclToMapUnit( rRRes.mnOffs2, nBOffs ) );
772 sal_uInt32 nWidth = lclToMapUnit( std::abs( nTOffs ) ) + lclToMapUnit( std::abs( nBOffs ) );
773 if ( ( nTOffs >= 0 && nBOffs >= 0 ) || ( nTOffs <= 0 && nBOffs <= 0 ) )
774 nWidth = std::abs( lclToMapUnit( nTOffs ) - lclToMapUnit( nBOffs ) ) + 1;
775 Point rLMid = ( aTPoints.maBeg + aBPoints.maBeg ) / 2;
776 Point rRMid = ( aTPoints.maEnd + aBPoints.maEnd ) / 2;
778 ::svtools::DrawLine( rDev, rLMid, rRMid, nWidth, nDashing );
781 /** Draws a horizontal frame border into the passed output device.
783 @param rLPos
784 The top-left or bottom-left reference point of the diagonal frame border.
785 @param rRPos
786 The top-right or bottom-right reference point of the diagonal frame border.
787 @param rBorder
788 The frame style used to draw the border.
789 @param rResult
790 The X coordinates of the edges of all lines of the frame border are
791 adjusted according to the offsets contained here.
793 void lclDrawHorFrameBorder(
794 OutputDevice& rDev, const Point& rLPos, const Point& rRPos,
795 const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
797 DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" );
798 DBG_ASSERT( rLPos.X() <= rRPos.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" );
799 DBG_ASSERT( rLPos.Y() == rRPos.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" );
800 if( rLPos.X() <= rRPos.X() )
802 if ( rBorder.UseGapColor( ) )
804 lclSetColorToOutDev( rDev, rBorder.GetColorGap(), pForceColor );
805 lclDrawHorLine( rDev, rLPos, rResult.maBeg.maGap, rRPos, rResult.maEnd.maGap,
806 lclGetPrimEnd( rBorder ), lclGetSecnBeg( rBorder ), rBorder.Type() );
807 rDev.Pop(); // Gap color
810 lclSetColorToOutDev( rDev, rBorder.GetColorPrim(), pForceColor );
811 lclDrawHorLine( rDev, rLPos, rResult.maBeg.maPrim, rRPos, rResult.maEnd.maPrim,
812 lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Type() );
813 rDev.Pop(); // colors
815 if( rBorder.Secn() )
817 lclSetColorToOutDev( rDev, rBorder.GetColorSecn(), pForceColor );
818 lclDrawHorLine( rDev, rLPos, rResult.maBeg.maSecn, rRPos, rResult.maEnd.maSecn,
819 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Type() );
820 rDev.Pop(); // colors
826 // Drawing of vertical frame borders.
828 /** Draws a vertical thin or thick line into the passed output device.
830 The Y coordinates of the edges of the line are adjusted according to the
831 passed LineEndResult structs. A one pixel wide line can be drawn dotted.
833 void lclDrawVerLine(
834 OutputDevice& rDev,
835 const Point& rTPos, const LineEndResult& rTRes,
836 const Point& rBPos, const LineEndResult& rBRes,
837 long nLOffs, long nROffs, SvxBorderStyle nDashing )
839 LinePoints aLPoints( rTPos + lclToMapUnit( nLOffs, rTRes.mnOffs1 ), rBPos + lclToMapUnit( nLOffs, rBRes.mnOffs1 ) );
840 LinePoints aRPoints( rTPos + lclToMapUnit( nROffs, rTRes.mnOffs2 ), rBPos + lclToMapUnit( nROffs, rBRes.mnOffs2 ) );
842 sal_uInt32 nWidth = lclToMapUnit( std::abs( nLOffs ) ) + lclToMapUnit( std::abs( nROffs ) );
843 if ( ( nLOffs >= 0 && nROffs >= 0 ) || ( nLOffs <= 0 && nROffs <= 0 ) )
844 nWidth = std::abs( lclToMapUnit( nLOffs ) - lclToMapUnit( nROffs ) ) + 1;
845 Point rTMid = ( aLPoints.maBeg + aRPoints.maBeg ) / 2;
846 Point rBMid = ( aLPoints.maEnd + aRPoints.maEnd ) / 2;
848 ::svtools::DrawLine( rDev, rTMid, rBMid, nWidth, nDashing );
851 /** Draws a vertical frame border into the passed output device.
853 @param rTPos
854 The top-left or top-right reference point of the diagonal frame border.
855 @param rBPos
856 The bottom-left or bottom-right reference point of the diagonal frame border.
857 @param rBorder
858 The frame style used to draw the border.
859 @param rResult
860 The Y coordinates of the edges of all lines of the frame border are
861 adjusted according to the offsets contained here.
863 void lclDrawVerFrameBorder(
864 OutputDevice& rDev, const Point& rTPos, const Point& rBPos,
865 const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
867 DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" );
868 DBG_ASSERT( rTPos.Y() <= rBPos.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" );
869 DBG_ASSERT( rTPos.X() == rBPos.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" );
870 if( rTPos.Y() <= rBPos.Y() )
872 if ( rBorder.UseGapColor( ) )
874 lclSetColorToOutDev( rDev, rBorder.GetColorGap(), pForceColor );
875 lclDrawVerLine( rDev, rTPos, rResult.maBeg.maGap, rBPos, rResult.maEnd.maGap,
876 lclGetPrimEnd( rBorder ), lclGetSecnBeg( rBorder ), rBorder.Type() );
877 rDev.Pop(); // Gap color
880 lclSetColorToOutDev( rDev, rBorder.GetColorPrim(), pForceColor );
881 lclDrawVerLine( rDev, rTPos, rResult.maBeg.maPrim, rBPos, rResult.maEnd.maPrim,
882 lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Type() );
883 rDev.Pop(); // colors
884 if( rBorder.Secn() )
886 lclSetColorToOutDev( rDev, rBorder.GetColorSecn(), pForceColor );
887 lclDrawVerLine( rDev, rTPos, rResult.maBeg.maSecn, rBPos, rResult.maEnd.maSecn,
888 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Type() );
889 rDev.Pop(); // colors
895 // Drawing of diagonal frame borders, incudes clipping functions.
897 /** Returns the drawing coordinates for a diagonal thin line.
899 This function can be used for top-left to bottom-right and for bottom-left
900 to top-right lines.
902 @param rRect
903 The reference rectangle of the diagonal frame border.
904 @param bTLBR
905 true = top-left to bottom-right; false = bottom-left to top-right.
906 @param nDiagOffs
907 Width offset (sub units) across the diagonal frame border.
908 @return
909 A struct containg start and end position of the diagonal line.
911 LinePoints lclGetDiagLineEnds( const Rectangle& rRect, bool bTLBR, long nDiagOffs )
913 LinePoints aPoints( rRect, bTLBR );
914 bool bVert = rRect.GetWidth() < rRect.GetHeight();
915 double fAngle = bVert ? GetVerDiagAngle( rRect ) : GetHorDiagAngle( rRect );
916 // vertical top-left to bottom-right borders are handled mirrored
917 if( bVert && bTLBR )
918 nDiagOffs = -nDiagOffs;
919 long nTOffs = bTLBR ? GetTLDiagOffset( 0, nDiagOffs, fAngle ) : GetTRDiagOffset( 0, nDiagOffs, fAngle );
920 long nBOffs = bTLBR ? GetBRDiagOffset( 0, nDiagOffs, fAngle ) : GetBLDiagOffset( 0, nDiagOffs, fAngle );
921 // vertical bottom-left to top-right borders are handled with exchanged end points
922 if( bVert && !bTLBR )
923 std::swap( nTOffs, nBOffs );
924 (bVert ? aPoints.maBeg.Y() : aPoints.maBeg.X()) += lclToMapUnit( nTOffs );
925 (bVert ? aPoints.maEnd.Y() : aPoints.maEnd.X()) += lclToMapUnit( nBOffs );
926 return aPoints;
930 // Clipping functions for diagonal frame borders.
932 /** Limits the clipping region to the inner area of a rectange.
934 Takes the values from the passed DiagLineResult struct into account. They
935 may specify to not clip one or more borders of a rectangle.
937 @param rDev
938 The output device with the clipping region to be modified. The old
939 clipping region is pushed onto the device's stack and can be restored
940 with a call to OutputDevice::Pop(). Please take care about the correct
941 calling order of Pop() if this function is used with other functions
942 pushing something onto the stack.
943 @param rRect
944 The reference rectangle of the diagonal frame borders.
945 @param rResult
946 The result struct containing modifies for each border of the reference
947 rectangle.
949 void lclPushDiagClipRect( OutputDevice& rDev, const Rectangle& rRect, const DiagLineResult& rResult )
951 // PixelToLogic() regards internal offset of the output device
952 Rectangle aClipRect( rRect );
953 aClipRect.Left() += lclToMapUnit( rResult.mnLClip );
954 aClipRect.Top() += lclToMapUnit( rResult.mnTClip );
955 aClipRect.Right() += lclToMapUnit( rResult.mnRClip );
956 aClipRect.Bottom() += lclToMapUnit( rResult.mnBClip );
957 // output device would adjust the rectangle -> invalidate it before
958 if( (aClipRect.GetWidth() < 1) ||(aClipRect.GetHeight() < 1) )
959 aClipRect.SetEmpty();
961 rDev.Push( PushFlags::CLIPREGION );
962 rDev.IntersectClipRegion( aClipRect );
965 /** Excludes inner area of a crossing double frame border from clipping region.
967 This function is used to modify the clipping region so that it excludes the
968 inner free area of a double diagonal frame border. This makes it possible
969 to draw a diagonal frame border in one step without taking care of the
970 crossing double frame border.
972 @param rDev
973 The output device with the clipping region to be modified. The old
974 clipping region is pushed onto the device's stack and can be restored
975 with a call to OutputDevice::Pop(). Please take care about the correct
976 calling order of Pop() if this function is used with other functions
977 pushing something onto the stack.
978 @param rRect
979 The reference rectangle of the diagonal frame borders.
980 @param bTLBR
981 The orientation of the processed frame border (not the orientation of
982 the crossing frame border).
983 @param bCrossStyle
984 The style of the crossing frame border. Must be a double frame style.
986 void lclPushCrossingClipRegion( OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, const Style& rCrossStyle )
988 DBG_ASSERT( rCrossStyle.Secn(), "lclGetCrossingClipRegion - use only for double styles" );
989 LinePoints aLPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetPrimEnd( rCrossStyle ) ) );
990 LinePoints aRPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetSecnBeg( rCrossStyle ) ) );
992 vcl::Region aClipReg;
993 if( bTLBR )
995 aClipReg = lclCreatePolygon(
996 aLPoints.maBeg, aLPoints.maEnd, rRect.BottomRight(), rRect.BottomLeft(), rRect.TopLeft() );
997 aClipReg.Union( lclCreatePolygon(
998 aRPoints.maBeg, aRPoints.maEnd, rRect.BottomRight(), rRect.TopRight(), rRect.TopLeft() ) );
1000 else
1002 aClipReg = lclCreatePolygon(
1003 aLPoints.maBeg, aLPoints.maEnd, rRect.BottomLeft(), rRect.TopLeft(), rRect.TopRight() );
1004 aClipReg.Union( lclCreatePolygon(
1005 aRPoints.maBeg, aRPoints.maEnd, rRect.BottomLeft(), rRect.BottomRight(), rRect.TopRight() ) );
1008 rDev.Push( PushFlags::CLIPREGION );
1009 rDev.IntersectClipRegion( aClipReg );
1013 // Drawing functions for diagonal frame borders.
1015 /** Draws a diagonal thin or thick line into the passed output device.
1017 The clipping region of the output device is modified according to the
1018 passed DiagLineResult struct. A one pixel wide line can be drawn dotted.
1020 void lclDrawDiagLine(
1021 OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1022 const DiagLineResult& rResult, long nDiagOffs1, long nDiagOffs2, SvxBorderStyle nDashing )
1024 lclPushDiagClipRect( rDev, rRect, rResult );
1025 LinePoints aLPoints( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs1 ) );
1026 LinePoints aL2Points( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs2 ) );
1027 Point aSMid( ( aLPoints.maBeg + aL2Points.maBeg ) / 2 );
1028 Point aEMid( ( aLPoints.maEnd + aL2Points.maEnd ) / 2 );
1030 sal_uInt32 nWidth = lclToMapUnit( std::abs( nDiagOffs1 ) ) + lclToMapUnit( std::abs( nDiagOffs2 ) );
1031 if ( ( nDiagOffs1 <= 0 && nDiagOffs2 <= 0 ) || ( nDiagOffs1 >=0 && nDiagOffs2 >=0 ) )
1032 nWidth = lclToMapUnit( std::abs( nDiagOffs1 - nDiagOffs2 ) );
1034 svtools::DrawLine( rDev, aSMid, aEMid, nWidth, nDashing );
1035 rDev.Pop(); // clipping region
1038 /** Draws a diagonal frame border into the passed output device.
1040 The lines of the frame border are drawn interrupted, if the style of the
1041 crossing frame border is double.
1043 @param rRect
1044 The reference rectangle of the diagonal frame border.
1045 @param bTLBR
1046 The orientation of the diagonal frame border.
1047 @param rBorder
1048 The frame style used to draw the border.
1049 @param rResult
1050 Offsets (sub units) to modify the clipping region of the output device.
1051 @param rCrossStyle
1052 Style of the crossing diagonal frame border.
1054 void lclDrawDiagFrameBorder(
1055 OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1056 const Style& rBorder, const DiagBorderResult& rResult, const Style& rCrossStyle,
1057 const Color* pForceColor, bool bDiagDblClip )
1059 DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" );
1061 bool bClip = bDiagDblClip && rCrossStyle.Secn();
1062 if( bClip )
1063 lclPushCrossingClipRegion( rDev, rRect, bTLBR, rCrossStyle );
1065 lclSetColorToOutDev( rDev, rBorder.GetColorPrim(), pForceColor );
1066 lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maPrim, lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Type() );
1067 rDev.Pop(); // colors
1068 if( rBorder.Secn() )
1070 if ( rBorder.UseGapColor( ) )
1072 lclSetColorToOutDev( rDev, rBorder.GetColorGap(), pForceColor );
1073 lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetDistBeg( rBorder ), lclGetDistEnd( rBorder ), rBorder.Type() );
1074 rDev.Pop(); // colors
1077 lclSetColorToOutDev( rDev, rBorder.GetColorSecn(), pForceColor );
1078 lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Type() );
1079 rDev.Pop(); // colors
1082 if( bClip )
1083 rDev.Pop(); // clipping region
1086 /** Draws both diagonal frame borders into the passed output device.
1088 The lines of each frame border is drawn interrupted, if the style of the
1089 other crossing frame border is double.
1091 @param rRect
1092 The reference rectangle of the diagonal frame borders.
1093 @param rTLBR
1094 The frame style of the top-left to bottom-right frame border.
1095 @param rBLTR
1096 The frame style of the bottom-left to top-right frame border.
1097 @param rResult
1098 Offsets (sub units) to modify the clipping region of the output device.
1100 void lclDrawDiagFrameBorders(
1101 OutputDevice& rDev, const Rectangle& rRect,
1102 const Style& rTLBR, const Style& rBLTR, const DiagBordersResult& rResult,
1103 const Color* pForceColor, bool bDiagDblClip )
1105 DBG_ASSERT( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" );
1106 if( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1) )
1108 bool bDrawTLBR = rTLBR.Prim() != 0;
1109 bool bDrawBLTR = rBLTR.Prim() != 0;
1110 bool bFirstDrawBLTR = rTLBR.Secn() != 0;
1112 if( bDrawBLTR && bFirstDrawBLTR )
1113 lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1114 if( bDrawTLBR )
1115 lclDrawDiagFrameBorder( rDev, rRect, true, rTLBR, rResult.maTLBR, rBLTR, pForceColor, bDiagDblClip );
1116 if( bDrawBLTR && !bFirstDrawBLTR )
1117 lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1123 } // namespace
1126 // Classes
1129 #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth )
1131 Style::Style() :
1132 meRefMode(REFMODE_CENTERED),
1133 mfPatternScale(1.0),
1134 mnType(table::BorderLineStyle::SOLID)
1136 Clear();
1139 Style::Style( double nP, double nD, double nS, editeng::SvxBorderStyle nType ) :
1140 meRefMode(REFMODE_CENTERED),
1141 mfPatternScale(1.0),
1142 mnType(nType)
1144 Clear();
1145 Set( nP, nD, nS );
1148 Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor,
1149 double nP, double nD, double nS, editeng::SvxBorderStyle nType ) :
1150 meRefMode(REFMODE_CENTERED),
1151 mfPatternScale(1.0),
1152 mnType(nType)
1154 Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS );
1157 Style::Style( const editeng::SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth ) :
1158 meRefMode(REFMODE_CENTERED),
1159 mfPatternScale(fScale)
1161 Set( pBorder, fScale, nMaxWidth );
1165 void Style::SetPatternScale( double fScale )
1167 mfPatternScale = fScale;
1170 void Style::Clear()
1172 Set( Color(), Color(), Color(), false, 0, 0, 0 );
1175 void Style::Set( double nP, double nD, double nS )
1177 /* nP nD nS -> mfPrim mfDist mfSecn
1178 --------------------------------------
1179 any any 0 nP 0 0
1180 0 any >0 nS 0 0
1181 >0 0 >0 nP 0 0
1182 >0 >0 >0 nP nD nS
1184 mfPrim = rtl::math::round(nP ? nP : nS, 2);
1185 mfDist = rtl::math::round((nP && nS) ? nD : 0, 2);
1186 mfSecn = rtl::math::round((nP && nD) ? nS : 0, 2);
1189 void Style::Set( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS )
1191 maColorPrim = rColorPrim;
1192 maColorSecn = rColorSecn;
1193 maColorGap = rColorGap;
1194 mbUseGapColor = bUseGapColor;
1195 Set( nP, nD, nS );
1198 void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth )
1200 maColorPrim = rBorder.GetColorOut();
1201 maColorSecn = rBorder.GetColorIn();
1202 maColorGap = rBorder.GetColorGap();
1203 mbUseGapColor = rBorder.HasGapColor();
1205 sal_uInt16 nPrim = rBorder.GetOutWidth();
1206 sal_uInt16 nDist = rBorder.GetDistance();
1207 sal_uInt16 nSecn = rBorder.GetInWidth();
1209 mnType = rBorder.GetBorderLineStyle();
1210 if( !nSecn ) // no or single frame border
1212 Set( SCALEVALUE( nPrim ), 0, 0 );
1214 else
1216 Set( SCALEVALUE( nPrim ), SCALEVALUE( nDist ), SCALEVALUE( nSecn ) );
1217 // Enlarge the style if distance is too small due to rounding losses.
1218 double nPixWidth = SCALEVALUE( nPrim + nDist + nSecn );
1219 if( nPixWidth > GetWidth() )
1220 mfDist = nPixWidth - mfPrim - mfSecn;
1221 // Shrink the style if it is too thick for the control.
1222 while( GetWidth() > nMaxWidth )
1224 // First decrease space between lines.
1225 if (mfDist)
1226 --mfDist;
1227 // Still too thick? Decrease the line widths.
1228 if( GetWidth() > nMaxWidth )
1230 if (!rtl::math::approxEqual(mfPrim, 0.0) && rtl::math::approxEqual(mfPrim, mfSecn))
1232 // Both lines equal - decrease both to keep symmetry.
1233 --mfPrim;
1234 --mfSecn;
1236 else
1238 // Decrease each line for itself
1239 if (mfPrim)
1240 --mfPrim;
1241 if ((GetWidth() > nMaxWidth) && !rtl::math::approxEqual(mfSecn, 0.0))
1242 --mfSecn;
1249 void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth )
1251 if( pBorder )
1252 Set( *pBorder, fScale, nMaxWidth );
1253 else
1255 Clear();
1256 mnType = table::BorderLineStyle::SOLID;
1260 Style& Style::MirrorSelf()
1262 if (mfSecn)
1263 std::swap( mfPrim, mfSecn );
1264 if( meRefMode != REFMODE_CENTERED )
1265 meRefMode = (meRefMode == REFMODE_BEGIN) ? REFMODE_END : REFMODE_BEGIN;
1266 return *this;
1269 Style Style::Mirror() const
1271 return Style( *this ).MirrorSelf();
1274 bool operator==( const Style& rL, const Style& rR )
1276 return (rL.Prim() == rR.Prim()) && (rL.Dist() == rR.Dist()) && (rL.Secn() == rR.Secn()) &&
1277 (rL.GetColorPrim() == rR.GetColorPrim()) && (rL.GetColorSecn() == rR.GetColorSecn()) &&
1278 (rL.GetColorGap() == rR.GetColorGap()) && (rL.GetRefMode() == rR.GetRefMode()) &&
1279 (rL.UseGapColor() == rR.UseGapColor() ) && (rL.Type() == rR.Type());
1282 bool operator<( const Style& rL, const Style& rR )
1284 // different total widths -> rL<rR, if rL is thinner
1285 double nLW = rL.GetWidth();
1286 double nRW = rR.GetWidth();
1287 if( nLW != nRW ) return nLW < nRW;
1289 // one line double, the other single -> rL<rR, if rL is single
1290 if( (rL.Secn() == 0) != (rR.Secn() == 0) ) return rL.Secn() == 0;
1292 // both lines double with different distances -> rL<rR, if distance of rL greater
1293 if( (rL.Secn() && rR.Secn()) && (rL.Dist() != rR.Dist()) ) return rL.Dist() > rR.Dist();
1295 // both lines single and 1 unit thick, only one is dotted -> rL<rR, if rL is dotted
1296 if( (nLW == 1) && (rL.Type() != rR.Type()) ) return rL.Type();
1298 // seem to be equal
1299 return false;
1302 #undef SCALEVALUE
1305 // Various helper functions
1308 double GetHorDiagAngle( long nWidth, long nHeight )
1310 return atan2( static_cast< double >( std::abs( nHeight ) ), static_cast< double >( std::abs( nWidth ) ) );
1315 long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1317 return lclD2L( nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1320 long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1322 return lclD2L( -nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1325 long GetBRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1327 return -lclD2L( -nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1330 long GetTRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1332 return -lclD2L( nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1337 bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
1338 const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
1339 const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
1341 return // returns 1 AND (2a OR 2b)
1342 // 1) only, if both frame borders are equal
1343 (rLBorder == rRBorder)
1347 // 2a) if the borders are not double, at least one of the vertical must not be double
1348 !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn())
1352 // 2b) if the borders are double, all other borders must not be double
1353 rLBorder.Secn() &&
1354 !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() &&
1355 !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn()
1361 // Drawing functions
1364 double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOpposite,
1365 long nAngleSide = 9000, long nAngleOpposite = 9000 )
1367 Style aOtherBorder = rSide;
1368 long nOtherAngle = nAngleSide;
1369 if ( rSide.GetWidth() == 0 && rOpposite.GetWidth() > 0 )
1371 nOtherAngle = nAngleOpposite;
1372 aOtherBorder = rOpposite;
1374 else if ( rSide.GetWidth() == 0 && rOpposite.GetWidth() == 0 )
1376 if ( ( nAngleOpposite % 18000 ) == 0 )
1377 nOtherAngle = nAngleSide;
1378 else if ( ( nAngleSide % 18000 ) == 0 )
1379 nOtherAngle = nAngleOpposite;
1382 // Let's assume the border we are drawing is horizontal and compute all the angles / distances from this
1383 basegfx::B2DVector aBaseVector( 1.0, 0.0 );
1384 basegfx::B2DPoint aBasePoint( 0.0, static_cast<double>( rBorder.GetWidth() / 2 ) );
1386 basegfx::B2DHomMatrix aRotation;
1387 aRotation.rotate( double( nOtherAngle ) * M_PI / 18000.0 );
1389 basegfx::B2DVector aOtherVector = aRotation * aBaseVector;
1390 // Compute a line shifted by half the width of the other border
1391 basegfx::B2DVector aPerpendicular = basegfx::getNormalizedPerpendicular( aOtherVector );
1392 basegfx::B2DPoint aOtherPoint = basegfx::B2DPoint() + aPerpendicular * aOtherBorder.GetWidth() / 2;
1394 // Find the cut between the two lines
1395 double nCut = 0.0;
1396 basegfx::tools::findCut(
1397 aBasePoint, aBaseVector, aOtherPoint, aOtherVector,
1398 CutFlagValue::ALL, &nCut );
1400 return nCut;
1403 basegfx::B2DPoint lcl_PointToB2DPoint( const Point& rPoint )
1405 return basegfx::B2DPoint(rPoint.getX(), rPoint.getY());
1408 drawinglayer::primitive2d::Primitive2DSequence CreateClippedBorderPrimitives (
1409 const Point& rStart, const Point& rEnd, const Style& rBorder,
1410 const Rectangle& rClipRect )
1412 drawinglayer::primitive2d::Primitive2DSequence aSequence( 1 );
1413 basegfx::B2DPolygon aPolygon;
1414 aPolygon.append( lcl_PointToB2DPoint( rClipRect.TopLeft( ) ) );
1415 aPolygon.append( lcl_PointToB2DPoint( rClipRect.TopRight( ) ) );
1416 aPolygon.append( lcl_PointToB2DPoint( rClipRect.BottomRight( ) ) );
1417 aPolygon.append( lcl_PointToB2DPoint( rClipRect.BottomLeft( ) ) );
1418 aPolygon.setClosed( true );
1420 aSequence[0] = new drawinglayer::primitive2d::ClippedBorderLinePrimitive2D(
1421 lcl_PointToB2DPoint( rStart ),
1422 lcl_PointToB2DPoint( rEnd ),
1423 rBorder.Prim(),
1424 rBorder.Dist(),
1425 rBorder.Secn(),
1426 aPolygon,
1427 rBorder.GetColorSecn().getBColor(),
1428 rBorder.GetColorPrim().getBColor(),
1429 rBorder.GetColorGap().getBColor(),
1430 rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale() );
1432 return aSequence;
1435 drawinglayer::primitive2d::Primitive2DSequence CreateBorderPrimitives(
1436 const Point& rLPos, const Point& rRPos, const Style& rBorder,
1437 const DiagStyle& /*rLFromTR*/, const Style& rLFromT, const Style& /*rLFromL*/, const Style& rLFromB, const DiagStyle& /*rLFromBR*/,
1438 const DiagStyle& /*rRFromTL*/, const Style& rRFromT, const Style& /*rRFromR*/, const Style& rRFromB, const DiagStyle& /*rRFromBL*/,
1439 const Color* /*pForceColor*/, const long& nRotateT, const long& nRotateB )
1441 drawinglayer::primitive2d::Primitive2DSequence aSequence( 1 );
1443 basegfx::B2DPoint aStart( rLPos.getX(), rLPos.getY() );
1444 basegfx::B2DPoint aEnd( rRPos.getX(), rRPos.getY() );
1446 aSequence[0] = new drawinglayer::primitive2d::BorderLinePrimitive2D(
1447 aStart, aEnd,
1448 rBorder.Prim(),
1449 rBorder.Dist(),
1450 rBorder.Secn(),
1451 lcl_GetExtent( rBorder, rLFromT, rLFromB, nRotateT, - nRotateB ),
1452 lcl_GetExtent( rBorder, rRFromT, rRFromB, 18000 - nRotateT, nRotateB - 18000 ),
1453 lcl_GetExtent( rBorder, rLFromB, rLFromT, nRotateB, - nRotateT ),
1454 lcl_GetExtent( rBorder, rRFromB, rRFromT, 18000 - nRotateB, nRotateT - 18000 ),
1455 rBorder.GetColorSecn().getBColor(),
1456 rBorder.GetColorPrim().getBColor(),
1457 rBorder.GetColorGap().getBColor(),
1458 rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale() );
1460 return aSequence;
1463 drawinglayer::primitive2d::Primitive2DSequence CreateBorderPrimitives(
1464 const Point& rLPos, const Point& rRPos, const Style& rBorder,
1465 const Style& rLFromT, const Style& rLFromL, const Style& rLFromB,
1466 const Style& rRFromT, const Style& rRFromR, const Style& rRFromB,
1467 const Color* pForceColor, const long& nRotateT, const long& nRotateB )
1469 return CreateBorderPrimitives( rLPos, rRPos, rBorder,
1470 DiagStyle(), rLFromT, rLFromL, rLFromB, DiagStyle(),
1471 DiagStyle(), rRFromT, rRFromR, rRFromB, DiagStyle(),
1472 pForceColor, nRotateT, nRotateB );
1475 void DrawHorFrameBorder( OutputDevice& rDev,
1476 const Point& rLPos, const Point& rRPos, const Style& rBorder,
1477 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
1478 const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL,
1479 const Color* pForceColor )
1481 if( rBorder.Prim() )
1483 BorderResult aResult;
1484 lclLinkHorFrameBorder( aResult, rBorder,
1485 rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR,
1486 rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
1487 lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, aResult, pForceColor );
1493 void DrawVerFrameBorder( OutputDevice& rDev,
1494 const Point& rTPos, const Point& rBPos, const Style& rBorder,
1495 const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
1496 const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR,
1497 const Color* pForceColor )
1499 if( rBorder.Prim() )
1501 BorderResult aResult;
1502 lclLinkVerFrameBorder( aResult, rBorder,
1503 rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR,
1504 rBFromTL, rBFromL, rBFromB, rBFromR, rBFromTR );
1505 lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, aResult, pForceColor );
1511 void DrawDiagFrameBorders(
1512 OutputDevice& rDev, const Rectangle& rRect, const Style& rTLBR, const Style& rBLTR,
1513 const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
1514 const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL,
1515 const Color* pForceColor, bool bDiagDblClip )
1517 if( rTLBR.Prim() || rBLTR.Prim() )
1519 DiagBordersResult aResult;
1520 lclLinkDiagFrameBorders( aResult, rTLBR, rBLTR,
1521 rTLFromB, rTLFromR, rBRFromT, rBRFromL, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
1522 lclDrawDiagFrameBorders( rDev, rRect, rTLBR, rBLTR, aResult, pForceColor, bDiagDblClip );
1531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */