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