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