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 27 #include <svx/svdotext.hxx> 28 #include "svx/svditext.hxx" 29 #include <svx/svdtrans.hxx> 30 #include <svx/svdogrp.hxx> 31 #include <svx/svdopath.hxx> 32 #include <svx/svdoutl.hxx> 33 #include <svx/svdpage.hxx> // fuer Convert 34 #include <svx/svdmodel.hxx> // fuer Convert 35 #include <editeng/outliner.hxx> 36 #include <svx/sdr/properties/itemsettools.hxx> 37 #include <svx/sdr/properties/properties.hxx> 38 #include <basegfx/polygon/b2dpolypolygontools.hxx> 39 #include <svl/itemset.hxx> 40 #include <svx/svditer.hxx> 41 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx> 42 #include <svx/sdr/contact/viewcontact.hxx> 43 #include <svx/xflclit.hxx> 44 #include <svx/xlnclit.hxx> 45 #include <svx/xlnwtit.hxx> 46 47 //////////////////////////////////////////////////////////////////////////////////////////////////// 48 // 49 // @@@@@@ @@@@@ @@ @@ @@@@@@ @@@@ @@@@@ @@@@@@ 50 // @@ @@ @@@ @@@ @@ @@ @@ @@ @@ @@ 51 // @@ @@ @@@@@ @@ @@ @@ @@ @@ @@ 52 // @@ @@@@ @@@ @@ @@ @@ @@@@@ @@ 53 // @@ @@ @@@@@ @@ @@ @@ @@ @@ @@ 54 // @@ @@ @@@ @@@ @@ @@ @@ @@ @@ @@ @@ 55 // @@ @@@@@ @@ @@ @@ @@@@ @@@@@ @@@@ 56 // 57 // Transformationen 58 // 59 //////////////////////////////////////////////////////////////////////////////////////////////////// 60 61 void SdrTextObj::NbcSetSnapRect(const Rectangle& rRect) 62 { 63 if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0) { 64 Rectangle aSR0(GetSnapRect()); 65 long nWdt0=aSR0.Right()-aSR0.Left(); 66 long nHgt0=aSR0.Bottom()-aSR0.Top(); 67 long nWdt1=rRect.Right()-rRect.Left(); 68 long nHgt1=rRect.Bottom()-rRect.Top(); 69 SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0)); 70 SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top())); 71 } else { 72 long nHDist=GetTextLeftDistance()+GetTextRightDistance(); 73 long nVDist=GetTextUpperDistance()+GetTextLowerDistance(); 74 long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0; 75 long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0; 76 long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0; 77 long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0; 78 aRect=rRect; 79 ImpJustifyRect(aRect); 80 if (bTextFrame && (pModel==NULL || !pModel->IsPasteResize())) { // #51139# 81 if (nTWdt0!=nTWdt1 && IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1); 82 if (nTHgt0!=nTHgt1 && IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1); 83 if (GetFitToSize()) 84 { 85 NbcResizeTextAttributes(Fraction(nTWdt1,nTWdt0),Fraction(nTHgt1,nTHgt0)); 86 } 87 NbcAdjustTextFrameWidthAndHeight(); 88 } 89 ImpCheckShear(); 90 SetRectsDirty(); 91 } 92 } 93 94 const Rectangle& SdrTextObj::GetLogicRect() const 95 { 96 return aRect; 97 } 98 99 void SdrTextObj::NbcSetLogicRect(const Rectangle& rRect) 100 { 101 long nHDist=GetTextLeftDistance()+GetTextRightDistance(); 102 long nVDist=GetTextUpperDistance()+GetTextLowerDistance(); 103 long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0; 104 long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0; 105 long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0; 106 long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0; 107 aRect=rRect; 108 ImpJustifyRect(aRect); 109 if (bTextFrame) { 110 if (nTWdt0!=nTWdt1 && IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1); 111 if (nTHgt0!=nTHgt1 && IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1); 112 if (GetFitToSize()) 113 { 114 NbcResizeTextAttributes(Fraction(nTWdt1,nTWdt0),Fraction(nTHgt1,nTHgt0)); 115 } 116 NbcAdjustTextFrameWidthAndHeight(); 117 } 118 SetRectsDirty(); 119 } 120 121 long SdrTextObj::GetRotateAngle() const 122 { 123 return aGeo.nDrehWink; 124 } 125 126 long SdrTextObj::GetShearAngle(FASTBOOL /*bVertical*/) const 127 { 128 return aGeo.nShearWink; 129 } 130 131 void SdrTextObj::NbcMove(const Size& rSiz) 132 { 133 MoveRect(aRect,rSiz); 134 MoveRect(aOutRect,rSiz); 135 MoveRect(maSnapRect,rSiz); 136 SetRectsDirty(sal_True); 137 } 138 139 void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) 140 { 141 FASTBOOL bNoShearMerk=aGeo.nShearWink==0; 142 FASTBOOL bRota90Merk=bNoShearMerk && aGeo.nDrehWink % 9000 ==0; 143 long nHDist=GetTextLeftDistance()+GetTextRightDistance(); 144 long nVDist=GetTextUpperDistance()+GetTextLowerDistance(); 145 long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0; 146 long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0; 147 FASTBOOL bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0); 148 FASTBOOL bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0); 149 if (bXMirr || bYMirr) { 150 Point aRef1(GetSnapRect().Center()); 151 if (bXMirr) { 152 Point aRef2(aRef1); 153 aRef2.Y()++; 154 NbcMirrorGluePoints(aRef1,aRef2); 155 } 156 if (bYMirr) { 157 Point aRef2(aRef1); 158 aRef2.X()++; 159 NbcMirrorGluePoints(aRef1,aRef2); 160 } 161 } 162 163 if (aGeo.nDrehWink==0 && aGeo.nShearWink==0) { 164 ResizeRect(aRect,rRef,xFact,yFact); 165 if (bYMirr) { 166 aRect.Justify(); 167 aRect.Move(aRect.Right()-aRect.Left(),aRect.Bottom()-aRect.Top()); 168 aGeo.nDrehWink=18000; 169 aGeo.RecalcSinCos(); 170 } 171 } 172 else 173 { 174 // #100663# aRect is NOT initialized for lines (polgon objects with two 175 // exceptionally handled points). Thus, after this call the text rotaion is 176 // gone. This error must be present since day one of this old drawing layer. 177 // It's astonishing that noone discovered it earlier. 178 // Polygon aPol(Rect2Poly(aRect,aGeo)); 179 // Polygon aPol(Rect2Poly(GetSnapRect(), aGeo)); 180 181 // #101412# go back to old method, side effects are impossible 182 // to calculate. 183 Polygon aPol(Rect2Poly(aRect,aGeo)); 184 185 for(sal_uInt16 a(0); a < aPol.GetSize(); a++) 186 { 187 ResizePoint(aPol[a], rRef, xFact, yFact); 188 } 189 190 if(bXMirr != bYMirr) 191 { 192 // Polygon wenden und etwas schieben 193 Polygon aPol0(aPol); 194 195 aPol[0] = aPol0[1]; 196 aPol[1] = aPol0[0]; 197 aPol[2] = aPol0[3]; 198 aPol[3] = aPol0[2]; 199 aPol[4] = aPol0[1]; 200 } 201 202 Poly2Rect(aPol, aRect, aGeo); 203 } 204 205 if (bRota90Merk) { 206 FASTBOOL bRota90=aGeo.nDrehWink % 9000 ==0; 207 if (!bRota90) { // Scheinbar Rundungsfehler: Korregieren 208 long a=NormAngle360(aGeo.nDrehWink); 209 if (a<4500) a=0; 210 else if (a<13500) a=9000; 211 else if (a<22500) a=18000; 212 else if (a<31500) a=27000; 213 else a=0; 214 aGeo.nDrehWink=a; 215 aGeo.RecalcSinCos(); 216 } 217 if (bNoShearMerk!=(aGeo.nShearWink==0)) { // Shear ggf. korregieren wg. Rundungsfehler 218 aGeo.nShearWink=0; 219 aGeo.RecalcTan(); 220 } 221 } 222 223 ImpJustifyRect(aRect); 224 long nTWdt1=aRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0; 225 long nTHgt1=aRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0; 226 if (bTextFrame && (pModel==NULL || !pModel->IsPasteResize())) { // #51139# 227 if (nTWdt0!=nTWdt1 && IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1); 228 if (nTHgt0!=nTHgt1 && IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1); 229 if (GetFitToSize()) 230 { 231 NbcResizeTextAttributes(Fraction(nTWdt1,nTWdt0),Fraction(nTHgt1,nTHgt0)); 232 } 233 NbcAdjustTextFrameWidthAndHeight(); 234 } 235 ImpCheckShear(); 236 SetRectsDirty(); 237 } 238 239 void SdrTextObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs) 240 { 241 SetGlueReallyAbsolute(sal_True); 242 long dx=aRect.Right()-aRect.Left(); 243 long dy=aRect.Bottom()-aRect.Top(); 244 Point aP(aRect.TopLeft()); 245 RotatePoint(aP,rRef,sn,cs); 246 aRect.Left()=aP.X(); 247 aRect.Top()=aP.Y(); 248 aRect.Right()=aRect.Left()+dx; 249 aRect.Bottom()=aRect.Top()+dy; 250 if (aGeo.nDrehWink==0) { 251 aGeo.nDrehWink=NormAngle360(nWink); 252 aGeo.nSin=sn; 253 aGeo.nCos=cs; 254 } else { 255 aGeo.nDrehWink=NormAngle360(aGeo.nDrehWink+nWink); 256 aGeo.RecalcSinCos(); 257 } 258 SetRectsDirty(); 259 NbcRotateGluePoints(rRef,nWink,sn,cs); 260 SetGlueReallyAbsolute(sal_False); 261 } 262 263 void SdrTextObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear) 264 { 265 SetGlueReallyAbsolute(sal_True); 266 267 // #75889# when this is a SdrPathObj aRect maybe not initialized 268 Polygon aPol(Rect2Poly(aRect.IsEmpty() ? GetSnapRect() : aRect, aGeo)); 269 270 sal_uInt16 nPointCount=aPol.GetSize(); 271 for (sal_uInt16 i=0; i<nPointCount; i++) { 272 ShearPoint(aPol[i],rRef,tn,bVShear); 273 } 274 Poly2Rect(aPol,aRect,aGeo); 275 ImpJustifyRect(aRect); 276 if (bTextFrame) { 277 NbcAdjustTextFrameWidthAndHeight(); 278 } 279 ImpCheckShear(); 280 SetRectsDirty(); 281 NbcShearGluePoints(rRef,nWink,tn,bVShear); 282 SetGlueReallyAbsolute(sal_False); 283 } 284 285 void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2) 286 { 287 SetGlueReallyAbsolute(sal_True); 288 FASTBOOL bNoShearMerk=aGeo.nShearWink==0; 289 FASTBOOL bRota90Merk=sal_False; 290 if (bNoShearMerk && 291 (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() || 292 Abs(rRef1.X()-rRef2.X())==Abs(rRef1.Y()-rRef2.Y()))) { 293 bRota90Merk=aGeo.nDrehWink % 9000 ==0; 294 } 295 Polygon aPol(Rect2Poly(aRect,aGeo)); 296 sal_uInt16 i; 297 sal_uInt16 nPntAnz=aPol.GetSize(); 298 for (i=0; i<nPntAnz; i++) { 299 MirrorPoint(aPol[i],rRef1,rRef2); 300 } 301 // Polygon wenden und etwas schieben 302 Polygon aPol0(aPol); 303 aPol[0]=aPol0[1]; 304 aPol[1]=aPol0[0]; 305 aPol[2]=aPol0[3]; 306 aPol[3]=aPol0[2]; 307 aPol[4]=aPol0[1]; 308 Poly2Rect(aPol,aRect,aGeo); 309 310 if (bRota90Merk) { 311 FASTBOOL bRota90=aGeo.nDrehWink % 9000 ==0; 312 if (bRota90Merk && !bRota90) { // Scheinbar Rundungsfehler: Korregieren 313 long a=NormAngle360(aGeo.nDrehWink); 314 if (a<4500) a=0; 315 else if (a<13500) a=9000; 316 else if (a<22500) a=18000; 317 else if (a<31500) a=27000; 318 else a=0; 319 aGeo.nDrehWink=a; 320 aGeo.RecalcSinCos(); 321 } 322 } 323 if (bNoShearMerk!=(aGeo.nShearWink==0)) { // Shear ggf. korregieren wg. Rundungsfehler 324 aGeo.nShearWink=0; 325 aGeo.RecalcTan(); 326 } 327 328 ImpJustifyRect(aRect); 329 if (bTextFrame) { 330 NbcAdjustTextFrameWidthAndHeight(); 331 } 332 ImpCheckShear(); 333 SetRectsDirty(); 334 NbcMirrorGluePoints(rRef1,rRef2); 335 SetGlueReallyAbsolute(sal_False); 336 } 337 338 ////////////////////////////////////////////////////////////////////////////// 339 340 SdrObject* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const 341 { 342 SdrObject* pRetval = 0; 343 344 if(!ImpCanConvTextToCurve()) 345 { 346 // suppress HelpTexts from PresObj's 347 return 0; 348 } 349 350 // get primitives 351 const drawinglayer::primitive2d::Primitive2DSequence xSequence(GetViewContact().getViewIndependentPrimitive2DSequence()); 352 353 if(xSequence.hasElements()) 354 { 355 // create an extractor with neutral ViewInformation 356 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 357 drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D); 358 359 // extract text as polygons 360 aExtractor.process(xSequence); 361 362 // get results 363 const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget(); 364 const sal_uInt32 nResultCount(rResult.size()); 365 366 if(nResultCount) 367 { 368 // prepare own target 369 SdrObjGroup* pGroup = new SdrObjGroup(); 370 SdrObjList* pObjectList = pGroup->GetSubList(); 371 372 // process results 373 for(sal_uInt32 a(0); a < nResultCount; a++) 374 { 375 const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a]; 376 basegfx::B2DPolyPolygon aPolyPolygon(rCandidate.getB2DPolyPolygon()); 377 378 if(aPolyPolygon.count()) 379 { 380 // take care of wanted polygon type 381 if(bToPoly) 382 { 383 if(aPolyPolygon.areControlPointsUsed()) 384 { 385 aPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon); 386 } 387 } 388 else 389 { 390 if(!aPolyPolygon.areControlPointsUsed()) 391 { 392 aPolyPolygon = basegfx::tools::expandToCurve(aPolyPolygon); 393 } 394 } 395 396 // create ItemSet with object attributes 397 SfxItemSet aAttributeSet(GetObjectItemSet()); 398 SdrPathObj* pPathObj = 0; 399 400 // always clear objectshadow; this is included in the extraction 401 aAttributeSet.Put(SdrShadowItem(false)); 402 403 if(rCandidate.getIsFilled()) 404 { 405 // set needed items 406 aAttributeSet.Put(XFillColorItem(String(), Color(rCandidate.getBColor()))); 407 aAttributeSet.Put(XLineStyleItem(XLINE_NONE)); 408 aAttributeSet.Put(XFillStyleItem(XFILL_SOLID)); 409 410 // create filled SdrPathObj 411 pPathObj = new SdrPathObj(OBJ_PATHFILL, aPolyPolygon); 412 } 413 else 414 { 415 // set needed items 416 aAttributeSet.Put(XLineColorItem(String(), Color(rCandidate.getBColor()))); 417 aAttributeSet.Put(XLineStyleItem(XLINE_SOLID)); 418 aAttributeSet.Put(XLineWidthItem(0)); 419 aAttributeSet.Put(XFillStyleItem(XFILL_NONE)); 420 421 // create line SdrPathObj 422 pPathObj = new SdrPathObj(OBJ_PATHLINE, aPolyPolygon); 423 } 424 425 // copy basic information from original 426 pPathObj->ImpSetAnchorPos(GetAnchorPos()); 427 pPathObj->NbcSetLayer(GetLayer()); 428 429 if(GetModel()) 430 { 431 pPathObj->SetModel(GetModel()); 432 pPathObj->NbcSetStyleSheet(GetStyleSheet(), true); 433 } 434 435 // apply prepared ItemSet and add to target 436 pPathObj->SetMergedItemSet(aAttributeSet); 437 pObjectList->InsertObject(pPathObj); 438 } 439 } 440 441 // postprocess; if no result and/or only one object, simplify 442 if(!pObjectList->GetObjCount()) 443 { 444 delete pGroup; 445 } 446 else if(1 == pObjectList->GetObjCount()) 447 { 448 pRetval = pObjectList->RemoveObject(0); 449 delete pGroup; 450 } 451 else 452 { 453 pRetval = pGroup; 454 } 455 } 456 } 457 458 return pRetval; 459 } 460 461 ////////////////////////////////////////////////////////////////////////////// 462 463 SdrObject* SdrTextObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const 464 { 465 if(bAddText) 466 { 467 return ImpConvertContainedTextToSdrPathObjs(!bBezier); 468 } 469 470 return 0; 471 } 472 473 bool SdrTextObj::ImpCanConvTextToCurve() const 474 { 475 return !IsOutlText(); 476 } 477 478 SdrObject* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, sal_Bool bClosed, sal_Bool bBezier, sal_Bool bNoSetAttr) const 479 { 480 SdrObjKind ePathKind = bClosed ? OBJ_PATHFILL : OBJ_PATHLINE; 481 basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon); 482 483 // #i37011# 484 if(!bBezier) 485 { 486 aB2DPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon); 487 ePathKind = bClosed ? OBJ_POLY : OBJ_PLIN; 488 } 489 490 SdrPathObj* pPathObj = new SdrPathObj(ePathKind, aB2DPolyPolygon); 491 492 if(bBezier) 493 { 494 // create bezier curves 495 pPathObj->SetPathPoly(basegfx::tools::expandToCurve(pPathObj->GetPathPoly())); 496 } 497 498 if(pPathObj) 499 { 500 pPathObj->ImpSetAnchorPos(aAnchor); 501 pPathObj->NbcSetLayer(SdrLayerID(GetLayer())); 502 503 if(pModel) 504 { 505 pPathObj->SetModel(pModel); 506 507 if(!bNoSetAttr) 508 { 509 sdr::properties::ItemChangeBroadcaster aC(*pPathObj); 510 511 pPathObj->ClearMergedItem(); 512 pPathObj->SetMergedItemSet(GetObjectItemSet()); 513 pPathObj->GetProperties().BroadcastItemChange(aC); 514 pPathObj->NbcSetStyleSheet(GetStyleSheet(), sal_True); 515 } 516 } 517 } 518 519 return pPathObj; 520 } 521 522 SdrObject* SdrTextObj::ImpConvertAddText(SdrObject* pObj, FASTBOOL bBezier) const 523 { 524 if(!ImpCanConvTextToCurve()) 525 { 526 return pObj; 527 } 528 529 SdrObject* pText = ImpConvertContainedTextToSdrPathObjs(!bBezier); 530 531 if(!pText) 532 { 533 return pObj; 534 } 535 536 if(!pObj) 537 { 538 return pText; 539 } 540 541 if(pText->IsGroupObject()) 542 { 543 // is already group object, add partial shape in front 544 SdrObjList* pOL=pText->GetSubList(); 545 pOL->InsertObject(pObj,0); 546 547 return pText; 548 } 549 else 550 { 551 // not yet a group, create one and add partial and new shapes 552 SdrObjGroup* pGrp=new SdrObjGroup; 553 SdrObjList* pOL=pGrp->GetSubList(); 554 pOL->InsertObject(pObj); 555 pOL->InsertObject(pText); 556 557 return pGrp; 558 } 559 } 560 561 ////////////////////////////////////////////////////////////////////////////// 562 // eof 563