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