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