Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / svdraw / svdotxtr.cxx
blob1454bc52f946b0dacc5636d24bee428e8a74ffcd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdotext.hxx>
22 #include <svx/svdtrans.hxx>
23 #include <svx/svdogrp.hxx>
24 #include <svx/svdopath.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svdmodel.hxx>
27 #include <sdr/properties/itemsettools.hxx>
28 #include <svx/sdr/properties/properties.hxx>
29 #include <basegfx/polygon/b2dpolypolygontools.hxx>
30 #include <svl/itemset.hxx>
31 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
32 #include <svx/sdr/contact/viewcontact.hxx>
33 #include <svx/xfillit0.hxx>
34 #include <svx/xflclit.hxx>
35 #include <svx/xlineit0.hxx>
36 #include <svx/xlnclit.hxx>
37 #include <svx/xlnwtit.hxx>
38 #include <svx/sdshitm.hxx>
39 #include <unotools/configmgr.hxx>
41 using namespace com::sun::star;
43 void SdrTextObj::NbcSetSnapRect(const tools::Rectangle& rRect)
45 if (maGeo.nRotationAngle || maGeo.nShearAngle)
47 // Either the rotation or shear angle exists.
48 tools::Rectangle aSR0(GetSnapRect());
49 tools::Long nWdt0=aSR0.Right()-aSR0.Left();
50 tools::Long nHgt0=aSR0.Bottom()-aSR0.Top();
51 tools::Long nWdt1=rRect.Right()-rRect.Left();
52 tools::Long nHgt1=rRect.Bottom()-rRect.Top();
53 SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
54 SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
56 else
58 // No rotation or shear.
60 setRectangle(rRect);
61 ImpJustifyRect(maRectangle);
63 AdaptTextMinSize();
65 ImpCheckShear();
66 SetBoundAndSnapRectsDirty();
70 const tools::Rectangle& SdrTextObj::GetLogicRect() const
72 return getRectangle();
75 void SdrTextObj::NbcSetLogicRect(const tools::Rectangle& rRect)
77 setRectangle(rRect);
78 ImpJustifyRect(maRectangle);
80 AdaptTextMinSize();
82 SetBoundAndSnapRectsDirty();
85 Degree100 SdrTextObj::GetRotateAngle() const
87 return maGeo.nRotationAngle;
90 Degree100 SdrTextObj::GetShearAngle(bool /*bVertical*/) const
92 return maGeo.nShearAngle;
95 void SdrTextObj::NbcMove(const Size& rSize)
97 moveRectangle(rSize.Width(), rSize.Height());
98 moveOutRectangle(rSize.Width(), rSize.Height());
99 maSnapRect.Move(rSize);
100 SetBoundAndSnapRectsDirty(true);
103 void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
105 bool bNotSheared=maGeo.nShearAngle==0_deg100;
106 bool bRotate90=bNotSheared && maGeo.nRotationAngle.get() % 9000 ==0;
107 bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
108 bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
109 if (bXMirr || bYMirr) {
110 Point aRef1(GetSnapRect().Center());
111 if (bXMirr) {
112 Point aRef2(aRef1);
113 aRef2.AdjustY( 1 );
114 NbcMirrorGluePoints(aRef1,aRef2);
116 if (bYMirr) {
117 Point aRef2(aRef1);
118 aRef2.AdjustX( 1 );
119 NbcMirrorGluePoints(aRef1,aRef2);
123 if (maGeo.nRotationAngle==0_deg100 && maGeo.nShearAngle==0_deg100) {
124 auto aRectangle = getRectangle();
125 ResizeRect(aRectangle, rRef, xFact, yFact);
126 setRectangle(aRectangle);
127 if (bYMirr)
129 maRectangle.Normalize();
130 moveRectangle(aRectangle.Right() - aRectangle.Left(), aRectangle.Bottom() - aRectangle.Top());
131 maGeo.nRotationAngle=18000_deg100;
132 maGeo.RecalcSinCos();
135 else
137 tools::Polygon aPol(Rect2Poly(getRectangle(), maGeo));
139 for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
141 ResizePoint(aPol[a], rRef, xFact, yFact);
144 if(bXMirr != bYMirr)
146 // turn polygon and move it a little
147 tools::Polygon aPol0(aPol);
149 aPol[0] = aPol0[1];
150 aPol[1] = aPol0[0];
151 aPol[2] = aPol0[3];
152 aPol[3] = aPol0[2];
153 aPol[4] = aPol0[1];
155 tools::Rectangle aRectangle = svx::polygonToRectangle(aPol, maGeo);
156 setRectangle(aRectangle);
159 if (bRotate90) {
160 bool bRota90=maGeo.nRotationAngle.get() % 9000 ==0;
161 if (!bRota90) { // there's seems to be a rounding error occurring: correct it
162 Degree100 a=NormAngle36000(maGeo.nRotationAngle);
163 if (a<4500_deg100) a=0_deg100;
164 else if (a<13500_deg100) a=9000_deg100;
165 else if (a<22500_deg100) a=18000_deg100;
166 else if (a<31500_deg100) a=27000_deg100;
167 else a=0_deg100;
168 maGeo.nRotationAngle=a;
169 maGeo.RecalcSinCos();
171 if (bNotSheared!=(maGeo.nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear
172 maGeo.nShearAngle=0_deg100;
173 maGeo.RecalcTan();
177 ImpJustifyRect(maRectangle);
179 AdaptTextMinSize();
181 if(mbTextFrame && !getSdrModelFromSdrObject().IsPasteResize())
183 NbcAdjustTextFrameWidthAndHeight();
186 ImpCheckShear();
187 SetBoundAndSnapRectsDirty();
190 void SdrTextObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
192 SetGlueReallyAbsolute(true);
193 tools::Long dx = getRectangle().Right() - getRectangle().Left();
194 tools::Long dy = getRectangle().Bottom() - getRectangle().Top();
195 Point aPoint1(getRectangle().TopLeft());
196 RotatePoint(aPoint1, rRef, sn, cs);
197 Point aPoint2(aPoint1.X() + dx, aPoint1.Y() + dy);
198 tools::Rectangle aRectangle(aPoint1, aPoint2);
199 setRectangle(aRectangle);
201 if (maGeo.nRotationAngle==0_deg100) {
202 maGeo.nRotationAngle=NormAngle36000(nAngle);
203 maGeo.mfSinRotationAngle=sn;
204 maGeo.mfCosRotationAngle=cs;
205 } else {
206 maGeo.nRotationAngle=NormAngle36000(maGeo.nRotationAngle+nAngle);
207 maGeo.RecalcSinCos();
209 SetBoundAndSnapRectsDirty();
210 NbcRotateGluePoints(rRef,nAngle,sn,cs);
211 SetGlueReallyAbsolute(false);
214 void SdrTextObj::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
216 SetGlueReallyAbsolute(true);
218 // when this is a SdrPathObj, aRect may be uninitialized
219 tools::Polygon aPol(Rect2Poly(getRectangle().IsEmpty() ? GetSnapRect() : getRectangle(), maGeo));
221 sal_uInt16 nPointCount=aPol.GetSize();
222 for (sal_uInt16 i=0; i<nPointCount; i++) {
223 ShearPoint(aPol[i],rRef,tn,bVShear);
225 tools::Rectangle aRectangle = svx::polygonToRectangle(aPol, maGeo);
226 setRectangle(aRectangle);
227 ImpJustifyRect(maRectangle);
229 if (mbTextFrame) {
230 NbcAdjustTextFrameWidthAndHeight();
232 ImpCheckShear();
233 SetBoundAndSnapRectsDirty();
234 NbcShearGluePoints(rRef,tn,bVShear);
235 SetGlueReallyAbsolute(false);
238 void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
240 SetGlueReallyAbsolute(true);
241 bool bNotSheared=maGeo.nShearAngle==0_deg100;
242 bool bRotate90 = false;
243 if (bNotSheared &&
244 (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
245 std::abs(rRef1.X()-rRef2.X())==std::abs(rRef1.Y()-rRef2.Y()))) {
246 bRotate90=maGeo.nRotationAngle.get() % 9000 ==0;
248 tools::Polygon aPol(Rect2Poly(getRectangle(),maGeo));
249 sal_uInt16 i;
250 sal_uInt16 nPointCount=aPol.GetSize();
251 for (i=0; i<nPointCount; i++) {
252 MirrorPoint(aPol[i],rRef1,rRef2);
254 // turn polygon and move it a little
255 tools::Polygon aPol0(aPol);
256 aPol[0]=aPol0[1];
257 aPol[1]=aPol0[0];
258 aPol[2]=aPol0[3];
259 aPol[3]=aPol0[2];
260 aPol[4]=aPol0[1];
261 tools::Rectangle aRectangle = svx::polygonToRectangle(aPol, maGeo);
262 setRectangle(aRectangle);
264 if (bRotate90) {
265 bool bRota90=maGeo.nRotationAngle.get() % 9000 ==0;
266 if (bRotate90 && !bRota90) { // there's seems to be a rounding error occurring: correct it
267 Degree100 a=NormAngle36000(maGeo.nRotationAngle);
268 if (a<4500_deg100) a=0_deg100;
269 else if (a<13500_deg100) a=9000_deg100;
270 else if (a<22500_deg100) a=18000_deg100;
271 else if (a<31500_deg100) a=27000_deg100;
272 else a=0_deg100;
273 maGeo.nRotationAngle=a;
274 maGeo.RecalcSinCos();
277 if (bNotSheared!=(maGeo.nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear
278 maGeo.nShearAngle=0_deg100;
279 maGeo.RecalcTan();
282 ImpJustifyRect(maRectangle);
283 if (mbTextFrame) {
284 NbcAdjustTextFrameWidthAndHeight();
286 ImpCheckShear();
287 SetBoundAndSnapRectsDirty();
288 NbcMirrorGluePoints(rRef1,rRef2);
289 SetGlueReallyAbsolute(false);
293 rtl::Reference<SdrObject> SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
295 rtl::Reference<SdrObject> pRetval;
297 if(!ImpCanConvTextToCurve())
299 // suppress HelpTexts from PresObj's
300 return nullptr;
303 // create an extractor with neutral ViewInformation
304 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
305 drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
307 // extract text as polygons
308 GetViewContact().getViewIndependentPrimitive2DContainer(aExtractor);
310 // get results
311 const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
312 const sal_uInt32 nResultCount(rResult.size());
314 if(nResultCount)
316 // prepare own target
317 rtl::Reference<SdrObjGroup> pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
318 SdrObjList* pObjectList = pGroup->GetSubList();
320 // process results
321 for(sal_uInt32 a(0); a < nResultCount; a++)
323 const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
324 basegfx::B2DPolyPolygon aPolyPolygon(rCandidate.getB2DPolyPolygon());
326 if(aPolyPolygon.count())
328 // take care of wanted polygon type
329 if(bToPoly)
331 if(aPolyPolygon.areControlPointsUsed())
333 aPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(aPolyPolygon);
336 else
338 if(!aPolyPolygon.areControlPointsUsed())
340 aPolyPolygon = basegfx::utils::expandToCurve(aPolyPolygon);
344 // create ItemSet with object attributes
345 SfxItemSet aAttributeSet(GetObjectItemSet());
346 rtl::Reference<SdrPathObj> pPathObj;
348 // always clear objectshadow; this is included in the extraction
349 aAttributeSet.Put(makeSdrShadowItem(false));
351 if(rCandidate.getIsFilled())
353 // set needed items
354 aAttributeSet.Put(XFillColorItem(OUString(), Color(rCandidate.getBColor())));
355 aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
356 aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
358 // create filled SdrPathObj
359 pPathObj = new SdrPathObj(
360 getSdrModelFromSdrObject(),
361 SdrObjKind::PathFill,
362 aPolyPolygon);
364 else
366 // set needed items
367 aAttributeSet.Put(XLineColorItem(OUString(), Color(rCandidate.getBColor())));
368 aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
369 aAttributeSet.Put(XLineWidthItem(0));
370 aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
372 // create line SdrPathObj
373 pPathObj = new SdrPathObj(
374 getSdrModelFromSdrObject(),
375 SdrObjKind::PathLine,
376 std::move(aPolyPolygon));
379 // copy basic information from original
380 pPathObj->ImpSetAnchorPos(GetAnchorPos());
381 pPathObj->NbcSetLayer(GetLayer());
382 pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
384 // apply prepared ItemSet and add to target
385 pPathObj->SetMergedItemSet(aAttributeSet);
386 pObjectList->InsertObject(pPathObj.get());
390 // postprocess; if no result and/or only one object, simplify
391 if(!pObjectList->GetObjCount())
393 pGroup.clear();
395 else if(1 == pObjectList->GetObjCount())
397 pRetval = pObjectList->RemoveObject(0);
398 pGroup.clear();
400 else
402 pRetval = pGroup;
406 return pRetval;
410 rtl::Reference<SdrObject> SdrTextObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
412 if(bAddText)
414 return ImpConvertContainedTextToSdrPathObjs(!bBezier);
417 return nullptr;
420 bool SdrTextObj::ImpCanConvTextToCurve() const
422 return !IsOutlText() && !utl::ConfigManager::IsFuzzing();
425 rtl::Reference<SdrPathObj> SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed, bool bBezier) const
427 SdrObjKind ePathKind = bClosed ? SdrObjKind::PathFill : SdrObjKind::PathLine;
428 basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
430 // #i37011#
431 if(!bBezier)
433 aB2DPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(aB2DPolyPolygon);
434 ePathKind = bClosed ? SdrObjKind::Polygon : SdrObjKind::PolyLine;
437 rtl::Reference<SdrPathObj> pPathObj(new SdrPathObj(
438 getSdrModelFromSdrObject(),
439 ePathKind,
440 std::move(aB2DPolyPolygon)));
442 if(bBezier)
444 // create bezier curves
445 pPathObj->SetPathPoly(basegfx::utils::expandToCurve(pPathObj->GetPathPoly()));
448 pPathObj->ImpSetAnchorPos(m_aAnchor);
449 pPathObj->NbcSetLayer(GetLayer());
450 sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
451 pPathObj->ClearMergedItem();
452 pPathObj->SetMergedItemSet(GetObjectItemSet());
453 pPathObj->GetProperties().BroadcastItemChange(aC);
454 pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
456 return pPathObj;
459 rtl::Reference<SdrObject> SdrTextObj::ImpConvertAddText(rtl::Reference<SdrObject> pObj, bool bBezier) const
461 if(!ImpCanConvTextToCurve())
463 return pObj;
466 rtl::Reference<SdrObject> pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
468 if(!pText)
470 return pObj;
473 if(!pObj)
475 return pText;
478 if(pText->IsGroupObject())
480 // is already group object, add partial shape in front
481 SdrObjList* pOL=pText->GetSubList();
482 pOL->InsertObject(pObj.get(),0);
484 return pText;
486 else
488 // not yet a group, create one and add partial and new shapes
489 rtl::Reference<SdrObjGroup> pGrp(new SdrObjGroup(getSdrModelFromSdrObject()));
490 SdrObjList* pOL=pGrp->GetSubList();
491 pOL->InsertObject(pObj.get());
492 pOL->InsertObject(pText.get());
494 return pGrp;
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */