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_starmath.hxx" 26 27 #include "node.hxx" 28 #include "rect.hxx" 29 #include "symbol.hxx" 30 #include "smmod.hxx" 31 #include "document.hxx" 32 #include "view.hxx" 33 #include "mathtype.hxx" 34 35 #include <tools/gen.hxx> 36 #include <tools/fract.hxx> 37 #include <rtl/math.hxx> 38 #include <tools/color.hxx> 39 #include <vcl/metric.hxx> 40 #include <vcl/lineinfo.hxx> 41 #include <vcl/outdev.hxx> 42 #include <sfx2/module.hxx> 43 44 #include <math.h> 45 #include <float.h> 46 47 48 #define APPEND(str,ascii) str.AppendAscii(RTL_CONSTASCII_STRINGPARAM(ascii)) 49 50 // define this to draw rectangles for debugging 51 //#define SM_RECT_DEBUG 52 53 54 using ::rtl::OUString; 55 56 57 //////////////////////////////////////// 58 // SmTmpDevice 59 // Allows for font and color changes. The original settings will be restored 60 // in the destructor. 61 // It's main purpose is to allow for the "const" in the 'OutputDevice' 62 // argument in the 'Arrange' functions and restore changes made in the 'Draw' 63 // functions. 64 // Usually a MapMode of 1/100th mm will be used. 65 // 66 67 class SmTmpDevice 68 { 69 OutputDevice &rOutDev; 70 71 // disallow use of copy-constructor and assignment-operator 72 SmTmpDevice(const SmTmpDevice &rTmpDev); 73 SmTmpDevice & operator = (const SmTmpDevice &rTmpDev); 74 75 Color Impl_GetColor( const Color& rColor ); 76 77 public: 78 SmTmpDevice(OutputDevice &rTheDev, sal_Bool bUseMap100th_mm); 79 ~SmTmpDevice() { rOutDev.Pop(); } 80 81 void SetFont(const Font &rNewFont); 82 83 void SetLineColor( const Color& rColor ) { rOutDev.SetLineColor( Impl_GetColor(rColor) ); } 84 void SetFillColor( const Color& rColor ) { rOutDev.SetFillColor( Impl_GetColor(rColor) ); } 85 void SetTextColor( const Color& rColor ) { rOutDev.SetTextColor( Impl_GetColor(rColor) ); } 86 87 operator OutputDevice & () { return rOutDev; } 88 }; 89 90 91 SmTmpDevice::SmTmpDevice(OutputDevice &rTheDev, sal_Bool bUseMap100th_mm) : 92 rOutDev(rTheDev) 93 { 94 rOutDev.Push( PUSH_FONT | PUSH_MAPMODE | 95 PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR ); 96 if (bUseMap100th_mm && MAP_100TH_MM != rOutDev.GetMapMode().GetMapUnit()) 97 { 98 DBG_ERROR( "incorrect MapMode?" ); 99 rOutDev.SetMapMode( MAP_100TH_MM ); //Immer fuer 100% fomatieren 100 } 101 } 102 103 104 Color SmTmpDevice::Impl_GetColor( const Color& rColor ) 105 { 106 ColorData nNewCol = rColor.GetColor(); 107 if (COL_AUTO == nNewCol) 108 { 109 if (OUTDEV_PRINTER == rOutDev.GetOutDevType()) 110 nNewCol = COL_BLACK; 111 else 112 { 113 Color aBgCol( rOutDev.GetBackground().GetColor() ); 114 if (OUTDEV_WINDOW == rOutDev.GetOutDevType()) 115 aBgCol = ((Window &) rOutDev).GetDisplayBackground().GetColor(); 116 117 nNewCol = SM_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor; 118 119 Color aTmpColor( nNewCol ); 120 if (aBgCol.IsDark() && aTmpColor.IsDark()) 121 nNewCol = COL_WHITE; 122 else if (aBgCol.IsBright() && aTmpColor.IsBright()) 123 nNewCol = COL_BLACK; 124 } 125 } 126 return Color( nNewCol ); 127 } 128 129 130 void SmTmpDevice::SetFont(const Font &rNewFont) 131 { 132 rOutDev.SetFont( rNewFont ); 133 rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor() ) ); 134 } 135 136 137 /////////////////////////////////////////////////////////////////////////// 138 139 140 SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken) 141 { 142 eType = eNodeType; 143 eScaleMode = SCALE_NONE; 144 aNodeToken = rNodeToken; 145 nAccIndex = -1; 146 } 147 148 149 SmNode::~SmNode() 150 { 151 } 152 153 154 sal_Bool SmNode::IsVisible() const 155 { 156 return sal_False; 157 } 158 159 160 sal_uInt16 SmNode::GetNumSubNodes() const 161 { 162 return 0; 163 } 164 165 166 SmNode * SmNode::GetSubNode(sal_uInt16 /*nIndex*/) 167 { 168 return NULL; 169 } 170 171 172 SmNode * SmNode::GetLeftMost() 173 // returns leftmost node of current subtree. 174 //! (this assumes the one with index 0 is always the leftmost subnode 175 //! for the current node). 176 { 177 SmNode *pNode = GetNumSubNodes() > 0 ? 178 GetSubNode(0) : NULL; 179 180 return pNode ? pNode->GetLeftMost() : this; 181 } 182 183 184 void SmNode::SetPhantom(sal_Bool bIsPhantomP) 185 { 186 if (! (Flags() & FLG_VISIBLE)) 187 bIsPhantom = bIsPhantomP; 188 189 SmNode *pNode; 190 sal_uInt16 nSize = GetNumSubNodes(); 191 for (sal_uInt16 i = 0; i < nSize; i++) 192 if (NULL != (pNode = GetSubNode(i))) 193 pNode->SetPhantom(bIsPhantom); 194 } 195 196 197 void SmNode::SetColor(const Color& rColor) 198 { 199 if (! (Flags() & FLG_COLOR)) 200 GetFont().SetColor(rColor); 201 202 SmNode *pNode; 203 sal_uInt16 nSize = GetNumSubNodes(); 204 for (sal_uInt16 i = 0; i < nSize; i++) 205 if (NULL != (pNode = GetSubNode(i))) 206 pNode->SetColor(rColor); 207 } 208 209 210 void SmNode::SetAttribut(sal_uInt16 nAttrib) 211 { 212 if ( 213 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) || 214 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC)) 215 ) 216 { 217 nAttributes |= nAttrib; 218 } 219 220 SmNode *pNode; 221 sal_uInt16 nSize = GetNumSubNodes(); 222 for (sal_uInt16 i = 0; i < nSize; i++) 223 if (NULL != (pNode = GetSubNode(i))) 224 pNode->SetAttribut(nAttrib); 225 } 226 227 228 void SmNode::ClearAttribut(sal_uInt16 nAttrib) 229 { 230 if ( 231 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) || 232 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC)) 233 ) 234 { 235 nAttributes &= ~nAttrib; 236 } 237 238 SmNode *pNode; 239 sal_uInt16 nSize = GetNumSubNodes(); 240 for (sal_uInt16 i = 0; i < nSize; i++) 241 if (NULL != (pNode = GetSubNode(i))) 242 pNode->ClearAttribut(nAttrib); 243 } 244 245 246 void SmNode::SetFont(const SmFace &rFace) 247 { 248 if (!(Flags() & FLG_FONT)) 249 GetFont() = rFace; 250 251 SmNode *pNode; 252 sal_uInt16 nSize = GetNumSubNodes(); 253 for (sal_uInt16 i = 0; i < nSize; i++) 254 if (NULL != (pNode = GetSubNode(i))) 255 pNode->SetFont(rFace); 256 } 257 258 259 void SmNode::SetFontSize(const Fraction &rSize, sal_uInt16 nType) 260 //! 'rSize' is in units of pts 261 { 262 Size aFntSize; 263 264 if (!(Flags() & FLG_SIZE)) 265 { 266 Fraction aVal (SmPtsTo100th_mm(rSize.GetNumerator()), 267 rSize.GetDenominator()); 268 //long nHeight = ::rtl::math::round(aVal); 269 long nHeight = (long)aVal; 270 271 aFntSize = GetFont().GetSize(); 272 aFntSize.Width() = 0; 273 switch(nType) 274 { 275 case FNTSIZ_ABSOLUT: 276 aFntSize.Height() = nHeight; 277 break; 278 279 case FNTSIZ_PLUS: 280 aFntSize.Height() += nHeight; 281 break; 282 283 case FNTSIZ_MINUS: 284 aFntSize.Height() -= nHeight; 285 break; 286 287 case FNTSIZ_MULTIPLY: 288 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) * rSize); 289 break; 290 291 case FNTSIZ_DIVIDE: 292 if (rSize != Fraction(0L)) 293 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) / rSize); 294 break; 295 default: 296 break; 297 } 298 299 // check the requested size against maximum value 300 static int __READONLY_DATA nMaxVal = SmPtsTo100th_mm(128); 301 if (aFntSize.Height() > nMaxVal) 302 aFntSize.Height() = nMaxVal; 303 304 GetFont().SetSize(aFntSize); 305 } 306 307 SmNode *pNode; 308 sal_uInt16 nSize = GetNumSubNodes(); 309 for (sal_uInt16 i = 0; i < nSize; i++) 310 if (NULL != (pNode = GetSubNode(i))) 311 pNode->SetFontSize(rSize, nType); 312 } 313 314 315 void SmNode::SetSize(const Fraction &rSize) 316 { 317 GetFont() *= rSize; 318 319 SmNode *pNode; 320 sal_uInt16 nSize = GetNumSubNodes(); 321 for (sal_uInt16 i = 0; i < nSize; i++) 322 if (NULL != (pNode = GetSubNode(i))) 323 pNode->SetSize(rSize); 324 } 325 326 327 void SmNode::SetRectHorAlign(RectHorAlign eHorAlign, sal_Bool bApplyToSubTree ) 328 { 329 if (!(Flags() & FLG_HORALIGN)) 330 eRectHorAlign = eHorAlign; 331 332 if (bApplyToSubTree) 333 { 334 SmNode *pNode; 335 sal_uInt16 nSize = GetNumSubNodes(); 336 for (sal_uInt16 i = 0; i < nSize; i++) 337 if (NULL != (pNode = GetSubNode(i))) 338 pNode->SetRectHorAlign(eHorAlign); 339 } 340 } 341 342 343 void SmNode::PrepareAttributes() 344 { 345 GetFont().SetWeight((Attributes() & ATTR_BOLD) ? WEIGHT_BOLD : WEIGHT_NORMAL); 346 GetFont().SetItalic((Attributes() & ATTR_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE); 347 } 348 349 350 void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 351 { 352 #if OSL_DEBUG_LEVEL > 1 353 bIsDebug = sal_True; 354 #else 355 bIsDebug = sal_False; 356 #endif 357 bIsPhantom = sal_False; 358 nFlags = 0; 359 nAttributes = 0; 360 361 switch (rFormat.GetHorAlign()) 362 { case AlignLeft: eRectHorAlign = RHA_LEFT; break; 363 case AlignCenter: eRectHorAlign = RHA_CENTER; break; 364 case AlignRight: eRectHorAlign = RHA_RIGHT; break; 365 } 366 367 GetFont() = rFormat.GetFont(FNT_MATH); 368 //GetFont().SetCharSet(RTL_TEXTENCODING_SYMBOL); 369 DBG_ASSERT( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE, 370 "unexpected CharSet" ); 371 GetFont().SetWeight(WEIGHT_NORMAL); 372 GetFont().SetItalic(ITALIC_NONE); 373 374 SmNode *pNode; 375 sal_uInt16 nSize = GetNumSubNodes(); 376 for (sal_uInt16 i = 0; i < nSize; i++) 377 if (NULL != (pNode = GetSubNode(i))) 378 pNode->Prepare(rFormat, rDocShell); 379 } 380 381 382 #if OSL_DEBUG_LEVEL > 1 383 void SmNode::ToggleDebug() const 384 // toggle 'bIsDebug' in current subtree 385 { 386 SmNode *pThis = (SmNode *) this; 387 388 pThis->bIsDebug = bIsDebug ? sal_False : sal_True; 389 390 SmNode *pNode; 391 sal_uInt16 nSize = GetNumSubNodes(); 392 for (sal_uInt16 i = 0; i < nSize; i++) 393 if (NULL != (pNode = pThis->GetSubNode(i))) 394 pNode->ToggleDebug(); 395 } 396 #endif 397 398 399 void SmNode::Move(const Point& rPosition) 400 { 401 if (rPosition.X() == 0 && rPosition.Y() == 0) 402 return; 403 404 SmRect::Move(rPosition); 405 406 SmNode *pNode; 407 sal_uInt16 nSize = GetNumSubNodes(); 408 for (sal_uInt16 i = 0; i < nSize; i++) 409 if (NULL != (pNode = GetSubNode(i))) 410 pNode->Move(rPosition); 411 } 412 413 414 void SmNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 415 { 416 SmNode *pNode; 417 sal_uInt16 nSize = GetNumSubNodes(); 418 for (sal_uInt16 i = 0; i < nSize; i++) 419 if (NULL != (pNode = GetSubNode(i))) 420 pNode->Arrange(rDev, rFormat); 421 } 422 423 void SmNode::CreateTextFromNode(String &rText) 424 { 425 SmNode *pNode; 426 sal_uInt16 nSize = GetNumSubNodes(); 427 if (nSize > 1) 428 rText.Append('{'); 429 for (sal_uInt16 i = 0; i < nSize; i++) 430 if (NULL != (pNode = GetSubNode(i))) 431 pNode->CreateTextFromNode(rText); 432 if (nSize > 1) 433 { 434 rText.EraseTrailingChars(); 435 APPEND(rText,"} "); 436 } 437 } 438 439 440 void SmNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong /*nWidth*/) 441 { 442 } 443 444 445 void SmNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong /*nHeight*/) 446 { 447 } 448 449 450 void SmNode::Draw(OutputDevice &rDev, const Point &rPosition) const 451 { 452 if (IsPhantom()) 453 return; 454 455 const SmNode *pNode; 456 sal_uInt16 nSize = GetNumSubNodes(); 457 for (sal_uInt16 i = 0; i < nSize; i++) 458 if (NULL != (pNode = GetSubNode(i))) 459 { Point aOffset (pNode->GetTopLeft() - GetTopLeft()); 460 pNode->Draw(rDev, rPosition + aOffset); 461 } 462 463 #ifdef SM_RECT_DEBUG 464 if (!IsDebug()) 465 return; 466 467 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID; 468 SmRect::Draw(rDev, rPosition, nRFlags); 469 #endif 470 } 471 472 const SmNode * SmNode::FindTokenAt(sal_uInt16 nRow, sal_uInt16 nCol) const 473 // returns (first) ** visible ** (sub)node with the tokens text at 474 // position 'nRow', 'nCol'. 475 //! (there should be exactly one such node if any) 476 { 477 if ( IsVisible() 478 && nRow == GetToken().nRow 479 && nCol >= GetToken().nCol && nCol < GetToken().nCol + GetToken().aText.Len()) 480 return this; 481 else 482 { 483 sal_uInt16 nNumSubNodes = GetNumSubNodes(); 484 for (sal_uInt16 i = 0; i < nNumSubNodes; i++) 485 { const SmNode *pNode = GetSubNode(i); 486 487 if (!pNode) 488 continue; 489 490 const SmNode *pResult = pNode->FindTokenAt(nRow, nCol); 491 if (pResult) 492 return pResult; 493 } 494 } 495 496 return 0; 497 } 498 499 500 const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const 501 { 502 long nDist = LONG_MAX; 503 const SmNode *pResult = 0; 504 505 if (IsVisible()) 506 pResult = this; 507 else 508 { 509 sal_uInt16 nNumSubNodes = GetNumSubNodes(); 510 for (sal_uInt16 i = 0; i < nNumSubNodes; i++) 511 { const SmNode *pNode = GetSubNode(i); 512 513 if (!pNode) 514 continue; 515 516 long nTmp; 517 const SmNode *pFound = pNode->FindRectClosestTo(rPoint); 518 if (pFound && (nTmp = pFound->OrientedDist(rPoint)) < nDist) 519 { nDist = nTmp; 520 pResult = pFound; 521 522 // quit immediately if 'rPoint' is inside the *should not 523 // overlap with other rectangles* part. 524 // This (partly) serves for getting the attributes in eg 525 // "bar overstrike a". 526 // ('nDist < 0' is used as *quick shot* to avoid evaluation of 527 // the following expression, where the result is already determined) 528 if (nDist < 0 && pFound->IsInsideRect(rPoint)) 529 break; 530 } 531 } 532 } 533 534 return pResult; 535 } 536 537 void SmNode::GetAccessibleText( String &/*rText*/ ) const 538 { 539 DBG_ERROR( "SmNode: GetAccessibleText not overloaded" ); 540 } 541 542 const SmNode * SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx) const 543 { 544 const SmNode *pResult = 0; 545 546 sal_Int32 nIdx = GetAccessibleIndex(); 547 String aTxt; 548 if (nIdx >= 0) 549 GetAccessibleText( aTxt ); // get text if used in following 'if' statement 550 551 if (nIdx >= 0 552 && nIdx <= nAccIdx && nAccIdx < nIdx + aTxt.Len()) 553 pResult = this; 554 else 555 { 556 sal_uInt16 nNumSubNodes = GetNumSubNodes(); 557 for (sal_uInt16 i = 0; i < nNumSubNodes; i++) 558 { 559 const SmNode *pNode = GetSubNode(i); 560 if (!pNode) 561 continue; 562 563 pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx); 564 if (pResult) 565 return pResult; 566 } 567 } 568 569 return pResult; 570 } 571 572 573 long SmNode::GetFormulaBaseline() const 574 { 575 DBG_ASSERT( 0, "This dummy implementation should not have been called." ); 576 return 0; 577 } 578 579 /////////////////////////////////////////////////////////////////////////// 580 581 SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) : 582 SmNode( rNode.GetType(), rNode.GetToken() ) 583 { 584 sal_uLong i; 585 for (i = 0; i < aSubNodes.size(); i++) 586 delete aSubNodes[i]; 587 aSubNodes.resize(0); 588 589 sal_uLong nSize = rNode.aSubNodes.size(); 590 aSubNodes.resize( nSize ); 591 for (i = 0; i < nSize; ++i) 592 { 593 SmNode *pNode = rNode.aSubNodes[i]; 594 aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0; 595 } 596 } 597 598 599 SmStructureNode::~SmStructureNode() 600 { 601 SmNode *pNode; 602 603 for (sal_uInt16 i = 0; i < GetNumSubNodes(); i++) 604 if (NULL != (pNode = GetSubNode(i))) 605 delete pNode; 606 } 607 608 609 SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode ) 610 { 611 SmNode::operator = ( rNode ); 612 613 sal_uLong i; 614 for (i = 0; i < aSubNodes.size(); i++) 615 delete aSubNodes[i]; 616 aSubNodes.resize(0); 617 618 sal_uLong nSize = rNode.aSubNodes.size(); 619 aSubNodes.resize( nSize ); 620 for (i = 0; i < nSize; ++i) 621 { 622 SmNode *pNode = rNode.aSubNodes[i]; 623 aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0; 624 } 625 626 return *this; 627 } 628 629 630 void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThird) 631 { 632 size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0)); 633 aSubNodes.resize( nSize ); 634 if (pFirst) 635 aSubNodes[0] = pFirst; 636 if (pSecond) 637 aSubNodes[1] = pSecond; 638 if (pThird) 639 aSubNodes[2] = pThird; 640 } 641 642 643 void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray) 644 { 645 aSubNodes = rNodeArray; 646 } 647 648 649 sal_Bool SmStructureNode::IsVisible() const 650 { 651 return sal_False; 652 } 653 654 655 sal_uInt16 SmStructureNode::GetNumSubNodes() const 656 { 657 return (sal_uInt16) aSubNodes.size(); 658 } 659 660 661 SmNode * SmStructureNode::GetSubNode(sal_uInt16 nIndex) 662 { 663 return aSubNodes[nIndex]; 664 } 665 666 667 void SmStructureNode::GetAccessibleText( String &rText ) const 668 { 669 sal_uInt16 nNodes = GetNumSubNodes(); 670 for (sal_uInt16 i = 0; i < nNodes; ++i) 671 { 672 const SmNode *pNode = ((SmStructureNode *) this)->GetSubNode(i); 673 if (pNode) 674 { 675 if (pNode->IsVisible()) 676 ((SmStructureNode *) pNode)->nAccIndex = rText.Len(); 677 pNode->GetAccessibleText( rText ); 678 // if (rText.Len() && ' ' != rText.GetChar( rText.Len() - 1 )) 679 // rText += String::CreateFromAscii( " " ); 680 } 681 } 682 } 683 684 /////////////////////////////////////////////////////////////////////////// 685 686 687 sal_Bool SmVisibleNode::IsVisible() const 688 { 689 return sal_True; 690 } 691 692 693 sal_uInt16 SmVisibleNode::GetNumSubNodes() const 694 { 695 return 0; 696 } 697 698 699 SmNode * SmVisibleNode::GetSubNode(sal_uInt16 /*nIndex*/) 700 { 701 return NULL; 702 } 703 704 705 /////////////////////////////////////////////////////////////////////////// 706 707 void SmGraphicNode::GetAccessibleText( String &rText ) const 708 { 709 rText += GetToken().aText; 710 } 711 712 /////////////////////////////////////////////////////////////////////////// 713 714 715 void SmExpressionNode::CreateTextFromNode(String &rText) 716 { 717 SmNode *pNode; 718 sal_uInt16 nSize = GetNumSubNodes(); 719 if (nSize > 1) 720 rText.Append('{'); 721 for (sal_uInt16 i = 0; i < nSize; i++) 722 if (NULL != (pNode = GetSubNode(i))) 723 { 724 pNode->CreateTextFromNode(rText); 725 //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice 726 if (pNode->GetType() == NMATH) 727 if ((nSize != 2) || ((rText.GetChar(rText.Len()-1) != '+') && 728 (rText.GetChar(rText.Len()-1) != '-'))) 729 rText.Append(' '); 730 } 731 732 if (nSize > 1) 733 { 734 rText.EraseTrailingChars(); 735 APPEND(rText,"} "); 736 } 737 } 738 739 740 /////////////////////////////////////////////////////////////////////////// 741 742 void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 743 // arranges all subnodes in one column 744 { 745 Point rPosition; 746 747 SmNode *pNode; 748 sal_uInt16 nSize = GetNumSubNodes(); 749 750 // make distance depend on font size 751 long nDist = +(rFormat.GetDistance(DIS_VERTICAL) 752 * GetFont().GetSize().Height()) / 100L; 753 754 if (nSize < 1) 755 return; 756 757 // arrange subnodes and get maximum width of them 758 long nMaxWidth = 0, 759 nTmp; 760 sal_uInt16 i; 761 for (i = 0; i < nSize; i++) 762 if (NULL != (pNode = GetSubNode(i))) 763 { pNode->Arrange(rDev, rFormat); 764 if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth) 765 nMaxWidth = nTmp; 766 } 767 768 Point aPos; 769 SmRect::operator = (SmRect(nMaxWidth, 1)); 770 for (i = 0; i < nSize; i++) 771 { if (NULL != (pNode = GetSubNode(i))) 772 { const SmRect &rNodeRect = pNode->GetRect(); 773 const SmNode *pCoNode = pNode->GetLeftMost(); 774 //SmTokenType eType = pCoNode->GetToken().eType; 775 RectHorAlign eHorAlign = pCoNode->GetRectHorAlign(); 776 777 aPos = rNodeRect.AlignTo(*this, RP_BOTTOM, 778 eHorAlign, RVA_BASELINE); 779 if (i) 780 aPos.Y() += nDist; 781 pNode->MoveTo(aPos); 782 ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG); 783 } 784 } 785 // --> 4.7.2010 #i972# 786 if (HasBaseline()) 787 nFormulaBaseline = GetBaseline(); 788 else 789 { 790 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 791 aTmpDev.SetFont(GetFont()); 792 793 SmRect aRect = (SmRect(aTmpDev, &rFormat, C2S("a"), 794 GetFont().GetBorderWidth())); 795 nFormulaBaseline = GetAlignM(); 796 // move from middle position by constant - distance 797 // between middle and baseline for single letter 798 nFormulaBaseline += aRect.GetBaseline() - aRect.GetAlignM(); 799 } 800 // <-- 801 } 802 803 804 SmNode * SmTableNode::GetLeftMost() 805 { 806 return this; 807 } 808 809 810 long SmTableNode::GetFormulaBaseline() const 811 { 812 return nFormulaBaseline; 813 } 814 815 816 /**************************************************************************/ 817 818 819 void SmLineNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 820 { 821 SmNode::Prepare(rFormat, rDocShell); 822 823 //! wir verwenden hier den 'FNT_VARIABLE' Font, da er vom Ascent und Descent 824 //! ia besser zum Rest der Formel passt als der 'FNT_MATH' Font. 825 GetFont() = rFormat.GetFont(FNT_VARIABLE); 826 Flags() |= FLG_FONT; 827 } 828 829 830 /**************************************************************************/ 831 832 833 void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 834 // arranges all subnodes in one row with some extra space between 835 { 836 SmNode *pNode; 837 sal_uInt16 nSize = GetNumSubNodes(); 838 sal_uInt16 i; 839 for (i = 0; i < nSize; i++) 840 if (NULL != (pNode = GetSubNode(i))) 841 pNode->Arrange(rDev, rFormat); 842 843 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 844 aTmpDev.SetFont(GetFont()); 845 846 if (nSize < 1) 847 { 848 // provide an empty rectangle with alignment parameters for the "current" 849 // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the 850 // same sub-/supscript positions.) 851 //! be sure to use a character that has explicitly defined HiAttribut 852 //! line in rect.cxx such as 'a' in order to make 'vec a' look same to 853 //! 'vec {a}'. 854 SmRect::operator = (SmRect(aTmpDev, &rFormat, C2S("a"), 855 GetFont().GetBorderWidth())); 856 // make sure that the rectangle occupies (almost) no space 857 SetWidth(1); 858 SetItalicSpaces(0, 0); 859 return; 860 } 861 862 // make distance depend on font size 863 long nDist = (rFormat.GetDistance(DIS_HORIZONTAL) * GetFont().GetSize().Height()) / 100L; 864 if (!IsUseExtraSpaces()) 865 nDist = 0; 866 867 Point aPos; 868 // copy the first node into LineNode and extend by the others 869 if (NULL != (pNode = GetSubNode(0))) 870 SmRect::operator = (pNode->GetRect()); 871 872 for (i = 1; i < nSize; i++) 873 if (NULL != (pNode = GetSubNode(i))) 874 { 875 aPos = pNode->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE); 876 877 // add horizontal space to the left for each but the first sub node 878 aPos.X() += nDist; 879 880 pNode->MoveTo(aPos); 881 ExtendBy( *pNode, RCP_XOR ); 882 } 883 } 884 885 886 /**************************************************************************/ 887 888 889 void SmExpressionNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 890 // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode 891 { 892 SmLineNode::Arrange(rDev, rFormat); 893 894 // copy alignment of leftmost subnode if any 895 SmNode *pNode = GetLeftMost(); 896 if (pNode) 897 SetRectHorAlign(pNode->GetRectHorAlign(), sal_False); 898 } 899 900 901 /**************************************************************************/ 902 903 904 void SmUnHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 905 { 906 sal_Bool bIsPostfix = GetToken().eType == TFACT; 907 908 SmNode *pOper = GetSubNode(bIsPostfix ? 1 : 0), 909 *pBody = GetSubNode(bIsPostfix ? 0 : 1); 910 DBG_ASSERT(pOper, "Sm: NULL pointer"); 911 DBG_ASSERT(pBody, "Sm: NULL pointer"); 912 913 pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100)); 914 pOper->Arrange(rDev, rFormat); 915 pBody->Arrange(rDev, rFormat); 916 917 Point aPos = pOper->AlignTo(*pBody, bIsPostfix ? RP_RIGHT : RP_LEFT, 918 RHA_CENTER, RVA_BASELINE); 919 // add a bit space between operator and argument 920 // (worst case -{1 over 2} where - and over have almost no space inbetween) 921 long nDelta = pOper->GetFont().GetSize().Height() / 20; 922 if (bIsPostfix) 923 aPos.X() += nDelta; 924 else 925 aPos.X() -= nDelta; 926 pOper->MoveTo(aPos); 927 928 SmRect::operator = (*pBody); 929 long nOldBot = GetBottom(); 930 931 ExtendBy(*pOper, RCP_XOR); 932 933 // workaround for Bug 50865: "a^2 a^+2" have different baselines 934 // for exponents (if size of exponent is large enough) 935 SetBottom(nOldBot); 936 } 937 938 939 /**************************************************************************/ 940 941 942 void SmRootNode::GetHeightVerOffset(const SmRect &rRect, 943 long &rHeight, long &rVerOffset) const 944 // calculate height and vertical offset of root sign suitable for 'rRect' 945 { 946 rVerOffset = (rRect.GetBottom() - rRect.GetAlignB()) / 2; 947 rHeight = rRect.GetHeight() - rVerOffset; 948 949 DBG_ASSERT(rHeight >= 0, "Sm : Ooops..."); 950 DBG_ASSERT(rVerOffset >= 0, "Sm : Ooops..."); 951 } 952 953 954 Point SmRootNode::GetExtraPos(const SmRect &rRootSymbol, 955 const SmRect &rExtra) const 956 { 957 const Size &rSymSize = rRootSymbol.GetSize(); 958 959 Point aPos = rRootSymbol.GetTopLeft() 960 + Point((rSymSize.Width() * 70) / 100, 961 (rSymSize.Height() * 52) / 100); 962 963 // from this calculate topleft edge of 'rExtra' 964 aPos.X() -= rExtra.GetWidth() + rExtra.GetItalicRightSpace(); 965 aPos.Y() -= rExtra.GetHeight(); 966 // if there's enough space move a bit less to the right 967 // examples: "nroot i a", "nroot j a" 968 // (it looks better if we don't use italic-spaces here) 969 long nX = rRootSymbol.GetLeft() + (rSymSize.Width() * 30) / 100; 970 if (aPos.X() > nX) 971 aPos.X() = nX; 972 973 return aPos; 974 } 975 976 977 void SmRootNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 978 { 979 //! pExtra needs to have the smaller index than pRootSym in order to 980 //! not to get the root symbol but the pExtra when clicking on it in the 981 //! GraphicWindow. (That is because of the simplicity of the algorithm 982 //! that finds the node corresponding to a mouseclick in the window.) 983 SmNode *pExtra = GetSubNode(0), 984 *pRootSym = GetSubNode(1), 985 *pBody = GetSubNode(2); 986 DBG_ASSERT(pRootSym, "Sm: NULL pointer"); 987 DBG_ASSERT(pBody, "Sm: NULL pointer"); 988 989 pBody->Arrange(rDev, rFormat); 990 991 long nHeight, 992 nVerOffset; 993 GetHeightVerOffset(*pBody, nHeight, nVerOffset); 994 nHeight += rFormat.GetDistance(DIS_ROOT) 995 * GetFont().GetSize().Height() / 100L; 996 997 // font specialist advised to change the width first 998 pRootSym->AdaptToY(rDev, nHeight); 999 pRootSym->AdaptToX(rDev, pBody->GetItalicWidth()); 1000 1001 pRootSym->Arrange(rDev, rFormat); 1002 1003 Point aPos = pRootSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE); 1004 //! overrride calulated vertical position 1005 aPos.Y() = pRootSym->GetTop() + pBody->GetBottom() - pRootSym->GetBottom(); 1006 aPos.Y() -= nVerOffset; 1007 pRootSym->MoveTo(aPos); 1008 1009 if (pExtra) 1010 { pExtra->SetSize(Fraction(rFormat.GetRelSize(SIZ_INDEX), 100)); 1011 pExtra->Arrange(rDev, rFormat); 1012 1013 aPos = GetExtraPos(*pRootSym, *pExtra); 1014 pExtra->MoveTo(aPos); 1015 } 1016 1017 SmRect::operator = (*pBody); 1018 ExtendBy(*pRootSym, RCP_THIS); 1019 if (pExtra) 1020 ExtendBy(*pExtra, RCP_THIS, (sal_Bool) sal_True); 1021 } 1022 1023 1024 void SmRootNode::CreateTextFromNode(String &rText) 1025 { 1026 SmNode *pExtra = GetSubNode(0); 1027 if (pExtra) 1028 { 1029 APPEND(rText,"nroot "); 1030 pExtra->CreateTextFromNode(rText); 1031 } 1032 else 1033 APPEND(rText,"sqrt "); 1034 GetSubNode(2)->CreateTextFromNode(rText); 1035 } 1036 1037 1038 /**************************************************************************/ 1039 1040 1041 void SmBinHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1042 { 1043 SmNode *pLeft = GetSubNode(0), 1044 *pOper = GetSubNode(1), 1045 *pRight = GetSubNode(2); 1046 DBG_ASSERT(pLeft != NULL, "Sm: NULL pointer"); 1047 DBG_ASSERT(pOper != NULL, "Sm: NULL pointer"); 1048 DBG_ASSERT(pRight != NULL, "Sm: NULL pointer"); 1049 1050 pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100)); 1051 1052 pLeft ->Arrange(rDev, rFormat); 1053 pOper ->Arrange(rDev, rFormat); 1054 pRight->Arrange(rDev, rFormat); 1055 1056 const SmRect &rOpRect = pOper->GetRect(); 1057 1058 long nDist = (rOpRect.GetWidth() * 1059 rFormat.GetDistance(DIS_HORIZONTAL)) / 100L; 1060 1061 SmRect::operator = (*pLeft); 1062 1063 Point aPos; 1064 aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE); 1065 aPos.X() += nDist; 1066 pOper->MoveTo(aPos); 1067 ExtendBy(*pOper, RCP_XOR); 1068 1069 aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE); 1070 aPos.X() += nDist; 1071 1072 pRight->MoveTo(aPos); 1073 ExtendBy(*pRight, RCP_XOR); 1074 } 1075 1076 1077 /**************************************************************************/ 1078 1079 1080 void SmBinVerNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1081 { 1082 SmNode *pNum = GetSubNode(0), 1083 *pLine = GetSubNode(1), 1084 *pDenom = GetSubNode(2); 1085 DBG_ASSERT(pNum, "Sm : NULL pointer"); 1086 DBG_ASSERT(pLine, "Sm : NULL pointer"); 1087 DBG_ASSERT(pDenom, "Sm : NULL pointer"); 1088 1089 sal_Bool bIsTextmode = rFormat.IsTextmode(); 1090 if (bIsTextmode) 1091 { 1092 Fraction aFraction(rFormat.GetRelSize(SIZ_INDEX), 100); 1093 pNum ->SetSize(aFraction); 1094 pLine ->SetSize(aFraction); 1095 pDenom->SetSize(aFraction); 1096 } 1097 1098 pNum ->Arrange(rDev, rFormat); 1099 pDenom->Arrange(rDev, rFormat); 1100 1101 long nFontHeight = GetFont().GetSize().Height(), 1102 nExtLen = nFontHeight * rFormat.GetDistance(DIS_FRACTION) / 100L, 1103 nThick = nFontHeight * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L, 1104 nWidth = Max(pNum->GetItalicWidth(), pDenom->GetItalicWidth()), 1105 nNumDist = bIsTextmode ? 0 : 1106 nFontHeight * rFormat.GetDistance(DIS_NUMERATOR) / 100L, 1107 nDenomDist = bIsTextmode ? 0 : 1108 nFontHeight * rFormat.GetDistance(DIS_DENOMINATOR) / 100L; 1109 1110 // font specialist advised to change the width first 1111 pLine->AdaptToY(rDev, nThick); 1112 pLine->AdaptToX(rDev, nWidth + 2 * nExtLen); 1113 pLine->Arrange(rDev, rFormat); 1114 1115 // get horizontal alignment for numerator 1116 const SmNode *pLM = pNum->GetLeftMost(); 1117 RectHorAlign eHorAlign = pLM->GetRectHorAlign(); 1118 1119 // move numerator to its position 1120 Point aPos = pNum->AlignTo(*pLine, RP_TOP, eHorAlign, RVA_BASELINE); 1121 aPos.Y() -= nNumDist; 1122 pNum->MoveTo(aPos); 1123 1124 // get horizontal alignment for denominator 1125 pLM = pDenom->GetLeftMost(); 1126 eHorAlign = pLM->GetRectHorAlign(); 1127 1128 // move denominator to its position 1129 aPos = pDenom->AlignTo(*pLine, RP_BOTTOM, eHorAlign, RVA_BASELINE); 1130 aPos.Y() += nDenomDist; 1131 pDenom->MoveTo(aPos); 1132 1133 SmRect::operator = (*pNum); 1134 ExtendBy(*pDenom, RCP_NONE).ExtendBy(*pLine, RCP_NONE, pLine->GetCenterY()); 1135 } 1136 1137 void SmBinVerNode::CreateTextFromNode(String &rText) 1138 { 1139 SmNode *pNum = GetSubNode(0), 1140 // *pLine = GetSubNode(1), 1141 *pDenom = GetSubNode(2); 1142 pNum->CreateTextFromNode(rText); 1143 APPEND(rText,"over "); 1144 pDenom->CreateTextFromNode(rText); 1145 } 1146 1147 1148 SmNode * SmBinVerNode::GetLeftMost() 1149 { 1150 return this; 1151 } 1152 1153 1154 /**************************************************************************/ 1155 1156 1157 double Det(const Point &rHeading1, const Point &rHeading2) 1158 // gibt den Wert der durch die beiden Punkte gebildeten Determinante 1159 // zurueck 1160 { 1161 return rHeading1.X() * rHeading2.Y() - rHeading1.Y() * rHeading2.X(); 1162 } 1163 1164 1165 sal_Bool IsPointInLine(const Point &rPoint1, 1166 const Point &rPoint2, const Point &rHeading2) 1167 // ergibt sal_True genau dann, wenn der Punkt 'rPoint1' zu der Gerade gehoert die 1168 // durch den Punkt 'rPoint2' geht und den Richtungsvektor 'rHeading2' hat 1169 { 1170 DBG_ASSERT(rHeading2 != Point(), "Sm : 0 vector"); 1171 1172 sal_Bool bRes = sal_False; 1173 const double eps = 5.0 * DBL_EPSILON; 1174 1175 double fLambda; 1176 if (labs(rHeading2.X()) > labs(rHeading2.Y())) 1177 { 1178 fLambda = (rPoint1.X() - rPoint2.X()) / (double) rHeading2.X(); 1179 bRes = fabs(rPoint1.Y() - (rPoint2.Y() + fLambda * rHeading2.Y())) < eps; 1180 } 1181 else 1182 { 1183 fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y(); 1184 bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps; 1185 } 1186 1187 return bRes; 1188 } 1189 1190 1191 sal_uInt16 GetLineIntersectionPoint(Point &rResult, 1192 const Point& rPoint1, const Point &rHeading1, 1193 const Point& rPoint2, const Point &rHeading2) 1194 { 1195 DBG_ASSERT(rHeading1 != Point(), "Sm : 0 vector"); 1196 DBG_ASSERT(rHeading2 != Point(), "Sm : 0 vector"); 1197 1198 sal_uInt16 nRes = 1; 1199 const double eps = 5.0 * DBL_EPSILON; 1200 1201 // sind die Richtumgsvektoren linear abhaengig ? 1202 double fDet = Det(rHeading1, rHeading2); 1203 if (fabs(fDet) < eps) 1204 { 1205 nRes = IsPointInLine(rPoint1, rPoint2, rHeading2) ? USHRT_MAX : 0; 1206 rResult = nRes ? rPoint1 : Point(); 1207 } 1208 else 1209 { 1210 // hier achten wir nicht auf Rechengenauigkeit 1211 // (das wuerde aufwendiger und lohnt sich hier kaum) 1212 double fLambda = ( (rPoint1.Y() - rPoint2.Y()) * rHeading2.X() 1213 - (rPoint1.X() - rPoint2.X()) * rHeading2.Y()) 1214 / fDet; 1215 rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()), 1216 rPoint1.Y() + (long) (fLambda * rHeading1.Y())); 1217 } 1218 1219 return nRes; 1220 } 1221 1222 1223 1224 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken) 1225 : SmStructureNode(NBINDIAGONAL, rNodeToken) 1226 { 1227 bAscending = sal_False; 1228 SetNumSubNodes(3); 1229 } 1230 1231 1232 void SmBinDiagonalNode::GetOperPosSize(Point &rPos, Size &rSize, 1233 const Point &rDiagPoint, double fAngleDeg) const 1234 // gibt die Position und Groesse fuer den Diagonalstrich zurueck. 1235 // Vor.: das SmRect des Nodes gibt die Begrenzung vor(!), muss also selbst 1236 // bereits bekannt sein. 1237 1238 { 1239 const double fPi = 3.1415926535897932384626433; 1240 double fAngleRad = fAngleDeg / 180.0 * fPi; 1241 long nRectLeft = GetItalicLeft(), 1242 nRectRight = GetItalicRight(), 1243 nRectTop = GetTop(), 1244 nRectBottom = GetBottom(); 1245 Point aRightHdg (100, 0), 1246 aDownHdg (0, 100), 1247 aDiagHdg ( (long)(100.0 * cos(fAngleRad)), 1248 (long)(-100.0 * sin(fAngleRad)) ); 1249 1250 long nLeft, nRight, nTop, nBottom; // Raender des Rechtecks fuer die 1251 // Diagonale 1252 Point aPoint; 1253 if (IsAscending()) 1254 { 1255 // 1256 // obere rechte Ecke bestimmen 1257 // 1258 GetLineIntersectionPoint(aPoint, 1259 Point(nRectLeft, nRectTop), aRightHdg, 1260 rDiagPoint, aDiagHdg); 1261 // 1262 // gibt es einen Schnittpunkt mit dem oberen Rand ? 1263 if (aPoint.X() <= nRectRight) 1264 { 1265 nRight = aPoint.X(); 1266 nTop = nRectTop; 1267 } 1268 else 1269 { 1270 // es muss einen Schnittpunkt mit dem rechten Rand geben! 1271 GetLineIntersectionPoint(aPoint, 1272 Point(nRectRight, nRectTop), aDownHdg, 1273 rDiagPoint, aDiagHdg); 1274 1275 nRight = nRectRight; 1276 nTop = aPoint.Y(); 1277 } 1278 1279 // 1280 // untere linke Ecke bestimmen 1281 // 1282 GetLineIntersectionPoint(aPoint, 1283 Point(nRectLeft, nRectBottom), aRightHdg, 1284 rDiagPoint, aDiagHdg); 1285 // 1286 // gibt es einen Schnittpunkt mit dem unteren Rand ? 1287 if (aPoint.X() >= nRectLeft) 1288 { 1289 nLeft = aPoint.X(); 1290 nBottom = nRectBottom; 1291 } 1292 else 1293 { 1294 // es muss einen Schnittpunkt mit dem linken Rand geben! 1295 GetLineIntersectionPoint(aPoint, 1296 Point(nRectLeft, nRectTop), aDownHdg, 1297 rDiagPoint, aDiagHdg); 1298 1299 nLeft = nRectLeft; 1300 nBottom = aPoint.Y(); 1301 } 1302 } 1303 else 1304 { 1305 // 1306 // obere linke Ecke bestimmen 1307 // 1308 GetLineIntersectionPoint(aPoint, 1309 Point(nRectLeft, nRectTop), aRightHdg, 1310 rDiagPoint, aDiagHdg); 1311 // 1312 // gibt es einen Schnittpunkt mit dem oberen Rand ? 1313 if (aPoint.X() >= nRectLeft) 1314 { 1315 nLeft = aPoint.X(); 1316 nTop = nRectTop; 1317 } 1318 else 1319 { 1320 // es muss einen Schnittpunkt mit dem linken Rand geben! 1321 GetLineIntersectionPoint(aPoint, 1322 Point(nRectLeft, nRectTop), aDownHdg, 1323 rDiagPoint, aDiagHdg); 1324 1325 nLeft = nRectLeft; 1326 nTop = aPoint.Y(); 1327 } 1328 1329 // 1330 // untere rechte Ecke bestimmen 1331 // 1332 GetLineIntersectionPoint(aPoint, 1333 Point(nRectLeft, nRectBottom), aRightHdg, 1334 rDiagPoint, aDiagHdg); 1335 // 1336 // gibt es einen Schnittpunkt mit dem unteren Rand ? 1337 if (aPoint.X() <= nRectRight) 1338 { 1339 nRight = aPoint.X(); 1340 nBottom = nRectBottom; 1341 } 1342 else 1343 { 1344 // es muss einen Schnittpunkt mit dem rechten Rand geben! 1345 GetLineIntersectionPoint(aPoint, 1346 Point(nRectRight, nRectTop), aDownHdg, 1347 rDiagPoint, aDiagHdg); 1348 1349 nRight = nRectRight; 1350 nBottom = aPoint.Y(); 1351 } 1352 } 1353 1354 rSize = Size(nRight - nLeft + 1, nBottom - nTop + 1); 1355 rPos.X() = nLeft; 1356 rPos.Y() = nTop; 1357 } 1358 1359 1360 void SmBinDiagonalNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1361 { 1362 //! die beiden Argumente muessen in den Subnodes vor dem Operator kommen, 1363 //! damit das anklicken im GraphicWindow den FormulaCursor richtig setzt 1364 //! (vgl SmRootNode) 1365 SmNode *pLeft = GetSubNode(0), 1366 *pRight = GetSubNode(1); 1367 DBG_ASSERT(pLeft, "Sm : NULL pointer"); 1368 DBG_ASSERT(pRight, "Sm : NULL pointer"); 1369 1370 DBG_ASSERT(GetSubNode(2)->GetType() == NPOLYLINE, "Sm : falscher Nodetyp"); 1371 SmPolyLineNode *pOper = (SmPolyLineNode *) GetSubNode(2); 1372 DBG_ASSERT(pOper, "Sm : NULL pointer"); 1373 1374 //! some routines being called extract some info from the OutputDevice's 1375 //! font (eg the space to be used for borders OR the font name(!!)). 1376 //! Thus the font should reflect the needs and has to be set! 1377 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 1378 aTmpDev.SetFont(GetFont()); 1379 1380 pLeft->Arrange(aTmpDev, rFormat); 1381 pRight->Arrange(aTmpDev, rFormat); 1382 1383 // implizit die Weite (incl Rand) des Diagonalstrichs ermitteln 1384 pOper->Arrange(aTmpDev, rFormat); 1385 1386 long nDelta = pOper->GetWidth() * 8 / 10; 1387 1388 // TopLeft Position vom rechten Argument ermitteln 1389 Point aPos; 1390 aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace(); 1391 if (IsAscending()) 1392 aPos.Y() = pLeft->GetBottom() + nDelta; 1393 else 1394 aPos.Y() = pLeft->GetTop() - nDelta - pRight->GetHeight(); 1395 1396 pRight->MoveTo(aPos); 1397 1398 // neue Baseline bestimmen 1399 long nTmpBaseline = IsAscending() ? (pLeft->GetBottom() + pRight->GetTop()) / 2 1400 : (pLeft->GetTop() + pRight->GetBottom()) / 2; 1401 Point aLogCenter ((pLeft->GetItalicRight() + pRight->GetItalicLeft()) / 2, 1402 nTmpBaseline); 1403 1404 SmRect::operator = (*pLeft); 1405 ExtendBy(*pRight, RCP_NONE); 1406 1407 1408 // Position und Groesse des Diagonalstrich ermitteln 1409 Size aTmpSize; 1410 GetOperPosSize(aPos, aTmpSize, aLogCenter, IsAscending() ? 60.0 : -60.0); 1411 1412 // font specialist advised to change the width first 1413 pOper->AdaptToY(aTmpDev, aTmpSize.Height()); 1414 pOper->AdaptToX(aTmpDev, aTmpSize.Width()); 1415 // und diese wirksam machen 1416 pOper->Arrange(aTmpDev, rFormat); 1417 1418 pOper->MoveTo(aPos); 1419 1420 ExtendBy(*pOper, RCP_NONE, nTmpBaseline); 1421 } 1422 1423 1424 /**************************************************************************/ 1425 1426 1427 void SmSubSupNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1428 { 1429 DBG_ASSERT(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES, 1430 "Sm: falsche Anzahl von subnodes"); 1431 1432 SmNode *pBody = GetBody(); 1433 DBG_ASSERT(pBody, "Sm: NULL pointer"); 1434 1435 long nOrigHeight = pBody->GetFont().GetSize().Height(); 1436 1437 pBody->Arrange(rDev, rFormat); 1438 1439 const SmRect &rBodyRect = pBody->GetRect(); 1440 SmRect::operator = (rBodyRect); 1441 1442 // line that separates sub- and supscript rectangles 1443 long nDelimLine = SmFromTo(GetAlignB(), GetAlignT(), 0.4); 1444 1445 Point aPos; 1446 long nDelta, nDist; 1447 1448 // iterate over all possible sub-/supscripts 1449 SmRect aTmpRect (rBodyRect); 1450 for (int i = 0; i < SUBSUP_NUM_ENTRIES; i++) 1451 { SmSubSup eSubSup = (SmSubSup) i; // cast 1452 SmNode *pSubSup = GetSubSup(eSubSup); 1453 1454 if (!pSubSup) 1455 continue; 1456 1457 // switch position of limits if we are in textmode 1458 if (rFormat.IsTextmode() && (GetToken().nGroup & TGLIMIT)) 1459 switch (eSubSup) 1460 { case CSUB: eSubSup = RSUB; break; 1461 case CSUP: eSubSup = RSUP; break; 1462 default: 1463 break; 1464 } 1465 1466 // prevent sub-/supscripts from diminishing in size 1467 // (as would be in "a_{1_{2_{3_4}}}") 1468 if (GetFont().GetSize().Height() > rFormat.GetBaseSize().Height() / 3) 1469 { 1470 sal_uInt16 nIndex = (eSubSup == CSUB || eSubSup == CSUP) ? 1471 SIZ_LIMITS : SIZ_INDEX; 1472 Fraction aFraction ( rFormat.GetRelSize(nIndex), 100 ); 1473 pSubSup->SetSize(aFraction); 1474 } 1475 1476 pSubSup->Arrange(rDev, rFormat); 1477 1478 sal_Bool bIsTextmode = rFormat.IsTextmode(); 1479 nDist = 0; 1480 1481 //! be sure that CSUB, CSUP are handled before the other cases! 1482 switch (eSubSup) 1483 { case RSUB : 1484 case LSUB : 1485 if (!bIsTextmode) 1486 nDist = nOrigHeight 1487 * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L; 1488 aPos = pSubSup->GetRect().AlignTo(aTmpRect, 1489 eSubSup == LSUB ? RP_LEFT : RP_RIGHT, 1490 RHA_CENTER, RVA_BOTTOM); 1491 aPos.Y() += nDist; 1492 nDelta = nDelimLine - aPos.Y(); 1493 if (nDelta > 0) 1494 aPos.Y() += nDelta; 1495 break; 1496 case RSUP : 1497 case LSUP : 1498 if (!bIsTextmode) 1499 nDist = nOrigHeight 1500 * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L; 1501 aPos = pSubSup->GetRect().AlignTo(aTmpRect, 1502 eSubSup == LSUP ? RP_LEFT : RP_RIGHT, 1503 RHA_CENTER, RVA_TOP); 1504 aPos.Y() -= nDist; 1505 nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine; 1506 if (nDelta > 0) 1507 aPos.Y() -= nDelta; 1508 break; 1509 case CSUB : 1510 if (!bIsTextmode) 1511 nDist = nOrigHeight 1512 * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L; 1513 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM, 1514 RHA_CENTER, RVA_BASELINE); 1515 aPos.Y() += nDist; 1516 break; 1517 case CSUP : 1518 if (!bIsTextmode) 1519 nDist = nOrigHeight 1520 * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L; 1521 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP, 1522 RHA_CENTER, RVA_BASELINE); 1523 aPos.Y() -= nDist; 1524 break; 1525 default : 1526 DBG_ASSERT(sal_False, "Sm: unbekannter Fall"); 1527 break; 1528 } 1529 1530 pSubSup->MoveTo(aPos); 1531 ExtendBy(*pSubSup, RCP_THIS, (sal_Bool) sal_True); 1532 1533 // update rectangle to which RSUB, RSUP, LSUB, LSUP 1534 // will be aligned to 1535 if (eSubSup == CSUB || eSubSup == CSUP) 1536 aTmpRect = *this; 1537 } 1538 } 1539 1540 void SmSubSupNode::CreateTextFromNode(String &rText) 1541 { 1542 SmNode *pNode; 1543 GetSubNode(0)->CreateTextFromNode(rText); 1544 1545 if (NULL != (pNode = GetSubNode(LSUB+1))) 1546 { 1547 APPEND(rText,"lsub "); 1548 pNode->CreateTextFromNode(rText); 1549 } 1550 if (NULL != (pNode = GetSubNode(LSUP+1))) 1551 { 1552 APPEND(rText,"lsup "); 1553 pNode->CreateTextFromNode(rText); 1554 } 1555 if (NULL != (pNode = GetSubNode(CSUB+1))) 1556 { 1557 APPEND(rText,"csub "); 1558 pNode->CreateTextFromNode(rText); 1559 } 1560 if (NULL != (pNode = GetSubNode(CSUP+1))) 1561 { 1562 APPEND(rText,"csup "); 1563 pNode->CreateTextFromNode(rText); 1564 } 1565 if (NULL != (pNode = GetSubNode(RSUB+1))) 1566 { 1567 rText.EraseTrailingChars(); 1568 rText.Append('_'); 1569 pNode->CreateTextFromNode(rText); 1570 } 1571 if (NULL != (pNode = GetSubNode(RSUP+1))) 1572 { 1573 rText.EraseTrailingChars(); 1574 rText.Append('^'); 1575 pNode->CreateTextFromNode(rText); 1576 } 1577 } 1578 1579 1580 /**************************************************************************/ 1581 1582 void SmBraceNode::CreateTextFromNode(String &rText) 1583 { 1584 if (GetScaleMode() == SCALE_HEIGHT) 1585 APPEND(rText,"left "); 1586 { 1587 String aStr; 1588 GetSubNode(0)->CreateTextFromNode(aStr); 1589 aStr.EraseLeadingAndTrailingChars(); 1590 aStr.EraseLeadingChars('\\'); 1591 if (aStr.Len()) 1592 { 1593 if (aStr.EqualsAscii("divides")) 1594 APPEND(rText,"lline"); 1595 else if (aStr.EqualsAscii("parallel")) 1596 APPEND(rText,"ldline"); 1597 else if (aStr.EqualsAscii("<")) 1598 APPEND(rText,"langle"); 1599 else 1600 rText.Append(aStr); 1601 rText.Append(' '); 1602 } 1603 else 1604 APPEND(rText,"none "); 1605 } 1606 GetSubNode(1)->CreateTextFromNode(rText); 1607 if (GetScaleMode() == SCALE_HEIGHT) 1608 APPEND(rText,"right "); 1609 { 1610 String aStr; 1611 GetSubNode(2)->CreateTextFromNode(aStr); 1612 aStr.EraseLeadingAndTrailingChars(); 1613 aStr.EraseLeadingChars('\\'); 1614 if (aStr.Len()) 1615 { 1616 if (aStr.EqualsAscii("divides")) 1617 APPEND(rText,"rline"); 1618 else if (aStr.EqualsAscii("parallel")) 1619 APPEND(rText,"rdline"); 1620 else if (aStr.EqualsAscii(">")) 1621 APPEND(rText,"rangle"); 1622 else 1623 rText.Append(aStr); 1624 rText.Append(' '); 1625 } 1626 else 1627 APPEND(rText,"none "); 1628 } 1629 rText.Append(' '); 1630 1631 } 1632 1633 void SmBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1634 { 1635 SmNode *pLeft = GetSubNode(0), 1636 *pBody = GetSubNode(1), 1637 *pRight = GetSubNode(2); 1638 DBG_ASSERT(pLeft, "Sm: NULL pointer"); 1639 DBG_ASSERT(pBody, "Sm: NULL pointer"); 1640 DBG_ASSERT(pRight, "Sm: NULL pointer"); 1641 1642 pBody->Arrange(rDev, rFormat); 1643 1644 sal_Bool bIsScaleNormal = rFormat.IsScaleNormalBrackets(), 1645 bScale = pBody->GetHeight() > 0 && 1646 (GetScaleMode() == SCALE_HEIGHT || bIsScaleNormal), 1647 bIsABS = GetToken().eType == TABS; 1648 1649 long nFaceHeight = GetFont().GetSize().Height(); 1650 1651 // Uebergroesse in % ermitteln 1652 sal_uInt16 nPerc = 0; 1653 if (!bIsABS && bScale) 1654 { // im Fall von Klammern mit Uebergroesse... 1655 sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ? 1656 DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE; 1657 nPerc = rFormat.GetDistance(nIndex); 1658 } 1659 1660 // ermitteln der Hoehe fuer die Klammern 1661 long nBraceHeight; 1662 if (bScale) 1663 { 1664 nBraceHeight = pBody->GetType() == NBRACEBODY ? 1665 ((SmBracebodyNode *) pBody)->GetBodyHeight() 1666 : pBody->GetHeight(); 1667 nBraceHeight += 2 * (nBraceHeight * nPerc / 100L); 1668 } 1669 else 1670 nBraceHeight = nFaceHeight; 1671 1672 // Abstand zum Argument 1673 nPerc = bIsABS ? 0 : rFormat.GetDistance(DIS_BRACKETSPACE); 1674 long nDist = nFaceHeight * nPerc / 100L; 1675 1676 // sofern erwuenscht skalieren der Klammern auf die gewuenschte Groesse 1677 if (bScale) 1678 { 1679 Size aTmpSize (pLeft->GetFont().GetSize()); 1680 DBG_ASSERT(pRight->GetFont().GetSize() == aTmpSize, 1681 "Sm : unterschiedliche Fontgroessen"); 1682 aTmpSize.Width() = Min((long) nBraceHeight * 60L / 100L, 1683 rFormat.GetBaseSize().Height() * 3L / 2L); 1684 // correction factor since change from StarMath to OpenSymbol font 1685 // because of the different font width in the FontMetric 1686 aTmpSize.Width() *= 182; 1687 aTmpSize.Width() /= 267; 1688 1689 xub_Unicode cChar = pLeft->GetToken().cMathChar; 1690 if (cChar != MS_LINE && cChar != MS_DLINE) 1691 pLeft ->GetFont().SetSize(aTmpSize); 1692 1693 cChar = pRight->GetToken().cMathChar; 1694 if (cChar != MS_LINE && cChar != MS_DLINE) 1695 pRight->GetFont().SetSize(aTmpSize); 1696 1697 pLeft ->AdaptToY(rDev, nBraceHeight); 1698 pRight->AdaptToY(rDev, nBraceHeight); 1699 } 1700 1701 pLeft ->Arrange(rDev, rFormat); 1702 pRight->Arrange(rDev, rFormat); 1703 1704 // damit auch "\(a\) - (a) - left ( a right )" vernuenftig aussieht 1705 RectVerAlign eVerAlign = bScale ? RVA_CENTERY : RVA_BASELINE; 1706 1707 Point aPos; 1708 aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign); 1709 aPos.X() -= nDist; 1710 pLeft->MoveTo(aPos); 1711 1712 aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign); 1713 aPos.X() += nDist; 1714 pRight->MoveTo(aPos); 1715 1716 SmRect::operator = (*pBody); 1717 ExtendBy(*pLeft, RCP_THIS).ExtendBy(*pRight, RCP_THIS); 1718 } 1719 1720 1721 /**************************************************************************/ 1722 1723 1724 void SmBracebodyNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1725 { 1726 sal_uInt16 nNumSubNodes = GetNumSubNodes(); 1727 if (nNumSubNodes == 0) 1728 return; 1729 1730 // arrange arguments 1731 sal_uInt16 i; 1732 for (i = 0; i < nNumSubNodes; i += 2) 1733 GetSubNode(i)->Arrange(rDev, rFormat); 1734 1735 // build reference rectangle with necessary info for vertical alignment 1736 SmRect aRefRect (*GetSubNode(0)); 1737 for (i = 0; i < nNumSubNodes; i += 2) 1738 { 1739 SmRect aTmpRect (*GetSubNode(i)); 1740 Point aPos = aTmpRect.AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE); 1741 aTmpRect.MoveTo(aPos); 1742 aRefRect.ExtendBy(aTmpRect, RCP_XOR); 1743 } 1744 1745 nBodyHeight = aRefRect.GetHeight(); 1746 1747 // scale separators to required height and arrange them 1748 sal_Bool bScale = GetScaleMode() == SCALE_HEIGHT || rFormat.IsScaleNormalBrackets(); 1749 long nHeight = bScale ? aRefRect.GetHeight() : GetFont().GetSize().Height(); 1750 sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ? 1751 DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE; 1752 sal_uInt16 nPerc = rFormat.GetDistance(nIndex); 1753 if (bScale) 1754 nHeight += 2 * (nHeight * nPerc / 100L); 1755 for (i = 1; i < nNumSubNodes; i += 2) 1756 { 1757 SmNode *pNode = GetSubNode(i); 1758 pNode->AdaptToY(rDev, nHeight); 1759 pNode->Arrange(rDev, rFormat); 1760 } 1761 1762 // horizontal distance between argument and brackets or separators 1763 long nDist = GetFont().GetSize().Height() 1764 * rFormat.GetDistance(DIS_BRACKETSPACE) / 100L; 1765 1766 SmNode *pLeft = GetSubNode(0); 1767 SmRect::operator = (*pLeft); 1768 for (i = 1; i < nNumSubNodes; i++) 1769 { 1770 sal_Bool bIsSeparator = i % 2 != 0; 1771 RectVerAlign eVerAlign = bIsSeparator ? RVA_CENTERY : RVA_BASELINE; 1772 1773 SmNode *pRight = GetSubNode(i); 1774 Point aPosX = pRight->AlignTo(*pLeft, RP_RIGHT, RHA_CENTER, eVerAlign), 1775 aPosY = pRight->AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, eVerAlign); 1776 aPosX.X() += nDist; 1777 1778 pRight->MoveTo(Point(aPosX.X(), aPosY.Y())); 1779 ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR); 1780 1781 pLeft = pRight; 1782 } 1783 } 1784 1785 1786 /**************************************************************************/ 1787 1788 1789 void SmVerticalBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1790 { 1791 SmNode *pBody = GetSubNode(0), 1792 *pBrace = GetSubNode(1), 1793 *pScript = GetSubNode(2); 1794 DBG_ASSERT(pBody, "Sm: NULL pointer!"); 1795 DBG_ASSERT(pBrace, "Sm: NULL pointer!"); 1796 DBG_ASSERT(pScript, "Sm: NULL pointer!"); 1797 1798 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 1799 aTmpDev.SetFont(GetFont()); 1800 1801 pBody->Arrange(aTmpDev, rFormat); 1802 1803 // Groesse wie bei Grenzen fuer diesen Teil 1804 pScript->SetSize( Fraction( rFormat.GetRelSize(SIZ_LIMITS), 100 ) ); 1805 // etwas hoehere Klammern als normal 1806 pBrace ->SetSize( Fraction(3, 2) ); 1807 1808 long nItalicWidth = pBody->GetItalicWidth(); 1809 if (nItalicWidth > 0) 1810 pBrace->AdaptToX(aTmpDev, nItalicWidth); 1811 1812 pBrace ->Arrange(aTmpDev, rFormat); 1813 pScript->Arrange(aTmpDev, rFormat); 1814 1815 // die relativen Position und die Abstaende zueinander bestimmen 1816 RectPos eRectPos; 1817 long nFontHeight = pBody->GetFont().GetSize().Height(); 1818 long nDistBody = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE), 1819 nDistScript = nFontHeight; 1820 if (GetToken().eType == TOVERBRACE) 1821 { 1822 eRectPos = RP_TOP; 1823 nDistBody = - nDistBody; 1824 nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT); 1825 } 1826 else // TUNDERBRACE 1827 { 1828 eRectPos = RP_BOTTOM; 1829 nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT); 1830 } 1831 nDistBody /= 100L; 1832 nDistScript /= 100L; 1833 1834 Point aPos = pBrace->AlignTo(*pBody, eRectPos, RHA_CENTER, RVA_BASELINE); 1835 aPos.Y() += nDistBody; 1836 pBrace->MoveTo(aPos); 1837 1838 aPos = pScript->AlignTo(*pBrace, eRectPos, RHA_CENTER, RVA_BASELINE); 1839 aPos.Y() += nDistScript; 1840 pScript->MoveTo(aPos); 1841 1842 SmRect::operator = (*pBody); 1843 ExtendBy(*pBrace, RCP_THIS).ExtendBy(*pScript, RCP_THIS); 1844 } 1845 1846 1847 /**************************************************************************/ 1848 1849 1850 SmNode * SmOperNode::GetSymbol() 1851 { 1852 SmNode *pNode = GetSubNode(0); 1853 DBG_ASSERT(pNode, "Sm: NULL pointer!"); 1854 1855 if (pNode->GetType() == NSUBSUP) 1856 pNode = ((SmSubSupNode *) pNode)->GetBody(); 1857 1858 DBG_ASSERT(pNode, "Sm: NULL pointer!"); 1859 return pNode; 1860 } 1861 1862 1863 long SmOperNode::CalcSymbolHeight(const SmNode &rSymbol, 1864 const SmFormat &rFormat) const 1865 // returns the font height to be used for operator-symbol 1866 { 1867 long nHeight = GetFont().GetSize().Height(); 1868 1869 SmTokenType eTmpType = GetToken().eType; 1870 if (eTmpType == TLIM || eTmpType == TLIMINF || eTmpType == TLIMSUP) 1871 return nHeight; 1872 1873 if (!rFormat.IsTextmode()) 1874 { 1875 // set minimum size () 1876 nHeight += (nHeight * 20L) / 100L; 1877 1878 nHeight += nHeight 1879 * rFormat.GetDistance(DIS_OPERATORSIZE) / 100L; 1880 nHeight = nHeight * 686L / 845L; 1881 } 1882 1883 // correct user-defined symbols to match height of sum from used font 1884 if (rSymbol.GetToken().eType == TSPECIAL) 1885 nHeight = nHeight * 845L / 686L; 1886 1887 return nHeight; 1888 } 1889 1890 1891 void SmOperNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1892 { 1893 SmNode *pOper = GetSubNode(0); 1894 SmNode *pBody = GetSubNode(1); 1895 1896 DBG_ASSERT(pOper, "Sm: Subnode fehlt"); 1897 DBG_ASSERT(pBody, "Sm: Subnode fehlt"); 1898 1899 SmNode *pSymbol = GetSymbol(); 1900 pSymbol->SetSize(Fraction(CalcSymbolHeight(*pSymbol, rFormat), 1901 pSymbol->GetFont().GetSize().Height())); 1902 1903 pBody->Arrange(rDev, rFormat); 1904 pOper->Arrange(rDev, rFormat); 1905 1906 long nOrigHeight = GetFont().GetSize().Height(), 1907 nDist = nOrigHeight 1908 * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L; 1909 1910 Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID); 1911 aPos.X() -= nDist; 1912 pOper->MoveTo(aPos); 1913 1914 SmRect::operator = (*pBody); 1915 ExtendBy(*pOper, RCP_THIS); 1916 } 1917 1918 1919 /**************************************************************************/ 1920 1921 1922 void SmAlignNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1923 // setzt im ganzen subtree (incl aktuellem node) das alignment 1924 { 1925 DBG_ASSERT(GetNumSubNodes() > 0, "Sm: SubNode fehlt"); 1926 1927 SmNode *pNode = GetSubNode(0); 1928 1929 RectHorAlign eHorAlign = RHA_CENTER; 1930 switch (GetToken().eType) 1931 { 1932 case TALIGNL: eHorAlign = RHA_LEFT; break; 1933 case TALIGNC: eHorAlign = RHA_CENTER; break; 1934 case TALIGNR: eHorAlign = RHA_RIGHT; break; 1935 default: 1936 break; 1937 } 1938 SetRectHorAlign(eHorAlign); 1939 1940 pNode->Arrange(rDev, rFormat); 1941 1942 SmRect::operator = (pNode->GetRect()); 1943 } 1944 1945 1946 /**************************************************************************/ 1947 1948 1949 void SmAttributNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 1950 { 1951 SmNode *pAttr = GetSubNode(0), 1952 *pBody = GetSubNode(1); 1953 DBG_ASSERT(pBody, "Sm: Body fehlt"); 1954 DBG_ASSERT(pAttr, "Sm: Attribut fehlt"); 1955 1956 pBody->Arrange(rDev, rFormat); 1957 1958 if (GetScaleMode() == SCALE_WIDTH) 1959 pAttr->AdaptToX(rDev, pBody->GetItalicWidth()); 1960 pAttr->Arrange(rDev, rFormat); 1961 1962 // get relative position of attribut 1963 RectVerAlign eVerAlign; 1964 long nDist = 0; 1965 switch (GetToken().eType) 1966 { case TUNDERLINE : 1967 eVerAlign = RVA_ATTRIBUT_LO; 1968 break; 1969 case TOVERSTRIKE : 1970 eVerAlign = RVA_ATTRIBUT_MID; 1971 break; 1972 default : 1973 eVerAlign = RVA_ATTRIBUT_HI; 1974 if (pBody->GetType() == NATTRIBUT) 1975 nDist = GetFont().GetSize().Height() 1976 * rFormat.GetDistance(DIS_ORNAMENTSPACE) / 100L; 1977 } 1978 Point aPos = pAttr->AlignTo(*pBody, RP_ATTRIBUT, RHA_CENTER, eVerAlign); 1979 aPos.Y() -= nDist; 1980 pAttr->MoveTo(aPos); 1981 1982 SmRect::operator = (*pBody); 1983 ExtendBy(*pAttr, RCP_THIS, (sal_Bool) sal_True); 1984 } 1985 1986 1987 /**************************************************************************/ 1988 1989 1990 1991 1992 void SmFontNode::CreateTextFromNode(String &rText) 1993 { 1994 switch (GetToken().eType) 1995 { 1996 case TBOLD: 1997 APPEND(rText,"bold "); 1998 break; 1999 case TNBOLD: 2000 APPEND(rText,"nbold "); 2001 break; 2002 case TITALIC: 2003 APPEND(rText,"italic "); 2004 break; 2005 case TNITALIC: 2006 APPEND(rText,"nitalic "); 2007 break; 2008 case TPHANTOM: 2009 APPEND(rText,"phantom "); 2010 break; 2011 case TSIZE: 2012 { 2013 APPEND(rText,"size "); 2014 switch (nSizeType) 2015 { 2016 case FNTSIZ_PLUS: 2017 rText.Append('+'); 2018 break; 2019 case FNTSIZ_MINUS: 2020 rText.Append('-'); 2021 break; 2022 case FNTSIZ_MULTIPLY: 2023 rText.Append('*'); 2024 break; 2025 case FNTSIZ_DIVIDE: 2026 rText.Append('/'); 2027 break; 2028 case FNTSIZ_ABSOLUT: 2029 default: 2030 break; 2031 } 2032 rText += String( ::rtl::math::doubleToUString( 2033 static_cast<double>(aFontSize), 2034 rtl_math_StringFormat_Automatic, 2035 rtl_math_DecimalPlaces_Max, '.', sal_True)); 2036 rText.Append(' '); 2037 } 2038 break; 2039 case TBLACK: 2040 APPEND(rText,"color black "); 2041 break; 2042 case TWHITE: 2043 APPEND(rText,"color white "); 2044 break; 2045 case TRED: 2046 APPEND(rText,"color red "); 2047 break; 2048 case TGREEN: 2049 APPEND(rText,"color green "); 2050 break; 2051 case TBLUE: 2052 APPEND(rText,"color blue "); 2053 break; 2054 case TCYAN: 2055 APPEND(rText,"color cyan "); 2056 break; 2057 case TMAGENTA: 2058 APPEND(rText,"color magenta "); 2059 break; 2060 case TYELLOW: 2061 APPEND(rText,"color yellow "); 2062 break; 2063 case TSANS: 2064 APPEND(rText,"font sans "); 2065 break; 2066 case TSERIF: 2067 APPEND(rText,"font serif "); 2068 break; 2069 case TFIXED: 2070 APPEND(rText,"font fixed "); 2071 break; 2072 default: 2073 break; 2074 } 2075 GetSubNode(1)->CreateTextFromNode(rText); 2076 } 2077 2078 2079 void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 2080 { 2081 //! prepare subnodes first 2082 SmNode::Prepare(rFormat, rDocShell); 2083 2084 int nFnt = -1; 2085 switch (GetToken().eType) 2086 { 2087 case TFIXED: nFnt = FNT_FIXED; break; 2088 case TSANS: nFnt = FNT_SANS; break; 2089 case TSERIF: nFnt = FNT_SERIF; break; 2090 default: 2091 break; 2092 } 2093 if (nFnt != -1) 2094 { GetFont() = rFormat.GetFont( sal::static_int_cast< sal_uInt16 >(nFnt) ); 2095 SetFont(GetFont()); 2096 } 2097 2098 //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of 2099 //! other font nodes (those with lower depth in the tree) 2100 Flags() |= FLG_FONT; 2101 } 2102 2103 2104 void SmFontNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2105 { 2106 SmNode *pNode = GetSubNode(1); 2107 DBG_ASSERT(pNode, "Sm: SubNode fehlt"); 2108 2109 switch (GetToken().eType) 2110 { case TSIZE : 2111 pNode->SetFontSize(aFontSize, nSizeType); 2112 break; 2113 case TSANS : 2114 case TSERIF : 2115 case TFIXED : 2116 pNode->SetFont(GetFont()); 2117 break; 2118 case TUNKNOWN : break; // no assertion on "font <?> <?>" 2119 2120 case TPHANTOM : SetPhantom(sal_True); break; 2121 case TBOLD : SetAttribut(ATTR_BOLD); break; 2122 case TITALIC : SetAttribut(ATTR_ITALIC); break; 2123 case TNBOLD : ClearAttribut(ATTR_BOLD); break; 2124 case TNITALIC : ClearAttribut(ATTR_ITALIC); break; 2125 2126 case TBLACK : SetColor(Color(COL_BLACK)); break; 2127 case TWHITE : SetColor(Color(COL_WHITE)); break; 2128 case TRED : SetColor(Color(COL_RED)); break; 2129 case TGREEN : SetColor(Color(COL_GREEN)); break; 2130 case TBLUE : SetColor(Color(COL_BLUE)); break; 2131 case TCYAN : SetColor(Color(COL_CYAN)); break; 2132 case TMAGENTA : SetColor(Color(COL_MAGENTA)); break; 2133 case TYELLOW : SetColor(Color(COL_YELLOW)); break; 2134 2135 default: 2136 DBG_ASSERT(sal_False, "Sm: unbekannter Fall"); 2137 } 2138 2139 pNode->Arrange(rDev, rFormat); 2140 2141 SmRect::operator = (pNode->GetRect()); 2142 } 2143 2144 2145 void SmFontNode::SetSizeParameter(const Fraction& rValue, sal_uInt16 Type) 2146 { 2147 nSizeType = Type; 2148 aFontSize = rValue; 2149 } 2150 2151 2152 /**************************************************************************/ 2153 2154 2155 SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken) 2156 : SmGraphicNode(NPOLYLINE, rNodeToken) 2157 { 2158 aPoly.SetSize(2); 2159 nWidth = 0; 2160 } 2161 2162 2163 void SmPolyLineNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nNewWidth) 2164 { 2165 aToSize.Width() = nNewWidth; 2166 } 2167 2168 2169 void SmPolyLineNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nNewHeight) 2170 { 2171 GetFont().FreezeBorderWidth(); 2172 aToSize.Height() = nNewHeight; 2173 } 2174 2175 2176 void SmPolyLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2177 { 2178 //! some routines being called extract some info from the OutputDevice's 2179 //! font (eg the space to be used for borders OR the font name(!!)). 2180 //! Thus the font should reflect the needs and has to be set! 2181 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2182 aTmpDev.SetFont(GetFont()); 2183 2184 long nBorderwidth = GetFont().GetBorderWidth(); 2185 2186 // 2187 // Das Polygon mit den beiden Endpunkten bilden 2188 // 2189 DBG_ASSERT(aPoly.GetSize() == 2, "Sm : falsche Anzahl von Punkten"); 2190 Point aPointA, aPointB; 2191 if (GetToken().eType == TWIDESLASH) 2192 { 2193 aPointA.X() = nBorderwidth; 2194 aPointA.Y() = aToSize.Height() - nBorderwidth; 2195 aPointB.X() = aToSize.Width() - nBorderwidth; 2196 aPointB.Y() = nBorderwidth; 2197 } 2198 else 2199 { 2200 DBG_ASSERT(GetToken().eType == TWIDEBACKSLASH, "Sm : unerwartetes Token"); 2201 aPointA.X() = 2202 aPointA.Y() = nBorderwidth; 2203 aPointB.X() = aToSize.Width() - nBorderwidth; 2204 aPointB.Y() = aToSize.Height() - nBorderwidth; 2205 } 2206 aPoly.SetPoint(aPointA, 0); 2207 aPoly.SetPoint(aPointB, 1); 2208 2209 long nThick = GetFont().GetSize().Height() 2210 * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L; 2211 nWidth = nThick + 2 * nBorderwidth; 2212 2213 SmRect::operator = (SmRect(aToSize.Width(), aToSize.Height())); 2214 } 2215 2216 2217 void SmPolyLineNode::Draw(OutputDevice &rDev, const Point &rPosition) const 2218 { 2219 if (IsPhantom()) 2220 return; 2221 2222 long nBorderwidth = GetFont().GetBorderWidth(); 2223 2224 LineInfo aInfo; 2225 aInfo.SetWidth(nWidth - 2 * nBorderwidth); 2226 2227 Point aOffset (Point() - aPoly.GetBoundRect().TopLeft() 2228 + Point(nBorderwidth, nBorderwidth)), 2229 aPos (rPosition + aOffset); 2230 ((Polygon &) aPoly).Move(aPos.X(), aPos.Y()); 2231 2232 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_False); 2233 aTmpDev.SetLineColor( GetFont().GetColor() ); 2234 2235 rDev.DrawPolyLine(aPoly, aInfo); 2236 2237 #ifdef SM_RECT_DEBUG 2238 if (!IsDebug()) 2239 return; 2240 2241 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID; 2242 SmRect::Draw(rDev, rPosition, nRFlags); 2243 #endif 2244 } 2245 2246 2247 /**************************************************************************/ 2248 2249 void SmRootSymbolNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth) 2250 { 2251 nBodyWidth = nWidth; 2252 } 2253 2254 2255 void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight) 2256 { 2257 // etwas extra Laenge damit der horizontale Balken spaeter ueber dem 2258 // Argument positioniert ist 2259 SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / 10L); 2260 } 2261 2262 2263 void SmRootSymbolNode::Draw(OutputDevice &rDev, const Point &rPosition) const 2264 { 2265 if (IsPhantom()) 2266 return; 2267 2268 // draw root-sign itself 2269 SmMathSymbolNode::Draw(rDev, rPosition); 2270 2271 SmTmpDevice aTmpDev( (OutputDevice &) rDev, sal_True ); 2272 aTmpDev.SetFillColor(GetFont().GetColor()); 2273 rDev.SetLineColor(); 2274 aTmpDev.SetFont( GetFont() ); 2275 2276 // since the width is always unscaled it corresponds ot the _original_ 2277 // _unscaled_ font height to be used, we use that to calculate the 2278 // bar height. Thus it is independent of the arguments height. 2279 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} ) 2280 long nBarHeight = GetWidth() * 7L / 100L; 2281 long nBarWidth = nBodyWidth + GetBorderWidth(); 2282 Point aBarOffset( GetWidth(), +GetBorderWidth() ); 2283 Point aBarPos( rPosition + aBarOffset ); 2284 2285 Rectangle aBar(aBarPos, Size( nBarWidth, nBarHeight) ); 2286 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly 2287 //! increasing zoomfactor. 2288 // This is done by shifting it's output-position to a point that 2289 // corresponds exactly to a pixel on the output device. 2290 Point aDrawPos( rDev.PixelToLogic(rDev.LogicToPixel(aBar.TopLeft())) ); 2291 //aDrawPos.X() = aBar.Left(); //! don't change X position 2292 aBar.SetPos( aDrawPos ); 2293 2294 rDev.DrawRect( aBar ); 2295 2296 #ifdef SM_RECT_DEBUG 2297 if (!IsDebug()) 2298 return; 2299 2300 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID; 2301 SmRect::Draw(rDev, rPosition, nRFlags); 2302 #endif 2303 } 2304 2305 2306 /**************************************************************************/ 2307 2308 2309 void SmRectangleNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth) 2310 { 2311 aToSize.Width() = nWidth; 2312 } 2313 2314 2315 void SmRectangleNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nHeight) 2316 { 2317 GetFont().FreezeBorderWidth(); 2318 aToSize.Height() = nHeight; 2319 } 2320 2321 2322 void SmRectangleNode::Arrange(const OutputDevice &rDev, const SmFormat &/*rFormat*/) 2323 { 2324 long nFontHeight = GetFont().GetSize().Height(); 2325 long nWidth = aToSize.Width(), 2326 nHeight = aToSize.Height(); 2327 if (nHeight == 0) 2328 nHeight = nFontHeight / 30; 2329 if (nWidth == 0) 2330 nWidth = nFontHeight / 3; 2331 2332 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2333 aTmpDev.SetFont(GetFont()); 2334 2335 // add some borderspace 2336 sal_uLong nTmpBorderWidth = GetFont().GetBorderWidth(); 2337 //nWidth += nTmpBorderWidth; 2338 nHeight += 2 * nTmpBorderWidth; 2339 2340 //! use this method in order to have 'SmRect::HasAlignInfo() == sal_True' 2341 //! and thus having the attribut-fences updated in 'SmRect::ExtendBy' 2342 SmRect::operator = (SmRect(nWidth, nHeight)); 2343 } 2344 2345 2346 void SmRectangleNode::Draw(OutputDevice &rDev, const Point &rPosition) const 2347 { 2348 if (IsPhantom()) 2349 return; 2350 2351 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_False); 2352 aTmpDev.SetFillColor(GetFont().GetColor()); 2353 rDev.SetLineColor(); 2354 aTmpDev.SetFont(GetFont()); 2355 2356 sal_uLong nTmpBorderWidth = GetFont().GetBorderWidth(); 2357 2358 // get rectangle and remove borderspace 2359 Rectangle aTmp (AsRectangle() + rPosition - GetTopLeft()); 2360 aTmp.Left() += nTmpBorderWidth; 2361 aTmp.Right() -= nTmpBorderWidth; 2362 aTmp.Top() += nTmpBorderWidth; 2363 aTmp.Bottom() -= nTmpBorderWidth; 2364 2365 DBG_ASSERT(aTmp.GetHeight() > 0 && aTmp.GetWidth() > 0, 2366 "Sm: leeres Rechteck"); 2367 2368 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly 2369 //! increasing zoomfactor. 2370 // This is done by shifting it's output-position to a point that 2371 // corresponds exactly to a pixel on the output device. 2372 Point aPos (rDev.PixelToLogic(rDev.LogicToPixel(aTmp.TopLeft()))); 2373 aTmp.SetPos(aPos); 2374 2375 rDev.DrawRect(aTmp); 2376 2377 #ifdef SM_RECT_DEBUG 2378 if (!IsDebug()) 2379 return; 2380 2381 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID; 2382 SmRect::Draw(rDev, rPosition, nRFlags); 2383 #endif 2384 } 2385 2386 2387 /**************************************************************************/ 2388 2389 2390 SmTextNode::SmTextNode( SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 nFontDescP ) : 2391 SmVisibleNode(eNodeType, rNodeToken) 2392 { 2393 nFontDesc = nFontDescP; 2394 } 2395 2396 2397 SmTextNode::SmTextNode( const SmToken &rNodeToken, sal_uInt16 nFontDescP ) : 2398 SmVisibleNode(NTEXT, rNodeToken) 2399 { 2400 nFontDesc = nFontDescP; 2401 } 2402 2403 2404 void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 2405 { 2406 SmNode::Prepare(rFormat, rDocShell); 2407 2408 // default setting for horizontal alignment of nodes with TTEXT 2409 // content is as alignl (cannot be done in Arrange since it would 2410 // override the settings made by an SmAlignNode before) 2411 if (TTEXT == GetToken().eType) 2412 SetRectHorAlign( RHA_LEFT ); 2413 2414 aText = GetToken().aText; 2415 GetFont() = rFormat.GetFont(GetFontDesc()); 2416 2417 if (IsItalic( GetFont() )) 2418 Attributes() |= ATTR_ITALIC; 2419 if (IsBold( GetFont() )) 2420 Attributes() |= ATTR_BOLD; 2421 2422 // special handling for ':' where it is a token on it's own and is likely 2423 // to be used for mathematical notations. (E.g. a:b = 2:3) 2424 // In that case it should not be displayed in italic. 2425 if (GetToken().aText.Len() == 1 && GetToken().aText.GetChar(0) == ':') 2426 Attributes() &= ~ATTR_ITALIC; 2427 }; 2428 2429 2430 void SmTextNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2431 { 2432 PrepareAttributes(); 2433 2434 sal_uInt16 nSizeDesc = GetFontDesc() == FNT_FUNCTION ? 2435 SIZ_FUNCTION : SIZ_TEXT; 2436 GetFont() *= Fraction (rFormat.GetRelSize(nSizeDesc), 100); 2437 2438 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2439 aTmpDev.SetFont(GetFont()); 2440 2441 SmRect::operator = (SmRect(aTmpDev, &rFormat, aText, GetFont().GetBorderWidth())); 2442 } 2443 2444 void SmTextNode::CreateTextFromNode(String &rText) 2445 { 2446 sal_Bool bQuoted=sal_False; 2447 if (GetToken().eType == TTEXT) 2448 { 2449 rText.Append('\"'); 2450 bQuoted=sal_True; 2451 } 2452 else 2453 { 2454 SmParser aParseTest; 2455 SmNode *pTable = aParseTest.Parse(GetToken().aText); 2456 bQuoted=sal_True; 2457 if ( (pTable->GetType() == NTABLE) && (pTable->GetNumSubNodes() == 1) ) 2458 { 2459 SmNode *pResult = pTable->GetSubNode(0); 2460 if ( (pResult->GetType() == NLINE) && 2461 (pResult->GetNumSubNodes() == 1) ) 2462 { 2463 pResult = pResult->GetSubNode(0); 2464 if ( (pResult->GetType() == NEXPRESSION) && 2465 (pResult->GetNumSubNodes() == 1) ) 2466 { 2467 pResult = pResult->GetSubNode(0); 2468 if (pResult->GetType() == NTEXT) 2469 bQuoted=sal_False; 2470 } 2471 } 2472 } 2473 delete pTable; 2474 2475 if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION)) 2476 { 2477 //Search for existing functions and remove extraenous keyword 2478 APPEND(rText,"func "); 2479 } 2480 else if (bQuoted) 2481 APPEND(rText,"italic "); 2482 2483 if (bQuoted) 2484 rText.Append('\"'); 2485 2486 } 2487 2488 rText.Append(GetToken().aText); 2489 2490 if (bQuoted) 2491 rText.Append('\"'); 2492 rText.Append(' '); 2493 } 2494 2495 void SmTextNode::Draw(OutputDevice &rDev, const Point& rPosition) const 2496 { 2497 if (IsPhantom() || aText.Len() == 0 || aText.GetChar(0) == xub_Unicode('\0')) 2498 return; 2499 2500 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_False); 2501 aTmpDev.SetFont(GetFont()); 2502 2503 Point aPos (rPosition); 2504 aPos.Y() += GetBaselineOffset(); 2505 // auf Pixelkoordinaten runden 2506 aPos = rDev.PixelToLogic( rDev.LogicToPixel(aPos) ); 2507 2508 #if OSL_DEBUG_LEVEL > 1 2509 sal_Int32 nPos = 0; 2510 sal_UCS4 cChar = OUString( aText ).iterateCodePoints( &nPos ); 2511 (void) cChar; 2512 #endif 2513 2514 rDev.DrawStretchText(aPos, GetWidth(), aText); 2515 2516 #ifdef SM_RECT_DEBUG 2517 if (!IsDebug()) 2518 return; 2519 2520 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID; 2521 SmRect::Draw(rDev, rPosition, nRFlags); 2522 #endif 2523 } 2524 2525 void SmTextNode::GetAccessibleText( String &rText ) const 2526 { 2527 rText += aText; 2528 } 2529 2530 /**************************************************************************/ 2531 2532 void SmMatrixNode::CreateTextFromNode(String &rText) 2533 { 2534 APPEND(rText,"matrix {"); 2535 for (sal_uInt16 i = 0; i < nNumRows; i++) 2536 { 2537 for (sal_uInt16 j = 0; j < nNumCols; j++) 2538 { 2539 SmNode *pNode = GetSubNode(i * nNumCols + j); 2540 pNode->CreateTextFromNode(rText); 2541 if (j != nNumCols-1) 2542 APPEND(rText,"# "); 2543 } 2544 if (i != nNumRows-1) 2545 APPEND(rText,"## "); 2546 } 2547 rText.EraseTrailingChars(); 2548 APPEND(rText,"} "); 2549 } 2550 2551 2552 void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2553 { 2554 Point aPosition, 2555 aOffset; 2556 SmNode *pNode; 2557 sal_uInt16 i, j; 2558 2559 // initialize array that is to hold the maximum widhts of all 2560 // elements (subnodes) in that column. 2561 long *pColWidth = new long[nNumCols]; 2562 for (j = 0; j < nNumCols; j++) 2563 pColWidth[j] = 0; 2564 2565 // arrange subnodes and calculate the aboves arrays contents 2566 sal_uInt16 nNodes = GetNumSubNodes(); 2567 for (i = 0; i < nNodes; i++) 2568 { 2569 sal_uInt16 nIdx = nNodes - 1 - i; 2570 if (NULL != (pNode = GetSubNode(nIdx))) 2571 { 2572 pNode->Arrange(rDev, rFormat); 2573 int nCol = nIdx % nNumCols; 2574 pColWidth[nCol] = Max(pColWidth[nCol], pNode->GetItalicWidth()); 2575 } 2576 } 2577 2578 // norm distance from which the following two are calcutated 2579 const int nNormDist = 3 * GetFont().GetSize().Height(); 2580 2581 // define horizontal and vertical minimal distances that seperate 2582 // the elements 2583 long nHorDist = nNormDist * rFormat.GetDistance(DIS_MATRIXCOL) / 100L, 2584 nVerDist = nNormDist * rFormat.GetDistance(DIS_MATRIXROW) / 100L; 2585 2586 // build array that holds the leftmost position for each column 2587 long *pColLeft = new long[nNumCols]; 2588 long nX = 0; 2589 for (j = 0; j < nNumCols; j++) 2590 { pColLeft[j] = nX; 2591 nX += pColWidth[j] + nHorDist; 2592 } 2593 2594 Point aPos, aDelta; 2595 SmRect aLineRect; 2596 SmRect::operator = (SmRect()); 2597 for (i = 0; i < nNumRows; i++) 2598 { aLineRect = SmRect(); 2599 for (j = 0; j < nNumCols; j++) 2600 { SmNode *pTmpNode = GetSubNode(i * nNumCols + j); 2601 DBG_ASSERT(pTmpNode, "Sm: NULL pointer"); 2602 2603 const SmRect &rNodeRect = pTmpNode->GetRect(); 2604 2605 // align all baselines in that row if possible 2606 aPos = rNodeRect.AlignTo(aLineRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE); 2607 aPos.X() += nHorDist; 2608 2609 // get horizontal alignment 2610 const SmNode *pCoNode = pTmpNode->GetLeftMost(); 2611 RectHorAlign eHorAlign = pCoNode->GetRectHorAlign(); 2612 2613 // caculate horizontal position of element depending on column 2614 // and horizontal alignment 2615 switch (eHorAlign) 2616 { case RHA_LEFT: 2617 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]; 2618 break; 2619 case RHA_CENTER: 2620 aPos.X() = rNodeRect.GetLeft() + pColLeft[j] 2621 + pColWidth[j] / 2 2622 - rNodeRect.GetItalicCenterX(); 2623 break; 2624 case RHA_RIGHT: 2625 aPos.X() = rNodeRect.GetLeft() + pColLeft[j] 2626 + pColWidth[j] - rNodeRect.GetItalicWidth(); 2627 break; 2628 } 2629 2630 pTmpNode->MoveTo(aPos); 2631 aLineRect.ExtendBy(rNodeRect, RCP_XOR); 2632 } 2633 2634 aPos = aLineRect.AlignTo(*this, RP_BOTTOM, RHA_CENTER, RVA_BASELINE); 2635 aPos.Y() += nVerDist; 2636 2637 // move 'aLineRect' and rectangles in that line to final position 2638 aDelta.X() = 0; // since horizontal alignment is already done 2639 aDelta.Y() = aPos.Y() - aLineRect.GetTop(); 2640 aLineRect.Move(aDelta); 2641 for (j = 0; j < nNumCols; j++) 2642 if (NULL != (pNode = GetSubNode(i * nNumCols + j))) 2643 pNode->Move(aDelta); 2644 2645 ExtendBy(aLineRect, RCP_NONE); 2646 } 2647 2648 delete [] pColLeft; 2649 delete [] pColWidth; 2650 } 2651 2652 2653 void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols) 2654 { 2655 nNumRows = nMatrixRows; 2656 nNumCols = nMatrixCols; 2657 } 2658 2659 2660 SmNode * SmMatrixNode::GetLeftMost() 2661 { 2662 return this; 2663 } 2664 2665 2666 /**************************************************************************/ 2667 2668 2669 SmMathSymbolNode::SmMathSymbolNode(const SmToken &rNodeToken) 2670 : SmSpecialNode(NMATH, rNodeToken, FNT_MATH) 2671 { 2672 xub_Unicode cChar = GetToken().cMathChar; 2673 if ((xub_Unicode) '\0' != cChar) 2674 SetText( cChar ); 2675 } 2676 2677 void SmMathSymbolNode::AdaptToX(const OutputDevice &rDev, sal_uLong nWidth) 2678 { 2679 // Since there is no function to do this, we try to approximate it: 2680 Size aFntSize (GetFont().GetSize()); 2681 2682 //! however the result is a bit better with 'nWidth' as initial font width 2683 aFntSize.Width() = nWidth; 2684 GetFont().SetSize(aFntSize); 2685 2686 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2687 aTmpDev.SetFont(GetFont()); 2688 2689 // get denominator of error factor for width 2690 long nTmpBorderWidth = GetFont().GetBorderWidth(); 2691 long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetItalicWidth(); 2692 2693 // scale fontwidth with this error factor 2694 aFntSize.Width() *= nWidth; 2695 aFntSize.Width() /= nDenom ? nDenom : 1; 2696 2697 GetFont().SetSize(aFntSize); 2698 } 2699 2700 void SmMathSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight) 2701 { 2702 GetFont().FreezeBorderWidth(); 2703 Size aFntSize (GetFont().GetSize()); 2704 2705 // da wir nur die Hoehe skalieren wollen muesen wir hier ggf die Fontweite 2706 // ermitteln um diese beizubehalten. 2707 if (aFntSize.Width() == 0) 2708 { 2709 OutputDevice &rDevNC = (OutputDevice &) rDev; 2710 rDevNC.Push(PUSH_FONT | PUSH_MAPMODE); 2711 rDevNC.SetFont(GetFont()); 2712 aFntSize.Width() = rDev.GetFontMetric().GetSize().Width(); 2713 rDevNC.Pop(); 2714 } 2715 DBG_ASSERT(aFntSize.Width() != 0, "Sm: "); 2716 2717 //! however the result is a bit better with 'nHeight' as initial 2718 //! font height 2719 aFntSize.Height() = nHeight; 2720 GetFont().SetSize(aFntSize); 2721 2722 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2723 aTmpDev.SetFont(GetFont()); 2724 2725 // get denominator of error factor for height 2726 long nTmpBorderWidth = GetFont().GetBorderWidth(); 2727 long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetHeight(); 2728 2729 // scale fontwidth with this error factor 2730 aFntSize.Height() *= nHeight; 2731 aFntSize.Height() /= nDenom ? nDenom : 1; 2732 2733 GetFont().SetSize(aFntSize); 2734 } 2735 2736 2737 void SmMathSymbolNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 2738 { 2739 SmNode::Prepare(rFormat, rDocShell); 2740 2741 GetFont() = rFormat.GetFont(GetFontDesc()); 2742 // use same font size as is used for variables 2743 GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() ); 2744 2745 DBG_ASSERT(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL || 2746 GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE, 2747 "incorrect charset for character from StarMath/OpenSymbol font"); 2748 2749 Flags() |= FLG_FONT | FLG_ITALIC; 2750 }; 2751 2752 2753 void SmMathSymbolNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2754 { 2755 const XubString &rText = GetText(); 2756 2757 if (rText.Len() == 0 || rText.GetChar(0) == xub_Unicode('\0')) 2758 { SmRect::operator = (SmRect()); 2759 return; 2760 } 2761 2762 PrepareAttributes(); 2763 2764 GetFont() *= Fraction (rFormat.GetRelSize(SIZ_TEXT), 100); 2765 2766 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2767 aTmpDev.SetFont(GetFont()); 2768 2769 SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth())); 2770 } 2771 2772 void SmMathSymbolNode::CreateTextFromNode(String &rText) 2773 { 2774 String sStr; 2775 MathType::LookupChar(GetToken().cMathChar, sStr); 2776 rText.Append(sStr); 2777 } 2778 2779 void SmRectangleNode::CreateTextFromNode(String &rText) 2780 { 2781 switch (GetToken().eType) 2782 { 2783 case TUNDERLINE: 2784 APPEND(rText,"underline "); 2785 break; 2786 case TOVERLINE: 2787 APPEND(rText,"overline "); 2788 break; 2789 case TOVERSTRIKE: 2790 APPEND(rText,"overstrike "); 2791 break; 2792 default: 2793 break; 2794 } 2795 } 2796 2797 void SmAttributNode::CreateTextFromNode(String &rText) 2798 { 2799 SmNode *pNode; 2800 sal_uInt16 nSize = GetNumSubNodes(); 2801 DBG_ASSERT(nSize == 2, "Node missing members"); 2802 rText.Append('{'); 2803 sal_Unicode nLast=0; 2804 if (NULL != (pNode = GetSubNode(0))) 2805 { 2806 String aStr; 2807 pNode->CreateTextFromNode(aStr); 2808 if (aStr.Len() > 1) 2809 rText.Append(aStr); 2810 else 2811 { 2812 nLast = aStr.GetChar(0); 2813 switch (nLast) 2814 { 2815 case 0xAF: 2816 APPEND(rText,"overline "); 2817 break; 2818 case 0x2d9: 2819 APPEND(rText,"dot "); 2820 break; 2821 case 0x2dc: 2822 APPEND(rText,"widetilde "); 2823 break; 2824 case 0xA8: 2825 APPEND(rText,"ddot "); 2826 break; 2827 case 0xE082: 2828 break; 2829 case 0xE09B: 2830 APPEND(rText,"dddot "); 2831 break; 2832 default: 2833 rText.Append(nLast); 2834 break; 2835 } 2836 } 2837 } 2838 2839 if (nSize == 2) 2840 if (NULL != (pNode = GetSubNode(1))) 2841 pNode->CreateTextFromNode(rText); 2842 2843 rText.EraseTrailingChars(); 2844 2845 if (nLast == 0xE082) 2846 APPEND(rText," overbrace {}"); 2847 2848 APPEND(rText,"} "); 2849 } 2850 2851 /**************************************************************************/ 2852 2853 bool lcl_IsFromGreekSymbolSet( const String &rTokenText ) 2854 { 2855 bool bRes = false; 2856 2857 // valid symbol name needs to have a '%' at pos 0 and at least an additonal char 2858 if (rTokenText.Len() > 2 && rTokenText.GetBuffer()[0] == (sal_Unicode)'%') 2859 { 2860 String aName( rTokenText.Copy(1) ); 2861 SmSym *pSymbol = SM_MOD()->GetSymbolManager().GetSymbolByName( aName ); 2862 if (pSymbol && GetExportSymbolSetName( pSymbol->GetSymbolSetName() ).EqualsAscii( "Greek" ) ) 2863 bRes = true; 2864 } 2865 2866 return bRes; 2867 } 2868 2869 2870 SmSpecialNode::SmSpecialNode(SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 _nFontDesc) : 2871 SmTextNode(eNodeType, rNodeToken, _nFontDesc) 2872 { 2873 bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText ); 2874 } 2875 2876 2877 SmSpecialNode::SmSpecialNode(const SmToken &rNodeToken) : 2878 SmTextNode(NSPECIAL, rNodeToken, FNT_MATH) //! default Font nicht immer richtig 2879 { 2880 bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText ); 2881 } 2882 2883 2884 void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 2885 { 2886 SmNode::Prepare(rFormat, rDocShell); 2887 2888 const SmSym *pSym; 2889 SmModule *pp = SM_MOD(); 2890 2891 String aName( GetToken().aText.Copy(1) ); 2892 if (NULL != (pSym = pp->GetSymbolManager().GetSymbolByName( aName ))) 2893 { 2894 sal_UCS4 cChar = pSym->GetCharacter(); 2895 String aTmp( OUString( &cChar, 1 ) ); 2896 SetText( aTmp ); 2897 GetFont() = pSym->GetFace(); 2898 } 2899 else 2900 { 2901 SetText( GetToken().aText ); 2902 GetFont() = rFormat.GetFont(FNT_VARIABLE); 2903 } 2904 // use same font size as is used for variables 2905 GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() ); 2906 2907 //! eigentlich sollten nur WEIGHT_NORMAL und WEIGHT_BOLD vorkommen... 2908 //! In der sms-Datei gibt es jedoch zB auch 'WEIGHT_ULTRALIGHT' 2909 //! daher vergleichen wir hier mit > statt mit != . 2910 //! (Langfristig sollte die Notwendigkeit fuer 'PrepareAttribut', und damit 2911 //! fuer dieses hier, mal entfallen.) 2912 // 2913 //! see also SmFontStyles::GetStyleName 2914 if (IsItalic( GetFont() )) 2915 SetAttribut(ATTR_ITALIC); 2916 if (IsBold( GetFont() )) 2917 SetAttribut(ATTR_BOLD); 2918 2919 Flags() |= FLG_FONT; 2920 2921 if (bIsFromGreekSymbolSet) 2922 { 2923 DBG_ASSERT( GetText().Len() == 1, "a symbol should only consist of 1 char!" ); 2924 bool bItalic = false; 2925 sal_Int16 nStyle = rFormat.GetGreekCharStyle(); 2926 DBG_ASSERT( nStyle >= 0 && nStyle <= 2, "unexpected value for GreekCharStyle" ); 2927 if (nStyle == 1) 2928 bItalic = true; 2929 else if (nStyle == 2) 2930 { 2931 String aTmp( GetText() ); 2932 if (aTmp.Len() > 0) 2933 { 2934 const sal_Unicode cUppercaseAlpha = 0x0391; 2935 const sal_Unicode cUppercaseOmega = 0x03A9; 2936 sal_Unicode cChar = aTmp.GetBuffer()[0]; 2937 // uppercase letters should be straight and lowercase letters italic 2938 bItalic = !(cUppercaseAlpha <= cChar && cChar <= cUppercaseOmega); 2939 } 2940 } 2941 2942 if (bItalic) 2943 Attributes() |= ATTR_ITALIC; 2944 else 2945 Attributes() &= ~ATTR_ITALIC;; 2946 } 2947 }; 2948 2949 2950 void SmSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2951 { 2952 PrepareAttributes(); 2953 2954 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2955 aTmpDev.SetFont(GetFont()); 2956 2957 SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth())); 2958 } 2959 2960 2961 void SmSpecialNode::Draw(OutputDevice &rDev, const Point& rPosition) const 2962 { 2963 //! since this chars might come from any font, that we may not have 2964 //! set to ALIGN_BASELINE yet, we do it now. 2965 ((SmSpecialNode *)this)->GetFont().SetAlign(ALIGN_BASELINE); 2966 2967 SmTextNode::Draw(rDev, rPosition); 2968 } 2969 2970 2971 /**************************************************************************/ 2972 2973 2974 void SmGlyphSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2975 { 2976 PrepareAttributes(); 2977 2978 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 2979 aTmpDev.SetFont(GetFont()); 2980 2981 SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), 2982 GetFont().GetBorderWidth()).AsGlyphRect()); 2983 } 2984 2985 2986 /**************************************************************************/ 2987 2988 2989 void SmPlaceNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 2990 { 2991 SmNode::Prepare(rFormat, rDocShell); 2992 2993 GetFont().SetColor(COL_GRAY); 2994 Flags() |= FLG_COLOR | FLG_FONT | FLG_ITALIC; 2995 }; 2996 2997 2998 void SmPlaceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 2999 { 3000 PrepareAttributes(); 3001 3002 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 3003 aTmpDev.SetFont(GetFont()); 3004 3005 SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth())); 3006 } 3007 3008 3009 /**************************************************************************/ 3010 3011 3012 void SmErrorNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 3013 { 3014 SmNode::Prepare(rFormat, rDocShell); 3015 3016 GetFont().SetColor(COL_RED); 3017 Flags() |= FLG_VISIBLE | FLG_BOLD | FLG_ITALIC 3018 | FLG_COLOR | FLG_FONT | FLG_SIZE; 3019 } 3020 3021 3022 void SmErrorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 3023 { 3024 PrepareAttributes(); 3025 3026 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 3027 aTmpDev.SetFont(GetFont()); 3028 3029 const XubString &rText = GetText(); 3030 SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth())); 3031 } 3032 3033 3034 /**************************************************************************/ 3035 3036 3037 void SmBlankNode::IncreaseBy(const SmToken &rToken) 3038 { 3039 switch(rToken.eType) 3040 { 3041 case TBLANK: nNum += 4; break; 3042 case TSBLANK: nNum += 1; break; 3043 default: 3044 break; 3045 } 3046 } 3047 3048 3049 void SmBlankNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) 3050 { 3051 SmNode::Prepare(rFormat, rDocShell); 3052 3053 //! hier muss/sollte es lediglich nicht der StarMath Font sein, 3054 //! damit fuer das in Arrange verwendete Zeichen ein "normales" 3055 //! (ungecliptes) Rechteck erzeugt wird. 3056 GetFont() = rFormat.GetFont(FNT_VARIABLE); 3057 3058 Flags() |= FLG_FONT | FLG_BOLD | FLG_ITALIC; 3059 } 3060 3061 3062 void SmBlankNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat) 3063 { 3064 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True); 3065 aTmpDev.SetFont(GetFont()); 3066 3067 // Abstand von der Fonthoehe abhaengig machen 3068 // (damit er beim skalieren (zB size *2 {a ~ b}) mitwaechst) 3069 long nDist = GetFont().GetSize().Height() / 10L, 3070 nSpace = nNum * nDist; 3071 3072 // ein SmRect mit Baseline und allem drum und dran besorgen 3073 SmRect::operator = (SmRect(aTmpDev, &rFormat, XubString(xub_Unicode(' ')), 3074 GetFont().GetBorderWidth())); 3075 3076 // und dieses auf die gewuenschte Breite bringen 3077 SetItalicSpaces(0, 0); 3078 SetWidth(nSpace); 3079 } 3080 3081 3082 3083