LibreOffice Module svx (master)  1
svdpdf.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <svdpdf.hxx>
21 
22 #include <config_features.h>
23 
24 #if HAVE_FEATURE_PDFIUM
25 #include <fpdfview.h>
26 #include <fpdf_edit.h>
27 #include <fpdf_text.h>
28 
29 #include <vcl/graph.hxx>
31 
32 #include <math.h>
33 #include <editeng/eeitem.hxx>
34 #include <editeng/fhgtitem.hxx>
35 #include <editeng/wghtitem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/udlnitem.hxx>
39 #include <editeng/shdditem.hxx>
40 #include <svx/xlnclit.hxx>
41 #include <svx/xlncapit.hxx>
42 #include <svx/xlnwtit.hxx>
43 #include <svx/xflclit.hxx>
44 #include <editeng/fontitem.hxx>
45 #include <editeng/wrlmitem.hxx>
46 #include <editeng/contouritem.hxx>
47 #include <editeng/colritem.hxx>
48 #include <vcl/metric.hxx>
50 #include <svx/sdtditm.hxx>
51 #include <svx/sdtagitm.hxx>
52 #include <svx/sdtfsitm.hxx>
53 #include <svx/svdmodel.hxx>
54 #include <svx/svdpage.hxx>
55 #include <svx/svdobj.hxx>
56 #include <svx/svdotext.hxx>
57 #include <svx/svdorect.hxx>
58 #include <svx/svdograf.hxx>
59 #include <svx/svdopath.hxx>
60 #include <svx/svdetc.hxx>
61 #include <svl/itemset.hxx>
63 #include <tools/helpers.hxx>
66 #include <svx/xlinjoit.hxx>
67 #include <svx/xlndsit.hxx>
69 #include <svx/xbtmpit.hxx>
70 #include <svx/xfillit0.hxx>
71 #include <svx/xflbmtit.hxx>
72 #include <svx/xflbstit.hxx>
73 #include <svx/xlineit0.hxx>
75 #include <svx/svditer.hxx>
76 #include <svx/svdogrp.hxx>
77 #include <vcl/dibtools.hxx>
78 #include <sal/log.hxx>
79 
80 namespace
81 {
82 double sqrt2(double a, double b) { return sqrt(a * a + b * b); }
83 
84 struct FPDFBitmapDeleter
85 {
86  void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); }
87 };
88 }
89 
90 using namespace com::sun::star;
91 
92 ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools::Rectangle& rRect,
93  Graphic const& rGraphic)
94  : maTmpList()
95  , mpVD(VclPtr<VirtualDevice>::Create())
96  , maScaleRect(rRect)
97  , mnMapScalingOfs(0)
98  , mpModel(&rModel)
99  , mnLayer(nLay)
100  , maOldLineColor()
101  , mnLineWidth(0)
102  , maDash(css::drawing::DashStyle_RECT, 0, 0, 0, 0, 0)
103  , mbMov(false)
104  , mbSize(false)
105  , maOfs(0, 0)
106  , mfScaleX(1.0)
107  , mfScaleY(1.0)
108  , maScaleX(1.0)
109  , maScaleY(1.0)
110  , mbFntDirty(true)
111  , mbLastObjWasPolyWithoutLine(false)
112  , mbNoLine(false)
113  , mbNoFill(false)
114  , maClip()
115  , mnPageCount(0)
116  , mdPageHeightPts(0)
117  , mpPDFium(vcl::pdf::PDFiumLibrary::get())
118 {
119  mpVD->EnableOutput(false);
120  mpVD->SetLineColor();
121  mpVD->SetFillColor();
122  maOldLineColor.SetRed(mpVD->GetLineColor().GetRed() + 1);
123  mpLineAttr = std::make_unique<SfxItemSet>(rModel.GetItemPool(),
125  mpFillAttr = std::make_unique<SfxItemSet>(rModel.GetItemPool(),
127  mpTextAttr = std::make_unique<SfxItemSet>(rModel.GetItemPool(),
129  checkClip();
130 
131  // Load the buffer using pdfium.
132  auto const& rVectorGraphicData = rGraphic.getVectorGraphicData();
133  auto* pData = rVectorGraphicData->getVectorGraphicDataArray().getConstArray();
134  sal_Int32 nSize = rVectorGraphicData->getVectorGraphicDataArrayLength();
135  mpPdfDocument = mpPDFium->openDocument(pData, nSize);
136  if (!mpPdfDocument)
137  return;
138 
139  mnPageCount = mpPdfDocument->getPageCount();
140 }
141 
142 ImpSdrPdfImport::~ImpSdrPdfImport() = default;
143 
144 void ImpSdrPdfImport::DoObjects(SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport,
145  int nPageIndex)
146 {
147  const int nPageCount = mpPdfDocument->getPageCount();
148  if (nPageCount > 0 && nPageIndex >= 0 && nPageIndex < nPageCount)
149  {
150  // Render next page.
151  auto pPdfPage = mpPdfDocument->openPage(nPageIndex);
152  if (!pPdfPage)
153  return;
154 
155  basegfx::B2DSize dPageSize = mpPdfDocument->getPageSize(nPageIndex);
156 
157  const double dPageWidth = dPageSize.getX();
158  const double dPageHeight = dPageSize.getY();
159 
160  SetupPageScale(dPageWidth, dPageHeight);
161 
162  // Load the page text to extract it when we get text elements.
163  auto pTextPage = pPdfPage->getTextPage();
164 
165  const int nPageObjectCount = pPdfPage->getObjectCount();
166  if (pProgrInfo)
167  pProgrInfo->SetActionCount(nPageObjectCount);
168 
169  for (int nPageObjectIndex = 0; nPageObjectIndex < nPageObjectCount; ++nPageObjectIndex)
170  {
171  auto pPageObject = pPdfPage->getObject(nPageObjectIndex);
172  ImportPdfObject(pPageObject, pTextPage, nPageObjectIndex);
173  if (pProgrInfo && pActionsToReport)
174  {
175  (*pActionsToReport)++;
176 
177  if (*pActionsToReport >= 16)
178  {
179  if (!pProgrInfo->ReportActions(*pActionsToReport))
180  break;
181 
182  *pActionsToReport = 0;
183  }
184  }
185  }
186  }
187 }
188 
189 void ImpSdrPdfImport::SetupPageScale(const double dPageWidth, const double dPageHeight)
190 {
191  mfScaleX = mfScaleY = 1.0;
192 
193  // Store the page dimensions in Points.
194  mdPageHeightPts = dPageHeight;
195 
196  Size aPageSize(convertPointToMm100(dPageWidth), convertPointToMm100(dPageHeight));
197 
198  if (aPageSize.Width() && aPageSize.Height() && (!maScaleRect.IsEmpty()))
199  {
200  maOfs = maScaleRect.TopLeft();
201 
202  if (aPageSize.Width() != (maScaleRect.GetWidth() - 1))
203  {
204  mfScaleX = static_cast<double>(maScaleRect.GetWidth() - 1)
205  / static_cast<double>(aPageSize.Width());
206  }
207 
208  if (aPageSize.Height() != (maScaleRect.GetHeight() - 1))
209  {
210  mfScaleY = static_cast<double>(maScaleRect.GetHeight() - 1)
211  / static_cast<double>(aPageSize.Height());
212  }
213  }
214 
215  mbMov = maOfs.X() != 0 || maOfs.Y() != 0;
216  mbSize = false;
217  maScaleX = Fraction(1, 1);
218  maScaleY = Fraction(1, 1);
219 
220  if (aPageSize.Width() != (maScaleRect.GetWidth() - 1))
221  {
222  maScaleX = Fraction(maScaleRect.GetWidth() - 1, aPageSize.Width());
223  mbSize = true;
224  }
225 
226  if (aPageSize.Height() != (maScaleRect.GetHeight() - 1))
227  {
228  maScaleY = Fraction(maScaleRect.GetHeight() - 1, aPageSize.Height());
229  mbSize = true;
230  }
231 }
232 
233 size_t ImpSdrPdfImport::DoImport(SdrObjList& rOL, size_t nInsPos, int nPageNumber,
234  SvdProgressInfo* pProgrInfo)
235 {
236  sal_uInt32 nActionsToReport(0);
237 
238  // execute
239  DoObjects(pProgrInfo, &nActionsToReport, nPageNumber);
240 
241  if (pProgrInfo)
242  {
243  pProgrInfo->ReportActions(nActionsToReport);
244  nActionsToReport = 0;
245  }
246 
247  // MapMode scaling
248  MapScaling();
249 
250  // To calculate the progress meter, we use GetActionSize()*3.
251  // However, maTmpList has a lower entry count limit than GetActionSize(),
252  // so the actions that were assumed were too much have to be re-added.
253  // nActionsToReport = (rMtf.GetActionSize() - maTmpList.size()) * 2;
254 
255  // announce all currently unannounced rescales
256  if (pProgrInfo)
257  {
258  pProgrInfo->ReportRescales(nActionsToReport);
259  pProgrInfo->SetInsertCount(maTmpList.size());
260  }
261 
262  nActionsToReport = 0;
263 
264  // insert all objects cached in aTmpList now into rOL from nInsPos
265  nInsPos = std::min(nInsPos, rOL.GetObjCount());
266 
267  for (SdrObject* pObj : maTmpList)
268  {
269  rOL.NbcInsertObject(pObj, nInsPos);
270  nInsPos++;
271 
272  if (pProgrInfo)
273  {
274  nActionsToReport++;
275 
276  if (nActionsToReport >= 32) // update all 32 actions
277  {
278  pProgrInfo->ReportInserts(nActionsToReport);
279  nActionsToReport = 0;
280  }
281  }
282  }
283 
284  // report all remaining inserts for the last time
285  if (pProgrInfo)
286  {
287  pProgrInfo->ReportInserts(nActionsToReport);
288  }
289 
290  return maTmpList.size();
291 }
292 
293 void ImpSdrPdfImport::SetAttributes(SdrObject* pObj, bool bForceTextAttr)
294 {
295  mbNoLine = false;
296  mbNoFill = false;
297  bool bLine(!bForceTextAttr);
298  bool bFill(!pObj || (pObj->IsClosedObj() && !bForceTextAttr));
299  bool bText(bForceTextAttr || (pObj && pObj->GetOutlinerParaObject()));
300 
301  if (bLine)
302  {
303  if (mnLineWidth)
304  {
305  mpLineAttr->Put(XLineWidthItem(mnLineWidth));
306  }
307  else
308  {
309  mpLineAttr->Put(XLineWidthItem(0));
310  }
311 
312  maOldLineColor = mpVD->GetLineColor();
313 
314  if (mpVD->IsLineColor())
315  {
316  mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_SOLID)); //TODO support dashed lines.
317  mpLineAttr->Put(XLineColorItem(OUString(), mpVD->GetLineColor()));
318  }
319  else
320  {
321  mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_NONE));
322  }
323 
324  mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_NONE));
325 
326  // Add LineCap support
327  mpLineAttr->Put(XLineCapItem(gaLineCap));
328 
329  if (((maDash.GetDots() && maDash.GetDotLen())
330  || (maDash.GetDashes() && maDash.GetDashLen()))
331  && maDash.GetDistance())
332  {
333  mpLineAttr->Put(XLineDashItem(OUString(), maDash));
334  }
335  else
336  {
337  mpLineAttr->Put(XLineDashItem(OUString(), XDash(css::drawing::DashStyle_RECT)));
338  }
339  }
340  else
341  {
342  mbNoLine = true;
343  }
344 
345  if (bFill)
346  {
347  if (mpVD->IsFillColor())
348  {
349  mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID));
350  mpFillAttr->Put(XFillColorItem(OUString(), mpVD->GetFillColor()));
351  }
352  else
353  {
354  mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_NONE));
355  }
356  }
357  else
358  {
359  mbNoFill = true;
360  }
361 
362  if (bText && mbFntDirty)
363  {
364  vcl::Font aFnt(mpVD->GetFont());
365  const sal_uInt32 nHeight(FRound(aFnt.GetFontSize().Height() * mfScaleY));
366 
367  mpTextAttr->Put(SvxFontItem(aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(),
368  aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO));
369  mpTextAttr->Put(SvxFontItem(aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(),
370  aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CJK));
371  mpTextAttr->Put(SvxFontItem(aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(),
372  aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CTL));
373  mpTextAttr->Put(SvxPostureItem(aFnt.GetItalic(), EE_CHAR_ITALIC));
374  mpTextAttr->Put(SvxWeightItem(aFnt.GetWeight(), EE_CHAR_WEIGHT));
375  mpTextAttr->Put(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT));
376  mpTextAttr->Put(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT_CJK));
377  mpTextAttr->Put(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT_CTL));
378  mpTextAttr->Put(SvxCharScaleWidthItem(100, EE_CHAR_FONTWIDTH));
379  mpTextAttr->Put(SvxUnderlineItem(aFnt.GetUnderline(), EE_CHAR_UNDERLINE));
380  mpTextAttr->Put(SvxOverlineItem(aFnt.GetOverline(), EE_CHAR_OVERLINE));
381  mpTextAttr->Put(SvxCrossedOutItem(aFnt.GetStrikeout(), EE_CHAR_STRIKEOUT));
382  mpTextAttr->Put(SvxShadowedItem(aFnt.IsShadow(), EE_CHAR_SHADOW));
383 
384  // #i118485# Setting this item leads to problems (written #i118498# for this)
385  // mpTextAttr->Put(SvxAutoKernItem(aFnt.IsKerning(), EE_CHAR_KERNING));
386 
387  mpTextAttr->Put(SvxWordLineModeItem(aFnt.IsWordLineMode(), EE_CHAR_WLM));
388  mpTextAttr->Put(SvxContourItem(aFnt.IsOutline(), EE_CHAR_OUTLINE));
389  mpTextAttr->Put(SvxColorItem(mpVD->GetTextColor(), EE_CHAR_COLOR));
390  //... svxfont textitem svditext
391  mbFntDirty = false;
392  }
393 
394  if (pObj)
395  {
396  pObj->SetLayer(mnLayer);
397 
398  if (bLine)
399  {
400  pObj->SetMergedItemSet(*mpLineAttr);
401  }
402 
403  if (bFill)
404  {
405  pObj->SetMergedItemSet(*mpFillAttr);
406  }
407 
408  if (bText)
409  {
410  pObj->SetMergedItemSet(*mpTextAttr);
412  }
413  }
414 }
415 
416 void ImpSdrPdfImport::InsertObj(SdrObject* pObj, bool bScale)
417 {
418  if (bScale && !maScaleRect.IsEmpty())
419  {
420  if (mbSize)
421  {
422  pObj->NbcResize(Point(), maScaleX, maScaleY);
423  }
424 
425  if (mbMov)
426  {
427  pObj->NbcMove(Size(maOfs.X(), maOfs.Y()));
428  }
429  }
430 
431  if (isClip())
432  {
433  const basegfx::B2DPolyPolygon aPoly(pObj->TakeXorPoly());
434  const basegfx::B2DRange aOldRange(aPoly.getB2DRange());
435  const SdrLayerID aOldLayer(pObj->GetLayer());
436  const SfxItemSet aOldItemSet(pObj->GetMergedItemSet());
437  const SdrGrafObj* pSdrGrafObj = dynamic_cast<SdrGrafObj*>(pObj);
438  const SdrTextObj* pSdrTextObj = dynamic_cast<SdrTextObj*>(pObj);
439 
440  if (pSdrTextObj && pSdrTextObj->HasText())
441  {
442  // all text objects are created from ImportText and have no line or fill attributes, so
443  // it is okay to concentrate on the text itself
444  while (true)
445  {
446  const basegfx::B2DPolyPolygon aTextContour(pSdrTextObj->TakeContour());
447  const basegfx::B2DRange aTextRange(aTextContour.getB2DRange());
448  const basegfx::B2DRange aClipRange(maClip.getB2DRange());
449 
450  // no overlap -> completely outside
451  if (!aClipRange.overlaps(aTextRange))
452  {
453  SdrObject::Free(pObj);
454  break;
455  }
456 
457  // when the clip is a rectangle fast check for inside is possible
458  if (basegfx::utils::isRectangle(maClip) && aClipRange.isInside(aTextRange))
459  {
460  // completely inside ClipRect
461  break;
462  }
463 
464  // here text needs to be clipped; to do so, convert to SdrObjects with polygons
465  // and add these recursively. Delete original object, do not add in this run
466  SdrObjectUniquePtr pConverted = pSdrTextObj->ConvertToPolyObj(true, true);
467  SdrObject::Free(pObj);
468 
469  if (pConverted)
470  {
471  // recursively add created conversion; per definition this shall not
472  // contain further SdrTextObjs. Visit only non-group objects
473  SdrObjListIter aIter(*pConverted, SdrIterMode::DeepNoGroups);
474 
475  // work with clones; the created conversion may contain group objects
476  // and when working with the original objects the loop itself could
477  // break and the cleanup later would be pretty complicated (only delete group
478  // objects, are these empty, ...?)
479  while (aIter.IsMore())
480  {
481  SdrObject* pCandidate = aIter.Next();
482  OSL_ENSURE(pCandidate && dynamic_cast<SdrObjGroup*>(pCandidate) == nullptr,
483  "SdrObjListIter with SdrIterMode::DeepNoGroups error (!)");
484  SdrObject* pNewClone(
485  pCandidate->CloneSdrObject(pCandidate->getSdrModelFromSdrObject()));
486 
487  if (pNewClone)
488  {
489  InsertObj(pNewClone, false);
490  }
491  else
492  {
493  OSL_ENSURE(false, "SdrObject::Clone() failed (!)");
494  }
495  }
496  }
497 
498  break;
499  }
500  }
501  else
502  {
503  BitmapEx aBitmapEx;
504 
505  if (pSdrGrafObj)
506  {
507  aBitmapEx = pSdrGrafObj->GetGraphic().GetBitmapEx();
508  }
509 
510  SdrObject::Free(pObj);
511 
512  if (!aOldRange.isEmpty())
513  {
514  // clip against ClipRegion
516  aPoly, maClip, true, !aPoly.isClosed()));
517  const basegfx::B2DRange aNewRange(aNewPoly.getB2DRange());
518 
519  if (!aNewRange.isEmpty())
520  {
521  pObj = new SdrPathObj(*mpModel, aNewPoly.isClosed() ? OBJ_POLY : OBJ_PLIN,
522  aNewPoly);
523 
524  pObj->SetLayer(aOldLayer);
525  pObj->SetMergedItemSet(aOldItemSet);
526 
527  if (!!aBitmapEx)
528  {
529  // aNewRange is inside of aOldRange and defines which part of aBitmapEx is used
530  const double fScaleX(aBitmapEx.GetSizePixel().Width()
531  / (aOldRange.getWidth() ? aOldRange.getWidth() : 1.0));
532  const double fScaleY(
533  aBitmapEx.GetSizePixel().Height()
534  / (aOldRange.getHeight() ? aOldRange.getHeight() : 1.0));
535  basegfx::B2DRange aPixel(aNewRange);
536  basegfx::B2DHomMatrix aTrans;
537 
538  aTrans.translate(-aOldRange.getMinX(), -aOldRange.getMinY());
539  aTrans.scale(fScaleX, fScaleY);
540  aPixel.transform(aTrans);
541 
542  const Size aOrigSizePixel(aBitmapEx.GetSizePixel());
543  const Point aClipTopLeft(
544  basegfx::fround(floor(std::max(0.0, aPixel.getMinX()))),
545  basegfx::fround(floor(std::max(0.0, aPixel.getMinY()))));
546  const Size aClipSize(
547  basegfx::fround(ceil(std::min(
548  static_cast<double>(aOrigSizePixel.Width()), aPixel.getWidth()))),
550  ceil(std::min(static_cast<double>(aOrigSizePixel.Height()),
551  aPixel.getHeight()))));
552  const BitmapEx aClippedBitmap(aBitmapEx, aClipTopLeft, aClipSize);
553 
554  pObj->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
555  pObj->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aClippedBitmap)));
556  pObj->SetMergedItem(XFillBmpTileItem(false));
557  pObj->SetMergedItem(XFillBmpStretchItem(true));
558  }
559  }
560  }
561  }
562  }
563 
564  if (pObj)
565  {
566  // #i111954# check object for visibility
567  // used are SdrPathObj, SdrRectObj, SdrCircObj, SdrGrafObj
568  bool bVisible(false);
569 
570  if (pObj->HasLineStyle())
571  {
572  bVisible = true;
573  }
574 
575  if (!bVisible && pObj->HasFillStyle())
576  {
577  bVisible = true;
578  }
579 
580  if (!bVisible)
581  {
582  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj);
583 
584  if (pTextObj && pTextObj->HasText())
585  {
586  bVisible = true;
587  }
588  }
589 
590  if (!bVisible)
591  {
592  SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>(pObj);
593 
594  if (pGrafObj)
595  {
596  // this may be refined to check if the graphic really is visible. It
597  // is here to ensure that graphic objects without fill, line and text
598  // get created
599  bVisible = true;
600  }
601  }
602 
603  if (!bVisible)
604  {
605  SdrObject::Free(pObj);
606  }
607  else
608  {
609  maTmpList.push_back(pObj);
610 
611  if (dynamic_cast<SdrPathObj*>(pObj))
612  {
613  const bool bClosed(pObj->IsClosedObj());
614 
615  mbLastObjWasPolyWithoutLine = mbNoLine && bClosed;
616  }
617  else
618  {
619  mbLastObjWasPolyWithoutLine = false;
620  }
621  }
622  }
623 }
624 
625 bool ImpSdrPdfImport::CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon& rPolyPolygon)
626 {
627  // #i73407# reformulation to use new B2DPolygon classes
628  if (mbLastObjWasPolyWithoutLine)
629  {
630  SdrObject* pTmpObj = !maTmpList.empty() ? maTmpList[maTmpList.size() - 1] : nullptr;
631  SdrPathObj* pLastPoly = dynamic_cast<SdrPathObj*>(pTmpObj);
632 
633  if (pLastPoly)
634  {
635  if (pLastPoly->GetPathPoly() == rPolyPolygon)
636  {
637  SetAttributes(nullptr);
638 
639  if (!mbNoLine && mbNoFill)
640  {
641  pLastPoly->SetMergedItemSet(*mpLineAttr);
642 
643  return true;
644  }
645  }
646  }
647  }
648 
649  return false;
650 }
651 
652 void ImpSdrPdfImport::checkClip()
653 {
654  if (mpVD->IsClipRegion())
655  {
656  maClip = mpVD->GetClipRegion().GetAsB2DPolyPolygon();
657 
658  if (isClip())
659  {
661  mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
662 
663  maClip.transform(aTransform);
664  }
665  }
666 }
667 
668 bool ImpSdrPdfImport::isClip() const { return !maClip.getB2DRange().isEmpty(); }
669 void ImpSdrPdfImport::ImportPdfObject(
670  std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
671  std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int nPageObjectIndex)
672 {
673  if (!pPageObject)
674  return;
675 
676  const int nPageObjectType = pPageObject->getType();
677  switch (nPageObjectType)
678  {
679  case FPDF_PAGEOBJ_TEXT:
680  ImportText(pPageObject, pTextPage, nPageObjectIndex);
681  break;
682  case FPDF_PAGEOBJ_PATH:
683  ImportPath(pPageObject, nPageObjectIndex);
684  break;
685  case FPDF_PAGEOBJ_IMAGE:
686  ImportImage(pPageObject, nPageObjectIndex);
687  break;
688  case FPDF_PAGEOBJ_SHADING:
689  SAL_WARN("sd.filter", "Got page object SHADING: " << nPageObjectIndex);
690  break;
691  case FPDF_PAGEOBJ_FORM:
692  ImportForm(pPageObject, pTextPage, nPageObjectIndex);
693  break;
694  default:
695  SAL_WARN("sd.filter", "Unknown PDF page object #" << nPageObjectIndex
696  << " of type: " << nPageObjectType);
697  break;
698  }
699 }
700 
701 void ImpSdrPdfImport::ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
702  std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
703  int /*nPageObjectIndex*/)
704 {
705  // Get the form matrix to perform correct translation/scaling of the form sub-objects.
706  const basegfx::B2DHomMatrix aOldMatrix = maCurrentMatrix;
707 
708  maCurrentMatrix = pPageObject->getMatrix();
709 
710  const int nCount = pPageObject->getFormObjectCount();
711  for (int nIndex = 0; nIndex < nCount; ++nIndex)
712  {
713  auto pFormObject = pPageObject->getFormObject(nIndex);
714 
715  ImportPdfObject(pFormObject, pTextPage, -1);
716  }
717 
718  // Restore the old one.
719  maCurrentMatrix = aOldMatrix;
720 }
721 
722 void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
723  std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
724  int /*nPageObjectIndex*/)
725 {
726  basegfx::B2DRectangle aTextRect = pPageObject->getBounds();
727  basegfx::B2DHomMatrix aMatrix = pPageObject->getMatrix();
728 
729  basegfx::B2DHomMatrix aTextMatrix(maCurrentMatrix);
730 
731  aTextRect *= aTextMatrix;
732  const tools::Rectangle aRect = PointsToLogic(aTextRect.getMinX(), aTextRect.getMaxX(),
733  aTextRect.getMinY(), aTextRect.getMaxY());
734 
735  OUString sText = pPageObject->getText(pTextPage);
736 
737  const double dFontSize = pPageObject->getFontSize();
738  double dFontSizeH = fabs(sqrt2(aMatrix.a(), aMatrix.c()) * dFontSize);
739  double dFontSizeV = fabs(sqrt2(aMatrix.b(), aMatrix.d()) * dFontSize);
740 
741  dFontSizeH = convertPointToMm100(dFontSizeH);
742  dFontSizeV = convertPointToMm100(dFontSizeV);
743 
744  const Size aFontSize(dFontSizeH, dFontSizeV);
745  vcl::Font aFnt = mpVD->GetFont();
746  if (aFontSize != aFnt.GetFontSize())
747  {
748  aFnt.SetFontSize(aFontSize);
749  mpVD->SetFont(aFnt);
750  mbFntDirty = true;
751  }
752 
753  OUString sFontName = pPageObject->getFontName();
754  if (!sFontName.isEmpty() && sFontName != aFnt.GetFamilyName())
755  {
756  aFnt.SetFamilyName(sFontName);
757  mpVD->SetFont(aFnt);
758  mbFntDirty = true;
759  }
760 
761  Color aTextColor(COL_TRANSPARENT);
762  bool bFill = false;
763  bool bUse = true;
764  switch (pPageObject->getTextRenderMode())
765  {
766  case FPDF_TEXTRENDERMODE_FILL:
767  case FPDF_TEXTRENDERMODE_FILL_CLIP:
768  case FPDF_TEXTRENDERMODE_FILL_STROKE:
769  case FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP:
770  bFill = true;
771  break;
772  case FPDF_TEXTRENDERMODE_STROKE:
773  case FPDF_TEXTRENDERMODE_STROKE_CLIP:
774  case FPDF_TEXTRENDERMODE_UNKNOWN:
775  break;
776  case FPDF_TEXTRENDERMODE_INVISIBLE:
777  case FPDF_TEXTRENDERMODE_CLIP:
778  bUse = false;
779  break;
780  }
781  if (bUse)
782  {
783  Color aColor = bFill ? pPageObject->getFillColor() : pPageObject->getStrokeColor();
784  if (aColor != COL_TRANSPARENT)
785  aTextColor = aColor.GetRGBColor();
786  }
787 
788  if (aTextColor != mpVD->GetTextColor())
789  {
790  mpVD->SetTextColor(aTextColor);
791  mbFntDirty = true;
792  }
793 
794  InsertTextObject(aRect.TopLeft(), aRect.GetSize(), sText);
795 }
796 
797 void ImpSdrPdfImport::InsertTextObject(const Point& rPos, const Size& rSize, const OUString& rStr)
798 {
799  // calc text box size, add 5% to make it fit safely
800 
801  FontMetric aFontMetric(mpVD->GetFontMetric());
802  vcl::Font aFont(mpVD->GetFont());
803  FontAlign eAlignment(aFont.GetAlignment());
804 
805  // sal_Int32 nTextWidth = static_cast<sal_Int32>(mpVD->GetTextWidth(rStr) * mfScaleX);
806  sal_Int32 nTextHeight = static_cast<sal_Int32>(mpVD->GetTextHeight() * mfScaleY);
807 
808  Point aPosition(FRound(rPos.X() * mfScaleX + maOfs.X()),
809  FRound(rPos.Y() * mfScaleY + maOfs.Y()));
810  Size aSize(FRound(rSize.Width() * mfScaleX), FRound(rSize.Height() * mfScaleY));
811 
812  if (eAlignment == ALIGN_BASELINE)
813  aPosition.AdjustY(-FRound(aFontMetric.GetAscent() * mfScaleY));
814  else if (eAlignment == ALIGN_BOTTOM)
815  aPosition.AdjustY(-nTextHeight);
816 
817  tools::Rectangle aTextRect(aPosition, aSize);
818  SdrRectObj* pText = new SdrRectObj(*mpModel, OBJ_TEXT, aTextRect);
819 
824 
825  if (aFont.GetAverageFontWidth())
826  {
829  // don't let the margins eat the space needed for the text
830  pText->SetMergedItem(SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_ALLLINES));
831  }
832  else
833  {
835  }
836 
837  pText->SetLayer(mnLayer);
838  pText->NbcSetText(rStr);
839  SetAttributes(pText, true);
840  pText->SetSnapRect(aTextRect);
841 
842  if (!aFont.IsTransparent())
843  {
844  SfxItemSet aAttr(*mpFillAttr->GetPool(), svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST>{});
845  aAttr.Put(XFillStyleItem(drawing::FillStyle_SOLID));
846  aAttr.Put(XFillColorItem(OUString(), aFont.GetFillColor()));
847  pText->SetMergedItemSet(aAttr);
848  }
849  sal_uInt32 nAngle = aFont.GetOrientation();
850  if (nAngle)
851  {
852  nAngle *= 10;
853  double a = nAngle * F_PI18000;
854  double nSin = sin(a);
855  double nCos = cos(a);
856  pText->NbcRotate(aPosition, nAngle, nSin, nCos);
857  }
858  InsertObj(pText, false);
859 }
860 
861 void ImpSdrPdfImport::MapScaling()
862 {
863  const size_t nCount(maTmpList.size());
864  const MapMode& rMap = mpVD->GetMapMode();
865  Point aMapOrg(rMap.GetOrigin());
866  bool bMov2(aMapOrg.X() != 0 || aMapOrg.Y() != 0);
867 
868  if (bMov2)
869  {
870  for (size_t i = mnMapScalingOfs; i < nCount; i++)
871  {
872  SdrObject* pObj = maTmpList[i];
873 
874  pObj->NbcMove(Size(aMapOrg.X(), aMapOrg.Y()));
875  }
876  }
877 
878  mnMapScalingOfs = nCount;
879 }
880 
881 void ImpSdrPdfImport::ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
882  int /*nPageObjectIndex*/)
883 {
884  std::unique_ptr<std::remove_pointer<FPDF_BITMAP>::type, FPDFBitmapDeleter> bitmap(
885  FPDFImageObj_GetBitmap(pPageObject->getPointer()));
886  if (!bitmap)
887  {
888  SAL_WARN("sd.filter", "Failed to get IMAGE");
889  return;
890  }
891 
892  const int format = FPDFBitmap_GetFormat(bitmap.get());
893  if (format == FPDFBitmap_Unknown)
894  {
895  SAL_WARN("sd.filter", "Failed to get IMAGE format");
896  return;
897  }
898 
899  const unsigned char* pBuf
900  = static_cast<const unsigned char*>(FPDFBitmap_GetBuffer(bitmap.get()));
901  const int nWidth = FPDFBitmap_GetWidth(bitmap.get());
902  const int nHeight = FPDFBitmap_GetHeight(bitmap.get());
903  const int nStride = FPDFBitmap_GetStride(bitmap.get());
904  BitmapEx aBitmap(Size(nWidth, nHeight), 24);
905 
906  switch (format)
907  {
908  case FPDFBitmap_BGR:
909  ReadRawDIB(aBitmap, pBuf, ScanlineFormat::N24BitTcBgr, nHeight, nStride);
910  break;
911  case FPDFBitmap_BGRx:
912  ReadRawDIB(aBitmap, pBuf, ScanlineFormat::N32BitTcRgba, nHeight, nStride);
913  break;
914  case FPDFBitmap_BGRA:
915  ReadRawDIB(aBitmap, pBuf, ScanlineFormat::N32BitTcBgra, nHeight, nStride);
916  break;
917  default:
918  SAL_WARN("sd.filter", "Got IMAGE width: " << nWidth << ", height: " << nHeight
919  << ", stride: " << nStride
920  << ", format: " << format);
921  break;
922  }
923 
924  float left;
925  float bottom;
926  float right;
927  float top;
928  if (!FPDFPageObj_GetBounds(pPageObject->getPointer(), &left, &bottom, &right, &top))
929  {
930  SAL_WARN("sd.filter", "FAILED to get image bounds");
931  }
932 
933  tools::Rectangle aRect = PointsToLogic(left, right, top, bottom);
934  aRect.AdjustRight(1);
935  aRect.AdjustBottom(1);
936 
937  SdrGrafObj* pGraf = new SdrGrafObj(*mpModel, Graphic(aBitmap), aRect);
938 
939  // This action is not creating line and fill, set directly, do not use SetAttributes(..)
940  pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
941  pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
942  InsertObj(pGraf);
943 }
944 
945 void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
946  int /*nPageObjectIndex*/)
947 {
948  auto aPathMatrix = pPageObject->getMatrix();
949 
950  aPathMatrix *= maCurrentMatrix;
951 
952  basegfx::B2DPolyPolygon aPolyPoly;
953  basegfx::B2DPolygon aPoly;
954  std::vector<basegfx::B2DPoint> aBezier;
955 
956  const int nSegments = pPageObject->getPathSegmentCount();
957  for (int nSegmentIndex = 0; nSegmentIndex < nSegments; ++nSegmentIndex)
958  {
959  auto pPathSegment = pPageObject->getPathSegment(nSegmentIndex);
960  if (pPathSegment != nullptr)
961  {
962  basegfx::B2DPoint aB2DPoint = pPathSegment->getPoint();
963  aB2DPoint *= aPathMatrix;
964 
965  const bool bClose = pPathSegment->isClosed();
966  if (bClose)
967  aPoly.setClosed(bClose); // TODO: Review
968 
969  Point aPoint = PointsToLogic(aB2DPoint.getX(), aB2DPoint.getY());
970  aB2DPoint.setX(aPoint.X());
971  aB2DPoint.setY(aPoint.Y());
972 
973  const int nSegmentType = pPathSegment->getType();
974  switch (nSegmentType)
975  {
976  case FPDF_SEGMENT_LINETO:
977  aPoly.append(aB2DPoint);
978  break;
979 
980  case FPDF_SEGMENT_BEZIERTO:
981  aBezier.emplace_back(aB2DPoint.getX(), aB2DPoint.getY());
982  if (aBezier.size() == 3)
983  {
984  aPoly.appendBezierSegment(aBezier[0], aBezier[1], aBezier[2]);
985  aBezier.clear();
986  }
987  break;
988 
989  case FPDF_SEGMENT_MOVETO:
990  // New Poly.
991  if (aPoly.count() > 0)
992  {
993  aPolyPoly.append(aPoly, 1);
994  aPoly.clear();
995  }
996 
997  aPoly.append(aB2DPoint);
998  break;
999 
1000  case FPDF_SEGMENT_UNKNOWN:
1001  default:
1002  SAL_WARN("sd.filter", "Unknown path segment type in PDF: " << nSegmentType);
1003  break;
1004  }
1005  }
1006  }
1007 
1008  if (aBezier.size() == 3)
1009  {
1010  aPoly.appendBezierSegment(aBezier[0], aBezier[1], aBezier[2]);
1011  aBezier.clear();
1012  }
1013 
1014  if (aPoly.count() > 0)
1015  {
1016  aPolyPoly.append(aPoly, 1);
1017  aPoly.clear();
1018  }
1019 
1020  const basegfx::B2DHomMatrix aTransform(
1021  basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
1022  aPolyPoly.transform(aTransform);
1023 
1024  float fWidth = 1;
1025  FPDFPageObj_GetStrokeWidth(pPageObject->getPointer(), &fWidth);
1026  const double dWidth = 0.5 * fabs(sqrt2(aPathMatrix.a(), aPathMatrix.c()) * fWidth);
1027  mnLineWidth = convertPointToMm100(dWidth);
1028 
1029  int nFillMode = FPDF_FILLMODE_ALTERNATE;
1030  FPDF_BOOL bStroke = 1; // Assume we have to draw, unless told otherwise.
1031  if (FPDFPath_GetDrawMode(pPageObject->getPointer(), &nFillMode, &bStroke))
1032  {
1033  if (nFillMode == FPDF_FILLMODE_ALTERNATE)
1034  mpVD->SetDrawMode(DrawModeFlags::Default);
1035  else if (nFillMode == FPDF_FILLMODE_WINDING)
1036  mpVD->SetDrawMode(DrawModeFlags::Default);
1037  else
1038  mpVD->SetDrawMode(DrawModeFlags::NoFill);
1039  }
1040 
1041  unsigned int nR;
1042  unsigned int nG;
1043  unsigned int nB;
1044  unsigned int nA;
1045  FPDFPageObj_GetFillColor(pPageObject->getPointer(), &nR, &nG, &nB, &nA);
1046  mpVD->SetFillColor(Color(nR, nG, nB));
1047 
1048  if (bStroke)
1049  {
1050  FPDFPageObj_GetStrokeColor(pPageObject->getPointer(), &nR, &nG, &nB, &nA);
1051  mpVD->SetLineColor(Color(nR, nG, nB));
1052  }
1053  else
1054  mpVD->SetLineColor(COL_TRANSPARENT);
1055 
1056  if (!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aPolyPoly))
1057  {
1058  SdrPathObj* pPath = new SdrPathObj(*mpModel, OBJ_POLY, aPolyPoly);
1059  SetAttributes(pPath);
1060  InsertObj(pPath, false);
1061  }
1062 }
1063 
1064 Point ImpSdrPdfImport::PointsToLogic(double x, double y) const
1065 {
1066  y = correctVertOrigin(y);
1067 
1069  return aPos;
1070 }
1071 
1072 tools::Rectangle ImpSdrPdfImport::PointsToLogic(double left, double right, double top,
1073  double bottom) const
1074 {
1075  top = correctVertOrigin(top);
1076  bottom = correctVertOrigin(bottom);
1077 
1078  Point aPos(convertPointToMm100(left), convertPointToMm100(top));
1079  Size aSize(convertPointToMm100(right - left), convertPointToMm100(bottom - top));
1080 
1081  return tools::Rectangle(aPos, aSize);
1082 }
1083 
1084 #endif // HAVE_FEATURE_PDFIUM
1085 
1086 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
Point TopLeft() const
long Width() const
void ReportRescales(size_t nRescaleCount)
Definition: svdetc.cxx:473
virtual basegfx::B2DPolyPolygon TakeXorPoly() const
The Xor-Polygon is required by the View to drag the object.
Definition: svdobj.cxx:1067
#define FontAlign
constexpr TypedWhichId< SvxFontItem > EE_CHAR_FONTINFO_CJK(EE_CHAR_START+17)
void setX(double fX)
sal_Int32 nIndex
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
void SetFontSize(const Size &)
bool bVisible
bool IsClosedObj() const
Definition: svdobj.hxx:788
const OUString & GetFamilyName() const
long FRound(double fVal)
sal_uInt64 left
std::unique_ptr< ContentProperties > pData
virtual void NbcResize(const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdobj.cxx:1380
long Height() const
constexpr TypedWhichId< SdrOnOffItem > SDRATTR_TEXT_AUTOGROWWIDTH(SDRATTR_MISC_FIRST+12)
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
periodic cubic Spline (ni)
Definition: svdobj.hxx:133
virtual void NbcInsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
Definition: svdpage.cxx:292
bool HasFillStyle() const
Definition: svdobj.cxx:2954
double getX() const
size_t GetObjCount() const
Definition: svdpage.cxx:752
constexpr TypedWhichId< SvxPostureItem > EE_CHAR_ITALIC(EE_CHAR_START+7)
void appendBezierSegment(const basegfx::B2DPoint &rNextControlPoint, const basegfx::B2DPoint &rPrevControlPoint, const basegfx::B2DPoint &rPoint)
double getY() const
circle cut
Definition: svdobj.hxx:125
static void Free(SdrObject *&_rpObject)
Definition: svdobj.cxx:396
double getMaxX() const
polygon, PolyPolygon
Definition: svdobj.hxx:126
Color GetRGBColor() const
virtual bool HasText() const override
Definition: svdotxat.cxx:412
SdrOnOffItem makeSdrTextAutoGrowHeightItem(bool bAuto)
Definition: sdtagitm.hxx:25
long AdjustBottom(long nVertMoveDelta)
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke)
B2DRange getB2DRange() const
Rectangle objects (rectangle, circle, ...)
Definition: svdorect.hxx:39
void ClearMergedItem(const sal_uInt16 nWhich=0)
Definition: svdobj.cxx:1904
Definition: xdash.hxx:31
constexpr TypedWhichId< SvxFontItem > EE_CHAR_FONTINFO_CTL(EE_CHAR_START+18)
int nCount
void SetMergedItemSet(const SfxItemSet &rSet, bool bClearAllItems=false)
Definition: svdobj.cxx:1914
B2DHomMatrix createScaleTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fTranslateX, double fTranslateY)
SdrOnOffItem makeSdrTextAutoGrowWidthItem(bool bAuto)
Definition: sdtagitm.hxx:29
double getMaxY() const
B2IRange fround(const B2DRange &rRange)
SdrMetricItem makeSdrTextUpperDistItem(long mnHeight)
Definition: sdtditm.hxx:33
constexpr TypedWhichId< SvxContourItem > EE_CHAR_OUTLINE(EE_CHAR_START+8)
constexpr TypedWhichId< SvxWeightItem > EE_CHAR_WEIGHT(EE_CHAR_START+4)
void SetInsertCount(size_t _nInsertCount)
Definition: svdetc.cxx:484
constexpr sal_Int64 convertPointToMm100(sal_Int64 nNumber)
void SetActionCount(size_t _nActionCount)
Definition: svdetc.cxx:479
constexpr TypedWhichId< SvxShadowedItem > EE_CHAR_SHADOW(EE_CHAR_START+9)
bool isEmpty() const
virtual void SetLayer(SdrLayerID nLayer)
Definition: svdobj.cxx:599
def right
void SetFamilyName(const OUString &rFamilyName)
int i
uno_Any a
basegfx::B2DPolyPolygon maClip
Helper class for the communication between the dialog In order to break open Metafiles (sd/source/ui/...
Definition: svdetc.hxx:111
void scale(double fX, double fY)
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:273
void transform(const basegfx::B2DHomMatrix &rMatrix)
const Size & GetFontSize() const
void SetMergedItem(const SfxPoolItem &rItem)
Definition: svdobj.cxx:1899
This class represents an embedded or linked bitmap graphic object.
Definition: svdograf.hxx:79
Abstract DrawObject.
Definition: svdobj.hxx:312
bool ReportActions(size_t nActionCount)
Definition: svdetc.cxx:455
virtual basegfx::B2DPolyPolygon TakeContour() const override
contour for TextToContour
Definition: svdotext.cxx:1064
Size GetSize() const
virtual SdrLayerID GetLayer() const
Definition: svdobj.cxx:577
bool HasLineStyle() const
Definition: svdobj.cxx:2959
const int mnLayer
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
void setClosed(bool bNew)
constexpr TypedWhichId< SvxCrossedOutItem > EE_CHAR_STRIKEOUT(EE_CHAR_START+6)
SdrObjectUniquePtr ConvertToPolyObj(bool bBezier, bool bLineToArea) const
Definition: svdobj.cxx:2510
double getMinY() const
long AdjustRight(long nHorzMoveDelta)
void setY(double fY)
virtual void NbcMove(const Size &rSiz)
The methods Move, Resize, Rotate, Mirror, Shear, SetSnapRect and SetLogicRect call the corresponding ...
Definition: svdobj.cxx:1374
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1889
constexpr TypedWhichId< SvxColorItem > EE_CHAR_COLOR(EE_CHAR_START+0)
void NbcSetText(const OUString &rStr)
Definition: svdotext.cxx:190
constexpr TypedWhichId< SvxWordLineModeItem > EE_CHAR_WLM(EE_CHAR_START+13)
virtual SdrObject * CloneSdrObject(SdrModel &rTargetModel) const
Definition: svdobj.cxx:974
#define F_PI18000
constexpr TypedWhichId< SvxOverlineItem > EE_CHAR_OVERLINE(EE_CHAR_START+29)
std::unique_ptr< SdrObject, SdrObjectFreeOp > SdrObjectUniquePtr
Definition: svdobj.hxx:114
constexpr TypedWhichId< SvxFontItem > EE_CHAR_FONTINFO(EE_CHAR_START+1)
SdrMetricItem makeSdrTextLeftDistItem(long mnHeight)
Definition: sdtditm.hxx:25
void translate(double fX, double fY)
const basegfx::B2DPolyPolygon & GetPathPoly() const
Definition: svdopath.hxx:139
void ReportInserts(size_t nInsertCount)
Definition: svdetc.cxx:465
virtual void SetSnapRect(const tools::Rectangle &rRect)
Definition: svdobj.cxx:1622
SdrMetricItem makeSdrTextRightDistItem(long mnHeight)
Definition: sdtditm.hxx:29
virtual void NbcRotate(const Point &rRef, long nAngle, double sn, double cs) override
Definition: svdorect.cxx:473
constexpr TypedWhichId< SvxUnderlineItem > EE_CHAR_UNDERLINE(EE_CHAR_START+5)
#define SAL_WARN(area, stream)
const SfxItemPool & GetItemPool() const
Definition: svdmodel.hxx:314
double getMinX() const
const std::shared_ptr< VectorGraphicData > & getVectorGraphicData() const
const Size & GetSizePixel() const
SdrMetricItem makeSdrTextLowerDistItem(long mnHeight)
Definition: sdtditm.hxx:37
virtual OutlinerParaObject * GetOutlinerParaObject() const
Definition: svdobj.cxx:1748
bool isRectangle(const B2DPolygon &rPoly)
bool ReadRawDIB(BitmapEx &rTarget, const unsigned char *pBuf, const ScanlineFormat nFormat, const int nHeight, const int nStride)
sal_uInt32 count() const