LibreOffice Module drawinglayer (master) 1
emfphelperdata.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 "emfpcustomlinecap.hxx"
21#include "emfphelperdata.hxx"
22#include "emfpbrush.hxx"
23#include "emfppen.hxx"
24#include "emfppath.hxx"
25#include "emfpregion.hxx"
26#include "emfpimage.hxx"
28#include "emfpfont.hxx"
29#include "emfpstringformat.hxx"
31#include <wmfemfhelper.hxx>
50#include <sal/log.hxx>
51#include <vcl/svapp.hxx>
52#include <vcl/settings.hxx>
55
56#include <algorithm>
57
58namespace emfplushelper
59{
60
61 enum
62 {
63 WrapModeTile = 0x00000000,
64 WrapModeTileFlipX = 0x00000001,
65 WrapModeTileFlipY = 0x00000002,
66 WrapModeTileFlipXY = 0x00000003,
67 WrapModeClamp = 0x00000004
68 };
69
70 const char* emfTypeToName(sal_uInt16 type)
71 {
72 switch (type)
73 {
74 case EmfPlusRecordTypeHeader: return "EmfPlusRecordTypeHeader";
75 case EmfPlusRecordTypeEndOfFile: return "EmfPlusRecordTypeEndOfFile";
76 case EmfPlusRecordTypeComment: return "EmfPlusRecordTypeComment";
77 case EmfPlusRecordTypeGetDC: return "EmfPlusRecordTypeGetDC";
78 case EmfPlusRecordTypeObject: return "EmfPlusRecordTypeObject";
79 case EmfPlusRecordTypeFillRects: return "EmfPlusRecordTypeFillRects";
80 case EmfPlusRecordTypeDrawRects: return "EmfPlusRecordTypeDrawRects";
81 case EmfPlusRecordTypeFillPolygon: return "EmfPlusRecordTypeFillPolygon";
82 case EmfPlusRecordTypeDrawLines: return "EmfPlusRecordTypeDrawLines";
83 case EmfPlusRecordTypeFillClosedCurve: return "EmfPlusRecordTypeFillClosedCurve";
84 case EmfPlusRecordTypeDrawClosedCurve: return "EmfPlusRecordTypeDrawClosedCurve";
85 case EmfPlusRecordTypeDrawCurve: return "EmfPlusRecordTypeDrawCurve";
86 case EmfPlusRecordTypeFillEllipse: return "EmfPlusRecordTypeFillEllipse";
87 case EmfPlusRecordTypeDrawEllipse: return "EmfPlusRecordTypeDrawEllipse";
88 case EmfPlusRecordTypeFillPie: return "EmfPlusRecordTypeFillPie";
89 case EmfPlusRecordTypeDrawPie: return "EmfPlusRecordTypeDrawPie";
90 case EmfPlusRecordTypeDrawArc: return "EmfPlusRecordTypeDrawArc";
91 case EmfPlusRecordTypeFillRegion: return "EmfPlusRecordTypeFillRegion";
92 case EmfPlusRecordTypeFillPath: return "EmfPlusRecordTypeFillPath";
93 case EmfPlusRecordTypeDrawPath: return "EmfPlusRecordTypeDrawPath";
94 case EmfPlusRecordTypeDrawBeziers: return "EmfPlusRecordTypeDrawBeziers";
95 case EmfPlusRecordTypeDrawImage: return "EmfPlusRecordTypeDrawImage";
96 case EmfPlusRecordTypeDrawImagePoints: return "EmfPlusRecordTypeDrawImagePoints";
97 case EmfPlusRecordTypeDrawString: return "EmfPlusRecordTypeDrawString";
98 case EmfPlusRecordTypeSetRenderingOrigin: return "EmfPlusRecordTypeSetRenderingOrigin";
99 case EmfPlusRecordTypeSetAntiAliasMode: return "EmfPlusRecordTypeSetAntiAliasMode";
100 case EmfPlusRecordTypeSetTextRenderingHint: return "EmfPlusRecordTypeSetTextRenderingHint";
101 case EmfPlusRecordTypeSetTextContrast: return "EmfPlusRecordTypeSetTextContrast";
102 case EmfPlusRecordTypeSetInterpolationMode: return "EmfPlusRecordTypeSetInterpolationMode";
103 case EmfPlusRecordTypeSetPixelOffsetMode: return "EmfPlusRecordTypeSetPixelOffsetMode";
104 case EmfPlusRecordTypeSetCompositingQuality: return "EmfPlusRecordTypeSetCompositingQuality";
105 case EmfPlusRecordTypeSave: return "EmfPlusRecordTypeSave";
106 case EmfPlusRecordTypeRestore: return "EmfPlusRecordTypeRestore";
107 case EmfPlusRecordTypeBeginContainer: return "EmfPlusRecordTypeBeginContainer";
108 case EmfPlusRecordTypeBeginContainerNoParams: return "EmfPlusRecordTypeBeginContainerNoParams";
109 case EmfPlusRecordTypeEndContainer: return "EmfPlusRecordTypeEndContainer";
110 case EmfPlusRecordTypeSetWorldTransform: return "EmfPlusRecordTypeSetWorldTransform";
111 case EmfPlusRecordTypeResetWorldTransform: return "EmfPlusRecordTypeResetWorldTransform";
112 case EmfPlusRecordTypeMultiplyWorldTransform: return "EmfPlusRecordTypeMultiplyWorldTransform";
113 case EmfPlusRecordTypeTranslateWorldTransform: return "EmfPlusRecordTypeTranslateWorldTransform";
114 case EmfPlusRecordTypeScaleWorldTransform: return "EmfPlusRecordTypeScaleWorldTransform";
115 case EmfPlusRecordTypeSetPageTransform: return "EmfPlusRecordTypeSetPageTransform";
116 case EmfPlusRecordTypeResetClip: return "EmfPlusRecordTypeResetClip";
117 case EmfPlusRecordTypeSetClipRect: return "EmfPlusRecordTypeSetClipRect";
118 case EmfPlusRecordTypeSetClipPath: return "EmfPlusRecordTypeSetClipPath";
119 case EmfPlusRecordTypeSetClipRegion: return "EmfPlusRecordTypeSetClipRegion";
120 case EmfPlusRecordTypeOffsetClip: return "EmfPlusRecordTypeOffsetClip";
121 case EmfPlusRecordTypeDrawDriverString: return "EmfPlusRecordTypeDrawDriverString";
122 }
123 return "";
124 }
125
126 static OUString emfObjectToName(sal_uInt16 type)
127 {
128 switch (type)
129 {
130 case EmfPlusObjectTypeBrush: return "EmfPlusObjectTypeBrush";
131 case EmfPlusObjectTypePen: return "EmfPlusObjectTypePen";
132 case EmfPlusObjectTypePath: return "EmfPlusObjectTypePath";
133 case EmfPlusObjectTypeRegion: return "EmfPlusObjectTypeRegion";
134 case EmfPlusObjectTypeImage: return "EmfPlusObjectTypeImage";
135 case EmfPlusObjectTypeFont: return "EmfPlusObjectTypeFont";
136 case EmfPlusObjectTypeStringFormat: return "EmfPlusObjectTypeStringFormat";
137 case EmfPlusObjectTypeImageAttributes: return "EmfPlusObjectTypeImageAttributes";
138 case EmfPlusObjectTypeCustomLineCap: return "EmfPlusObjectTypeCustomLineCap";
139 }
140 return "";
141 }
142
143 static OUString PixelOffsetModeToString(sal_uInt16 nPixelOffset)
144 {
145 switch (nPixelOffset)
146 {
147 case PixelOffsetMode::PixelOffsetModeDefault: return "PixelOffsetModeDefault";
148 case PixelOffsetMode::PixelOffsetModeHighSpeed: return "PixelOffsetModeHighSpeed";
149 case PixelOffsetMode::PixelOffsetModeHighQuality: return "PixelOffsetModeHighQuality";
150 case PixelOffsetMode::PixelOffsetModeNone: return "PixelOffsetModeNone";
151 case PixelOffsetMode::PixelOffsetModeHalf: return "PixelOffsetModeHalf";
152 }
153 return "";
154 }
155
156 static OUString SmoothingModeToString(sal_uInt16 nSmoothMode)
157 {
158 switch (nSmoothMode)
159 {
160 case SmoothingMode::SmoothingModeDefault: return "SmoothingModeDefault";
161 case SmoothingMode::SmoothingModeHighSpeed: return "SmoothModeHighSpeed";
162 case SmoothingMode::SmoothingModeHighQuality: return "SmoothingModeHighQuality";
163 case SmoothingMode::SmoothingModeNone: return "SmoothingModeNone";
164 case SmoothingMode::SmoothingModeAntiAlias8x4: return "SmoothingModeAntiAlias8x4";
165 case SmoothingMode::SmoothingModeAntiAlias8x8: return "SmoothingModeAntiAlias8x8";
166 }
167 return "";
168 }
169
170 static OUString TextRenderingHintToString(sal_uInt16 nHint)
171 {
172 switch (nHint)
173 {
174 case TextRenderingHint::TextRenderingHintSystemDefault: return "TextRenderingHintSystemDefault";
175 case TextRenderingHint::TextRenderingHintSingleBitPerPixelGridFit: return "TextRenderingHintSingleBitPerPixelGridFit";
176 case TextRenderingHint::TextRenderingHintSingleBitPerPixel: return "TextRenderingHintSingleBitPerPixel";
177 case TextRenderingHint::TextRenderingHintAntialiasGridFit: return "TextRenderingHintAntialiasGridFit";
178 case TextRenderingHint::TextRenderingHintAntialias: return "TextRenderingHintAntialias";
179 case TextRenderingHint::TextRenderingHintClearTypeGridFit: return "TextRenderingHintClearTypeGridFit";
180 }
181 return "";
182 }
183
184 static OUString InterpolationModeToString(sal_uInt16 nMode)
185 {
186 switch (nMode)
187 {
188 case InterpolationMode::InterpolationModeDefault: return "InterpolationModeDefault";
189 case InterpolationMode::InterpolationModeLowQuality: return "InterpolationModeLowQuality";
190 case InterpolationMode::InterpolationModeHighQuality: return "InterpolationModeHighQuality";
191 case InterpolationMode::InterpolationModeBilinear: return "InterpolationModeBilinear";
192 case InterpolationMode::InterpolationModeBicubic: return "InterpolationModeBicubic";
193 case InterpolationMode::InterpolationModeNearestNeighbor: return "InterpolationModeNearestNeighbor";
194 case InterpolationMode::InterpolationModeHighQualityBilinear: return "InterpolationModeHighQualityBilinear";
195 case InterpolationMode::InterpolationModeHighQualityBicubic: return "InterpolationModeHighQualityBicubic";
196 }
197 return "";
198 }
199
200 OUString UnitTypeToString(sal_uInt16 nType)
201 {
202 switch (nType)
203 {
204 case UnitTypeWorld: return "UnitTypeWorld";
205 case UnitTypeDisplay: return "UnitTypeDisplay";
206 case UnitTypePixel: return "UnitTypePixel";
207 case UnitTypePoint: return "UnitTypePoint";
208 case UnitTypeInch: return "UnitTypeInch";
209 case UnitTypeDocument: return "UnitTypeDocument";
210 case UnitTypeMillimeter: return "UnitTypeMillimeter";
211 }
212 return "";
213 }
214
215 static bool IsBrush(sal_uInt16 flags)
216 {
217 return (!((flags >> 15) & 0x0001));
218 }
219
220 static OUString BrushIDToString(sal_uInt16 flags, sal_uInt32 brushid)
221 {
222 if (IsBrush(flags))
223 return "EmfPlusBrush ID: " + OUString::number(brushid);
224 else
225 return "ARGB: 0x" + OUString::number(brushid, 16);
226 }
227
229 {
230 }
231
232 float EmfPlusHelperData::getUnitToPixelMultiplier(const UnitType aUnitType, const sal_uInt32 aDPI)
233 {
234 switch (aUnitType)
235 {
236 case UnitTypePixel:
237 return 1.0f;
238
239 case UnitTypePoint:
240 return aDPI / 72.0;
241
242 case UnitTypeInch:
243 return aDPI;
244
246 return aDPI / 25.4;
247
248 case UnitTypeDocument:
249 return aDPI / 300.0;
250
251 case UnitTypeWorld:
252 case UnitTypeDisplay:
253 SAL_WARN("drawinglayer.emf", "EMF+\t Converting to World/Display.");
254 return 1.0f;
255
256 default:
257 SAL_WARN("drawinglayer.emf", "EMF+\tTODO Unimplemented support of Unit Type: 0x" << std::hex << aUnitType);
258 return 1.0f;
259 }
260 }
261
262 void EmfPlusHelperData::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags, sal_uInt32 dataSize, bool bUseWholeStream)
263 {
264 sal_uInt16 objecttype = flags & 0x7f00;
265 sal_uInt16 index = flags & 0xff;
266 SAL_INFO("drawinglayer.emf", "EMF+ Object: " << emfObjectToName(objecttype) << " (0x" << objecttype << ")");
267 SAL_INFO("drawinglayer.emf", "EMF+\tObject slot: " << index);
268 SAL_INFO("drawinglayer.emf", "EMF+\tFlags: " << (flags & 0xff00));
269
270 switch (objecttype)
271 {
273 {
274 EMFPBrush *brush = new EMFPBrush();
275 maEMFPObjects[index].reset(brush);
276 brush->Read(rObjectStream, *this);
277 break;
278 }
280 {
281 EMFPPen *pen = new EMFPPen();
282 maEMFPObjects[index].reset(pen);
283 pen->Read(rObjectStream, *this);
284 pen->penWidth = pen->penWidth * getUnitToPixelMultiplier(static_cast<UnitType>(pen->penUnit), mnHDPI);
285 break;
286 }
288 {
289 sal_uInt32 aVersion, aPathPointCount, aPathPointFlags;
290
291 rObjectStream.ReadUInt32(aVersion).ReadUInt32(aPathPointCount).ReadUInt32(aPathPointFlags);
292 SAL_INFO("drawinglayer.emf", "EMF+\t\tVersion: 0x" << std::hex << aVersion);
293 SAL_INFO("drawinglayer.emf", "EMF+\t\tNumber of points: " << std::dec << aPathPointCount);
294 SAL_INFO("drawinglayer.emf", "EMF+\t\tPath point flags: 0x" << std::hex << aPathPointFlags << std::dec);
295 EMFPPath *path = new EMFPPath(aPathPointCount);
296 maEMFPObjects[index].reset(path);
297 path->Read(rObjectStream, aPathPointFlags);
298 break;
299 }
301 {
302 EMFPRegion *region = new EMFPRegion();
303 maEMFPObjects[index].reset(region);
304 region->ReadRegion(rObjectStream, *this);
305 break;
306 }
308 {
309 EMFPImage *image = new EMFPImage;
310 maEMFPObjects[index].reset(image);
311 image->type = 0;
312 image->width = 0;
313 image->height = 0;
314 image->stride = 0;
315 image->pixelFormat = 0;
316 image->Read(rObjectStream, dataSize, bUseWholeStream);
317 break;
318 }
320 {
321 EMFPFont *font = new EMFPFont;
322 maEMFPObjects[index].reset(font);
323 font->emSize = 0;
324 font->sizeUnit = 0;
325 font->fontFlags = 0;
326 font->Read(rObjectStream);
327 // tdf#113624 Convert unit to Pixels
328 font->emSize = font->emSize * getUnitToPixelMultiplier(static_cast<UnitType>(font->sizeUnit), mnHDPI);
329
330 break;
331 }
333 {
334 EMFPStringFormat *stringFormat = new EMFPStringFormat();
335 maEMFPObjects[index].reset(stringFormat);
336 stringFormat->Read(rObjectStream);
337 break;
338 }
340 {
341 EMFPImageAttributes *imageAttributes = new EMFPImageAttributes();
342 maEMFPObjects[index].reset(imageAttributes);
343 imageAttributes->Read(rObjectStream);
344 break;
345 }
347 {
348 SAL_WARN("drawinglayer.emf", "EMF+\t TODO Object type 'custom line cap' not yet implemented");
349 break;
350 }
351 default:
352 {
353 SAL_WARN("drawinglayer.emf", "EMF+\t TODO Object unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
354 }
355 }
356 }
357
358 void EmfPlusHelperData::ReadPoint(SvStream& s, float& x, float& y, sal_uInt32 flags)
359 {
360 if (flags & 0x800)
361 {
362 // specifies a location in the coordinate space that is relative to
363 // the location specified by the previous element in the array. In the case of the first element in
364 // PointData, a previous location at coordinates (0,0) is assumed.
365 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO Relative coordinates bit detected. Implement parse EMFPlusPointR");
366 }
367
368 if (flags & 0x4000)
369 {
370 sal_Int16 ix, iy;
371
372 s.ReadInt16(ix).ReadInt16(iy);
373
374 x = ix;
375 y = iy;
376 }
377 else
378 {
380 }
381 }
382
383 void EmfPlusHelperData::ReadRectangle(SvStream& s, float& x, float& y, float &width, float& height, bool bCompressed)
384 {
385 if (bCompressed)
386 {
387 sal_Int16 ix, iy, iw, ih;
388
389 s.ReadInt16(ix).ReadInt16(iy).ReadInt16(iw).ReadInt16(ih);
390
391 x = ix;
392 y = iy;
393 width = iw;
394 height = ih;
395 }
396 else
397 {
398 s.ReadFloat(x).ReadFloat(y).ReadFloat(width).ReadFloat(height);
399 }
400 }
401
403 {
404 rTarget.identity();
405
406 if (sizeof(float) != 4)
407 {
408 OSL_FAIL("EnhWMFReader::sizeof( float ) != 4");
409 return false;
410 }
411 else
412 {
413 float eM11(0.0);
414 float eM12(0.0);
415 float eM21(0.0);
416 float eM22(0.0);
417 float eDx(0.0);
418 float eDy(0.0);
419 rIn.ReadFloat(eM11).ReadFloat(eM12).ReadFloat(eM21).ReadFloat(eM22).ReadFloat(eDx).ReadFloat(eDy);
421 eM11, eM21, eDx,
422 eM12, eM22, eDy);
423 }
424
425 return true;
426 }
427
429 {
430 if (mnPixX == 0 || mnPixY == 0)
431 {
432 SAL_WARN("drawinglayer.emf", "dimensions in pixels is 0");
433 return;
434 }
435 // Call when mnMmX/mnMmY/mnPixX/mnPixY/mnFrameLeft/mnFrameTop/maWorldTransform/ changes.
436 // Currently not used are mnHDPI/mnVDPI/mnFrameRight/mnFrameBottom. *If* these should
437 // be used in the future, this method will need to be called.
438 //
439 // Re-calculate maMapTransform to contain the complete former transformation so that
440 // it can be applied by a single matrix multiplication or be added to an encapsulated
441 // primitive later
442 //
443 // To evtl. correct and see where this came from, please compare with the implementations
444 // of EmfPlusHelperData::MapToDevice and EmfPlusHelperData::Map* in prev versions
447 double(-mnFrameLeft), double(-mnFrameTop));
449
450 // Used only for performance optimization, to do not calculate it every line draw
453 }
454
455 ::basegfx::B2DPoint EmfPlusHelperData::Map(double ix, double iy) const
456 {
457 // map in one step using complete MapTransform (see mappingChanged)
458 return maMapTransform * ::basegfx::B2DPoint(ix, iy);
459 }
460
461 Color EmfPlusHelperData::EMFPGetBrushColorOrARGBColor(const sal_uInt16 flags, const sal_uInt32 brushIndexOrColor) const {
462 Color color;
463 if (flags & 0x8000) // we use a color
464 {
465 color = Color(ColorAlpha, (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff,
466 (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff);
467 }
468 else // we use a brush
469 {
470 const EMFPBrush* brush = dynamic_cast<EMFPBrush*>(maEMFPObjects[brushIndexOrColor & 0xff].get());
471 if (brush)
472 {
473 color = brush->GetColor();
474 if (brush->type != BrushTypeSolidColor)
475 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO Brush other than solid color is not supported");
476 }
477 }
478 return color;
479 }
480
482 {
483 GraphicStateMap::iterator iter = map.find( index );
484
485 if ( iter != map.end() )
486 {
487 map.erase( iter );
488 SAL_INFO("drawinglayer.emf", "EMF+\t\tStack index: " << index << " found and erased");
489 }
490
492 // tdf#112500 We need to save world transform somehow, during graphic state push
494 map[ index ] = state;
495 }
496
498 {
499 GraphicStateMap::iterator iter = map.find(index);
500
501 if (iter != map.end())
502 {
503 wmfemfhelper::PropertyHolder state = iter->second;
504
506 if (state.getClipPolyPolygonActive())
507 {
508 SAL_INFO("drawinglayer.emf",
509 "EMF+\t Restore clipping region to saved in index: " << index);
512 }
513 else
514 {
515 SAL_INFO("drawinglayer.emf", "EMF+\t Disable clipping");
518 }
520 SAL_INFO("drawinglayer.emf",
521 "EMF+\t\tStack index: " << index
522 << " found, maWorldTransform: " << maWorldTransform);
523 }
524 }
525
527 EmfPlusHelperData::CreateLineEnd(const sal_Int32 aCap, const float aPenWidth) const
528 {
529 const double pw = mdExtractedYScale * aPenWidth;
530 if (aCap == LineCapTypeSquare)
531 {
532 basegfx::B2DPolygon aCapPolygon(
533 { {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} });
534 aCapPolygon.setClosed(true);
536 pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
537 }
538 else if (aCap == LineCapTypeRound)
539 {
540 basegfx::B2DPolygon aCapPolygon(
541 { {-1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.9236, -0.3827},
542 {0.7071, -0.7071}, {0.3827, -0.9236}, {0.0, -1.0}, {-0.3827, -0.9236},
543 {-0.7071, -0.7071}, {-0.9236, -0.3827}, {-1.0, 0.0} });
544 aCapPolygon.setClosed(true);
546 pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
547 }
548 else if (aCap == LineCapTypeTriangle)
549 {
550 basegfx::B2DPolygon aCapPolygon(
551 { {-1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, -1.0}, {-1.0, 0.0} });
552 aCapPolygon.setClosed(true);
554 pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
555 }
556 else if (aCap == LineCapTypeSquareAnchor)
557 {
558 basegfx::B2DPolygon aCapPolygon(
559 { {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} });
560 aCapPolygon.setClosed(true);
562 1.5 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
563 }
564 else if (aCap == LineCapTypeRoundAnchor)
565 {
566 const basegfx::B2DPolygon aCapPolygon
567 = ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(0.0, 0.0), 1.0, 1.0);
569 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
570 }
571 else if (aCap == LineCapTypeDiamondAnchor)
572 {
573 basegfx::B2DPolygon aCapPolygon({ {0.0, -1.0}, {1.0, 0.0}, {0.5, 0.5},
574 {0.5, 1.0}, {-0.5, 1.0}, {-0.5, 0.5},
575 {-1.0, 0.0} });
576 aCapPolygon.setClosed(true);
578 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
579 }
580 else if (aCap == LineCapTypeArrowAnchor)
581 {
582 basegfx::B2DPolygon aCapPolygon({ {0.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} });
583 aCapPolygon.setClosed(true);
585 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
586 }
588 }
589
590 void EmfPlusHelperData::EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon,
591 sal_uInt32 penIndex)
592 {
593 const EMFPPen* pen = dynamic_cast<EMFPPen*>(maEMFPObjects[penIndex & 0xff].get());
594 SAL_WARN_IF(!pen, "drawinglayer.emf", "emf+ missing pen");
595
596 if (!(pen && polygon.count()))
597 return;
598
599 const double transformedPenWidth = mdExtractedYScale * pen->penWidth;
601 pen->GetColor().getBColor(), transformedPenWidth, pen->maLineJoin,
602 css::drawing::LineCap_BUTT, //TODO implement PenDataDashedLineCap support here
603 pen->fMiterMinimumAngle);
604
607 {
609 && (pen->customStartCap->polygon.begin()->count() > 1))
611 pen->customStartCap->polygon.getB2DRange().getRange().getX() * mdExtractedXScale
612 * pen->customStartCap->widthScale * pen->penWidth,
613 pen->customStartCap->polygon, false);
614 else
616 }
617
620 {
622 && (pen->customEndCap->polygon.begin()->count() > 1))
624 pen->customEndCap->polygon.getB2DRange().getRange().getX() * mdExtractedXScale
625 * pen->customEndCap->widthScale * pen->penWidth,
626 pen->customEndCap->polygon, false);
627 else
629 }
630
631 if (pen->GetColor().IsTransparent())
632 {
634 if (aStart.isDefault() && aEnd.isDefault())
637 polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale))));
638 else
639 {
640 aContainer.resize(polygon.count());
641 for (sal_uInt32 i = 0; i < polygon.count(); i++)
644 polygon.getB2DPolygon(i), lineAttribute,
645 pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd));
646 }
649 std::move(aContainer), (255 - pen->GetColor().GetAlpha()) / 255.0));
650 }
651 else
652 {
653 if (aStart.isDefault() && aEnd.isDefault())
656 polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale)));
657 else
658 for (sal_uInt32 i = 0; i < polygon.count(); i++)
659 {
662 polygon.getB2DPolygon(i), lineAttribute,
663 pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd));
664 }
665 }
669 }
670
671 void EmfPlusHelperData::EMFPPlusFillPolygonSolidColor(const ::basegfx::B2DPolyPolygon& polygon, Color const& color)
672 {
673 if (color.GetAlpha() == 0)
674 return;
675
676 if (!color.IsTransparent())
677 {
678 // not transparent
681 polygon,
682 color.getBColor()));
683 }
684 else
685 {
688 polygon,
689 color.getBColor()));
690
694 (255 - color.GetAlpha()) / 255.0));
695 }
696 }
697
698 void EmfPlusHelperData::EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, const bool isColor, const sal_uInt32 brushIndexOrColor)
699 {
700 if (!polygon.count())
701 return;
702
703 if (isColor) // use Color
704 {
705 SAL_INFO("drawinglayer.emf", "EMF+\t\t Fill polygon, ARGB color: 0x" << std::hex << brushIndexOrColor << std::dec);
706
707 // EMF Alpha (1 byte): An 8-bit unsigned integer that specifies the transparency of the background,
708 // ranging from 0 for completely transparent to 0xFF for completely opaque.
709 const Color color(ColorAlpha, (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff);
711
715 }
716 else // use Brush
717 {
718 EMFPBrush* brush = dynamic_cast<EMFPBrush*>(maEMFPObjects[brushIndexOrColor & 0xff].get());
719 SAL_INFO("drawinglayer.emf", "EMF+\t\t Fill polygon, brush slot: " << brushIndexOrColor << " (brush type: " << (brush ? brush->GetType() : -1) << ")");
720
721 // give up in case something wrong happened
722 if( !brush )
723 return;
724
727
728 if (brush->type == BrushTypeSolidColor)
729 {
730 Color fillColor = brush->solidColor;
731 EMFPPlusFillPolygonSolidColor(polygon, fillColor);
732 }
733 else if (brush->type == BrushTypeHatchFill)
734 {
735 // EMF+ like hatching is currently not supported. These are just color blends which serve as an approximation for some of them
736 // for the others the hatch "background" color (secondColor in brush) is used.
737
738 bool isHatchBlend = true;
739 double blendFactor = 0.0;
740
741 switch (brush->hatchStyle)
742 {
743 case HatchStyle05Percent: blendFactor = 0.05; break;
744 case HatchStyle10Percent: blendFactor = 0.10; break;
745 case HatchStyle20Percent: blendFactor = 0.20; break;
746 case HatchStyle25Percent: blendFactor = 0.25; break;
747 case HatchStyle30Percent: blendFactor = 0.30; break;
748 case HatchStyle40Percent: blendFactor = 0.40; break;
749 case HatchStyle50Percent: blendFactor = 0.50; break;
750 case HatchStyle60Percent: blendFactor = 0.60; break;
751 case HatchStyle70Percent: blendFactor = 0.70; break;
752 case HatchStyle75Percent: blendFactor = 0.75; break;
753 case HatchStyle80Percent: blendFactor = 0.80; break;
754 case HatchStyle90Percent: blendFactor = 0.90; break;
755 default:
756 isHatchBlend = false;
757 break;
758 }
759 Color fillColor;
760 if (isHatchBlend)
761 {
762 fillColor = brush->solidColor;
763 fillColor.Merge(brush->secondColor, static_cast<sal_uInt8>(255 * blendFactor));
764 }
765 else
766 {
767 fillColor = brush->secondColor;
768 }
769 // temporal solution: create a solid colored polygon
770 // TODO create a 'real' hatching primitive
773 polygon,
774 fillColor.getBColor()));
775 }
776 else if (brush->type == BrushTypeTextureFill)
777 {
778 SAL_WARN("drawinglayer.emf", "EMF+\tTODO: implement BrushTypeTextureFill brush");
779 }
780 else if (brush->type == BrushTypePathGradient || brush->type == BrushTypeLinearGradient)
781
782 {
783 if (brush->type == BrushTypePathGradient && !(brush->additionalFlags & 0x1))
784 {
785 SAL_WARN("drawinglayer.emf", "EMF+\t TODO Implement displaying BrushTypePathGradient with Boundary: ");
786 }
787 ::basegfx::B2DHomMatrix aTextureTransformation;
788
789 if (brush->hasTransformation) {
790 aTextureTransformation = brush->brush_transformation;
791
792 // adjust aTextureTransformation for our world space:
793 // -> revert the mapping -> apply the transformation -> map back
794 basegfx::B2DHomMatrix aInvertedMapTrasform(maMapTransform);
795 aInvertedMapTrasform.invert();
796 aTextureTransformation = maMapTransform * aTextureTransformation * aInvertedMapTrasform;
797 }
798
799 // select the stored colors
800 const basegfx::BColor aStartColor = brush->solidColor.getBColor();
801 const basegfx::BColor aEndColor = brush->secondColor.getBColor();
803
804 if (brush->blendPositions)
805 {
806 SAL_INFO("drawinglayer.emf", "EMF+\t\tUse blend");
807
808 // store the blendpoints in the vector
809 for (sal_uInt32 i = 0; i < brush->blendPoints; i++)
810 {
811 const double aBlendPoint = brush->blendPositions[i];
812 basegfx::BColor aColor;
813 aColor.setGreen(aStartColor.getGreen() + brush->blendFactors[i] * (aEndColor.getGreen() - aStartColor.getGreen()));
814 aColor.setBlue (aStartColor.getBlue() + brush->blendFactors[i] * (aEndColor.getBlue() - aStartColor.getBlue()));
815 aColor.setRed (aStartColor.getRed() + brush->blendFactors[i] * (aEndColor.getRed() - aStartColor.getRed()));
816 const double aAlpha = brush->solidColor.GetAlpha() + brush->blendFactors[i] * (brush->secondColor.GetAlpha() - brush->solidColor.GetAlpha());
817 aVector.emplace_back(aBlendPoint, aColor, aAlpha / 255.0);
818 }
819 }
820 else if (brush->colorblendPositions)
821 {
822 SAL_INFO("drawinglayer.emf", "EMF+\t\tUse color blend");
823
824 // store the colorBlends in the vector
825 for (sal_uInt32 i = 0; i < brush->colorblendPoints; i++)
826 {
827 const double aBlendPoint = brush->colorblendPositions[i];
828 const basegfx::BColor aColor = brush->colorblendColors[i].getBColor();
829 aVector.emplace_back(aBlendPoint, aColor, brush->colorblendColors[i].GetAlpha() / 255.0);
830 }
831 }
832 else // ok, no extra points: just start and end
833 {
834 aVector.emplace_back(0.0, aStartColor, brush->solidColor.GetAlpha() / 255.0);
835 aVector.emplace_back(1.0, aEndColor, brush->secondColor.GetAlpha() / 255.0);
836 }
837
838 // get the polygon range to be able to map the start/end/center point correctly
839 // therefore, create a mapping and invert it
840 basegfx::B2DRange aPolygonRange= polygon.getB2DRange();
842 aPolygonRange.getWidth(),aPolygonRange.getHeight(),
843 aPolygonRange.getMinX(), aPolygonRange.getMinY());
844 aPolygonTransformation.invert();
845
846 if (brush->type == BrushTypeLinearGradient)
847 {
848 // support for public enum EmfPlusWrapMode
849 basegfx::B2DPoint aStartPoint = Map(brush->firstPointX, 0.0);
850 aStartPoint = aPolygonTransformation * aStartPoint;
851 basegfx::B2DPoint aEndPoint = Map(brush->firstPointX + brush->aWidth, 0.0);
852 aEndPoint = aPolygonTransformation * aEndPoint;
853
854 // support for public enum EmfPlusWrapMode
856 switch(brush->wrapMode)
857 {
858 case WrapModeTile:
860 {
862 break;
863 }
866 {
868 break;
869 }
870 default:
871 break;
872 }
873
874 // create the same one used for SVG
877 aTextureTransformation,
878 polygon,
879 std::move(aVector),
880 aStartPoint,
881 aEndPoint,
882 false, // do not use UnitCoordinates
883 aSpreadMethod));
884 }
885 else // BrushTypePathGradient
886 { // TODO The PathGradient is not implemented, and Radial Gradient is used instead
887 basegfx::B2DPoint aCenterPoint = Map(brush->firstPointX, brush->firstPointY);
888 aCenterPoint = aPolygonTransformation * aCenterPoint;
889
890 // create the same one used for SVG
893 aTextureTransformation,
894 polygon,
895 std::move(aVector),
896 aCenterPoint,
897 0.7, // relative radius little bigger to cover all elements
898 true, // use UnitCoordinates to stretch the gradient
900 nullptr));
901 }
902 }
903 }
904 }
905
907 SvMemoryStream& rMS,
908 wmfemfhelper::TargetHolders& rTargetHolders,
909 wmfemfhelper::PropertyHolders& rPropertyHolders)
910 : mfPageScale(0.0),
911 mnOriginX(0),
912 mnOriginY(0),
913 mnHDPI(0),
914 mnVDPI(0),
915 mbSetTextContrast(false),
916 mnTextContrast(0),
917 mnFrameLeft(0),
918 mnFrameTop(0),
919 mnFrameRight(0),
920 mnFrameBottom(0),
921 mnPixX(0),
922 mnPixY(0),
923 mnMmX(0),
924 mnMmY(0),
925 mbMultipart(false),
926 mMFlags(0),
927 mdExtractedXScale(1.0),
928 mdExtractedYScale(1.0),
929 mrTargetHolders(rTargetHolders),
930 mrPropertyHolders(rPropertyHolders),
931 bIsGetDCProcessing(false)
932 {
934 SAL_INFO("drawinglayer.emf", "EMF+ picture frame: " << mnFrameLeft << "," << mnFrameTop << " - " << mnFrameRight << "," << mnFrameBottom);
936 SAL_INFO("drawinglayer.emf", "EMF+ ref device pixel size: " << mnPixX << "x" << mnPixY << " mm size: " << mnMmX << "x" << mnMmY);
938 SAL_INFO("drawinglayer.emf", "EMF+ base transform: " << maBaseTransform);
940 }
941
943 {
944 }
945
947 {
948 basegfx::B2DPolyPolygon aClippedPolyPolygon;
949 switch (combineMode)
950 {
952 {
953 aClippedPolyPolygon = rightPolygon;
954 break;
955 }
957 {
959 leftPolygon, rightPolygon, true, false);
960 break;
961 }
963 {
964 aClippedPolyPolygon = ::basegfx::utils::solvePolygonOperationOr(leftPolygon, rightPolygon);
965 break;
966 }
968 {
969 aClippedPolyPolygon = ::basegfx::utils::solvePolygonOperationXor(leftPolygon, rightPolygon);
970 break;
971 }
973 {
974 // Replaces the existing region with the part of itself that is not in the new region.
975 aClippedPolyPolygon = ::basegfx::utils::solvePolygonOperationDiff(leftPolygon, rightPolygon);
976 break;
977 }
979 {
980 // Replaces the existing region with the part of the new region that is not in the existing region.
981 aClippedPolyPolygon = ::basegfx::utils::solvePolygonOperationDiff(rightPolygon, leftPolygon);
982 break;
983 }
984 }
985 return aClippedPolyPolygon;
986 }
987
989 SvMemoryStream& rMS,
990 const drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/)
991 {
992 sal_uInt64 length = rMS.GetSize();
993
994 if (length < 12)
995 SAL_WARN("drawinglayer.emf", "length is less than required header size");
996
997 // 12 is minimal valid EMF+ record size; remaining bytes are padding
998 while (length >= 12)
999 {
1000 sal_uInt16 type, flags;
1001 sal_uInt32 size, dataSize;
1002 sal_uInt64 next;
1003
1004 rMS.ReadUInt16(type).ReadUInt16(flags).ReadUInt32(size).ReadUInt32(dataSize);
1005
1006 next = rMS.Tell() + (size - 12);
1007
1008 if (size < 12)
1009 {
1010 SAL_WARN("drawinglayer.emf", "Size field is less than 12 bytes");
1011 break;
1012 }
1013 else if (size > length)
1014 {
1015 SAL_WARN("drawinglayer.emf", "Size field is greater than bytes left");
1016 break;
1017 }
1018
1019 if (dataSize > (size - 12))
1020 {
1021 SAL_WARN("drawinglayer.emf", "DataSize field is greater than Size-12");
1022 break;
1023 }
1024
1025 SAL_INFO("drawinglayer.emf", "EMF+ " << emfTypeToName(type) << " (0x" << std::hex << type << ")" << std::dec);
1026 SAL_INFO("drawinglayer.emf", "EMF+\t record size: " << size);
1027 SAL_INFO("drawinglayer.emf", "EMF+\t flags: 0x" << std::hex << flags << std::dec);
1028 SAL_INFO("drawinglayer.emf", "EMF+\t data size: " << dataSize);
1029
1031 {
1033 {
1034 SAL_INFO("drawinglayer.emf", "EMF+\t Restore region to GetDC saved");
1037 }
1038 else
1039 {
1040 SAL_INFO("drawinglayer.emf", "EMF+\t Disable clipping");
1043 }
1044 bIsGetDCProcessing = false;
1045 }
1046 if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000)))
1047 {
1048 if (!mbMultipart)
1049 {
1050 mbMultipart = true;
1051 mMFlags = flags;
1052 mMStream.Seek(0);
1053 }
1054
1055 OSL_ENSURE(dataSize >= 4, "No room for TotalObjectSize in EmfPlusContinuedObjectRecord");
1056
1057 // 1st 4 bytes are TotalObjectSize
1058 mMStream.WriteBytes(static_cast<const char *>(rMS.GetData()) + rMS.Tell() + 4, dataSize - 4);
1059 SAL_INFO("drawinglayer.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
1060 }
1061 else
1062 {
1063 if (mbMultipart)
1064 {
1065 SAL_INFO("drawinglayer.emf", "EMF+ multipart record flags: " << mMFlags);
1066 mMStream.Seek(0);
1068 }
1069
1070 mbMultipart = false;
1071 }
1072
1073 if (type != EmfPlusRecordTypeObject || !(flags & 0x8000))
1074 {
1075 switch (type)
1076 {
1078 {
1079 sal_uInt32 header, version;
1080
1082 SAL_INFO("drawinglayer.emf", "EMF+\tHeader: 0x" << std::hex << header);
1083 SAL_INFO("drawinglayer.emf", "EMF+\tVersion: " << std::dec << version);
1084 SAL_INFO("drawinglayer.emf", "EMF+\tHorizontal DPI: " << mnHDPI);
1085 SAL_INFO("drawinglayer.emf", "EMF+\tVertical DPI: " << mnVDPI);
1086 SAL_INFO("drawinglayer.emf", "EMF+\tDual: " << ((flags & 1) ? "true" : "false"));
1087 break;
1088 }
1090 {
1091 break;
1092 }
1094 {
1095#if OSL_DEBUG_LEVEL > 1
1096 unsigned char data;
1097 OUString hexdata;
1098
1099 SAL_INFO("drawinglayer.emf", "EMF+\tDatasize: 0x" << std::hex << dataSize << std::dec);
1100
1101 for (sal_uInt32 i=0; i<dataSize; i++)
1102 {
1103 rMS.ReadUChar(data);
1104
1105 if (i % 16 == 0)
1106 hexdata += "\n";
1107
1108 OUString padding;
1109 if ((data & 0xF0) == 0)
1110 padding = "0";
1111
1112 hexdata += "0x" + padding + OUString::number(data, 16) + " ";
1113 }
1114
1115 SAL_INFO("drawinglayer.emf", "EMF+\t" << hexdata);
1116#endif
1117 break;
1118 }
1120 {
1121 bIsGetDCProcessing = true;
1123 SAL_INFO("drawinglayer.emf", "EMF+\tAlready used in svtools wmf/emf filter parser");
1124 break;
1125 }
1127 {
1128 processObjectRecord(rMS, flags, dataSize);
1129 break;
1130 }
1134 {
1135 float startAngle, sweepAngle;
1136
1137 // Silent MSVC warning C4701: potentially uninitialized local variable 'brushIndexOrColor' used
1138 sal_uInt32 brushIndexOrColor = 999;
1139
1141 {
1142 rMS.ReadUInt32(brushIndexOrColor);
1143 SAL_INFO("drawinglayer.emf", "EMF+\t FillPie colorOrIndex: " << brushIndexOrColor);
1144 }
1145 else if (type == EmfPlusRecordTypeDrawPie)
1146 {
1147 SAL_INFO("drawinglayer.emf", "EMF+\t DrawPie");
1148 }
1149 else
1150 {
1151 SAL_INFO("drawinglayer.emf", "EMF+\t DrawArc");
1152 }
1153
1154 rMS.ReadFloat(startAngle).ReadFloat(sweepAngle);
1155 float dx, dy, dw, dh;
1156 ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
1157 SAL_INFO("drawinglayer.emf", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1158 startAngle = basegfx::deg2rad(startAngle);
1159 sweepAngle = basegfx::deg2rad(sweepAngle);
1160 float endAngle = startAngle + sweepAngle;
1161 startAngle = fmodf(startAngle, static_cast<float>(M_PI * 2));
1162
1163 if (startAngle < 0.0)
1164 {
1165 startAngle += static_cast<float>(M_PI * 2.0);
1166 }
1167 endAngle = fmodf(endAngle, static_cast<float>(M_PI * 2.0));
1168
1169 if (endAngle < 0.0)
1170 {
1171 endAngle += static_cast<float>(M_PI * 2.0);
1172 }
1173 if (sweepAngle < 0)
1174 {
1175 std::swap(endAngle, startAngle);
1176 }
1177
1178 SAL_INFO("drawinglayer.emf", "EMF+\t Adjusted angles: start " <<
1179 basegfx::rad2deg(startAngle) << ", end: " << basegfx::rad2deg(endAngle) <<
1180 " startAngle: " << startAngle << " sweepAngle: " << sweepAngle);
1181 const ::basegfx::B2DPoint centerPoint(dx + 0.5 * dw, dy + 0.5 * dh);
1182 ::basegfx::B2DPolygon polygon(
1183 ::basegfx::utils::createPolygonFromEllipseSegment(centerPoint,
1184 0.5 * dw, 0.5 * dh,
1185 startAngle, endAngle));
1187 {
1188 polygon.append(centerPoint);
1189 polygon.setClosed(true);
1190 }
1191 ::basegfx::B2DPolyPolygon polyPolygon(polygon);
1192 polyPolygon.transform(maMapTransform);
1194 EMFPPlusFillPolygon(polyPolygon, flags & 0x8000, brushIndexOrColor);
1195 else
1196 EMFPPlusDrawPolygon(polyPolygon, flags & 0xff);
1197 }
1198 break;
1200 {
1201 sal_uInt32 index = flags & 0xff;
1202 sal_uInt32 brushIndexOrColor;
1203 rMS.ReadUInt32(brushIndexOrColor);
1204 SAL_INFO("drawinglayer.emf", "EMF+ FillPath slot: " << index);
1205
1206 EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[index].get());
1207 if (path)
1208 EMFPPlusFillPolygon(path->GetPolygon(*this), flags & 0x8000, brushIndexOrColor);
1209 else
1210 SAL_WARN("drawinglayer.emf", "EMF+\tEmfPlusRecordTypeFillPath missing path");
1211 }
1212 break;
1214 {
1215 sal_uInt32 index = flags & 0xff;
1216 sal_uInt32 brushIndexOrColor;
1217 rMS.ReadUInt32(brushIndexOrColor);
1218 SAL_INFO("drawinglayer.emf", "EMF+\t FillRegion slot: " << index);
1219
1220 EMFPRegion* region = dynamic_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get());
1221 if (region)
1222 EMFPPlusFillPolygon(region->regionPolyPolygon, flags & 0x8000, brushIndexOrColor);
1223 else
1224 SAL_WARN("drawinglayer.emf", "EMF+\tEmfPlusRecordTypeFillRegion missing region");
1225 }
1226 break;
1229 {
1230 // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
1231 // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
1232 // when it is later used.
1233 sal_uInt32 brushIndexOrColor = 1234567;
1234
1236 {
1237 rMS.ReadUInt32(brushIndexOrColor);
1238 }
1239
1240 SAL_INFO("drawinglayer.emf", "EMF+\t " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
1241 float dx, dy, dw, dh;
1242 ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
1243 SAL_INFO("drawinglayer.emf", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1244 ::basegfx::B2DPolyPolygon polyPolygon(
1245 ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(dx + 0.5 * dw, dy + 0.5 * dh),
1246 0.5 * dw, 0.5 * dh));
1247 polyPolygon.transform(maMapTransform);
1249 EMFPPlusFillPolygon(polyPolygon, flags & 0x8000, brushIndexOrColor);
1250 else
1251 EMFPPlusDrawPolygon(polyPolygon, flags & 0xff);
1252 }
1253 break;
1256 {
1257 // Silent MSVC warning C4701: potentially uninitialized local variable 'brushIndexOrColor' used
1258 sal_uInt32 brushIndexOrColor = 999;
1259 ::basegfx::B2DPolyPolygon polyPolygon;
1260 sal_uInt32 rectangles;
1261 float x, y, width, height;
1262 const bool isColor = (flags & 0x8000);
1263 ::basegfx::B2DPolygon polygon;
1264
1266 {
1267 SAL_INFO("drawinglayer.emf", "EMF+\t FillRects");
1268 rMS.ReadUInt32(brushIndexOrColor);
1269 SAL_INFO("drawinglayer.emf", "EMF+\t" << (isColor ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
1270 }
1271 else
1272 {
1273 SAL_INFO("drawinglayer.emf", "EMF+\t DrawRects");
1274 }
1275
1276 rMS.ReadUInt32(rectangles);
1277 for (sal_uInt32 i = 0; i < rectangles; i++)
1278 {
1279 ReadRectangle(rMS, x, y, width, height, bool(flags & 0x4000));
1280 polygon.clear();
1281 polygon.append(Map(x, y));
1282 polygon.append(Map(x + width, y));
1283 polygon.append(Map(x + width, y + height));
1284 polygon.append(Map(x, y + height));
1285 polygon.setClosed(true);
1286
1287 SAL_INFO("drawinglayer.emf", "EMF+\t\t rectangle: " << x << ", "<< y << " " << width << "x" << height);
1288 polyPolygon.append(polygon);
1289 }
1291 EMFPPlusFillPolygon(polyPolygon, isColor, brushIndexOrColor);
1292 else
1293 EMFPPlusDrawPolygon(polyPolygon, flags & 0xff);
1294 break;
1295 }
1297 {
1298 sal_uInt32 brushIndexOrColor, points;
1299
1300 rMS.ReadUInt32(brushIndexOrColor);
1301 rMS.ReadUInt32(points);
1302 SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points);
1303 SAL_INFO("drawinglayer.emf", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << " : 0x" << std::hex << brushIndexOrColor << std::dec);
1304
1305 EMFPPath path(points, true);
1306 path.Read(rMS, flags);
1307
1308 EMFPPlusFillPolygon(path.GetPolygon(*this), flags & 0x8000, brushIndexOrColor);
1309 break;
1310 }
1312 {
1313 sal_uInt32 points;
1314 rMS.ReadUInt32(points);
1315 SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points);
1316 EMFPPath path(points, true);
1317 path.Read(rMS, flags);
1318
1319 // 0x2000 bit indicates whether to draw an extra line between the last point
1320 // and the first point, to close the shape.
1321 EMFPPlusDrawPolygon(path.GetPolygon(*this, true, (flags & 0x2000)), flags);
1322
1323 break;
1324 }
1326 {
1327 sal_uInt32 penIndex;
1328 rMS.ReadUInt32(penIndex);
1329 SAL_INFO("drawinglayer.emf", "EMF+\t Pen: " << penIndex);
1330
1331 EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get());
1332 if (path)
1333 EMFPPlusDrawPolygon(path->GetPolygon(*this), penIndex);
1334 else
1335 SAL_WARN("drawinglayer.emf", "\t\tEmfPlusRecordTypeDrawPath missing path");
1336
1337 break;
1338 }
1340 {
1341 sal_uInt32 aCount;
1342 float x1, y1, x2, y2, x3, y3, x4, y4;
1343 ::basegfx::B2DPolygon aPolygon;
1344 rMS.ReadUInt32(aCount);
1345 SAL_INFO("drawinglayer.emf", "EMF+\t DrawBeziers slot: " << (flags & 0xff));
1346 SAL_INFO("drawinglayer.emf", "EMF+\t Number of points: " << aCount);
1347 SAL_WARN_IF((aCount - 1) % 3 != 0, "drawinglayer.emf",
1348 "EMF+\t Bezier Draw not support number of points other than 4, 7, "
1349 "10, 13, 16...");
1350
1351 if (aCount < 4)
1352 {
1353 SAL_WARN("drawinglayer.emf", "EMF+\t Bezier Draw does not support less "
1354 "than 4 points. Number of points: "
1355 << aCount);
1356 break;
1357 }
1358
1359 ReadPoint(rMS, x1, y1, flags);
1360 // We need to add first starting point
1361 aPolygon.append(Map(x1, y1));
1362 SAL_INFO("drawinglayer.emf",
1363 "EMF+\t Bezier starting point: " << x1 << "," << y1);
1364 for (sal_uInt32 i = 4; i <= aCount; i += 3)
1365 {
1366 ReadPoint(rMS, x2, y2, flags);
1367 ReadPoint(rMS, x3, y3, flags);
1368 ReadPoint(rMS, x4, y4, flags);
1369
1370 SAL_INFO("drawinglayer.emf",
1371 "EMF+\t Bezier points: " << x2 << "," << y2 << " " << x3 << ","
1372 << y3 << " " << x4 << "," << y4);
1373 aPolygon.appendBezierSegment(Map(x2, y2), Map(x3, y3), Map(x4, y4));
1374 }
1375 EMFPPlusDrawPolygon(::basegfx::B2DPolyPolygon(aPolygon), flags & 0xff);
1376 break;
1377 }
1379 {
1380 sal_uInt32 aOffset, aNumSegments, points;
1381 float aTension;
1382 rMS.ReadFloat(aTension);
1383 rMS.ReadUInt32(aOffset);
1384 rMS.ReadUInt32(aNumSegments);
1385 rMS.ReadUInt32(points);
1386 SAL_WARN("drawinglayer.emf",
1387 "EMF+\t Tension: " << aTension << " Offset: " << aOffset
1388 << " NumSegments: " << aNumSegments
1389 << " Points: " << points);
1390
1391 EMFPPath path(points, true);
1392 path.Read(rMS, flags);
1393
1394 if (points >= 2)
1396 path.GetCardinalSpline(*this, aTension, aOffset, aNumSegments),
1397 flags & 0xff);
1398 else
1399 SAL_WARN("drawinglayer.emf", "Not enough number of points");
1400 break;
1401 }
1404 {
1405 // Silent MSVC warning C4701: potentially uninitialized local variable 'brushIndexOrColor' used
1406 sal_uInt32 brushIndexOrColor = 999, points;
1407 float aTension;
1409 {
1410 rMS.ReadUInt32(brushIndexOrColor);
1411 SAL_INFO(
1412 "drawinglayer.emf",
1413 "EMF+\t Fill Mode: " << (flags & 0x2000 ? "Winding" : "Alternate"));
1414 }
1415 rMS.ReadFloat(aTension);
1416 rMS.ReadUInt32(points);
1417 SAL_WARN("drawinglayer.emf",
1418 "EMF+\t Tension: " << aTension << " Points: " << points);
1419 SAL_INFO("drawinglayer.emf",
1420 "EMF+\t " << (flags & 0x8000 ? "Color" : "Brush index") << " : 0x"
1421 << std::hex << brushIndexOrColor << std::dec);
1422 if (points < 3)
1423 {
1424 SAL_WARN("drawinglayer.emf", "Not enough number of points");
1425 break;
1426 }
1427 EMFPPath path(points, true);
1428 path.Read(rMS, flags);
1430 EMFPPlusFillPolygon(path.GetClosedCardinalSpline(*this, aTension),
1431 flags & 0x8000, brushIndexOrColor);
1432 else
1433 EMFPPlusDrawPolygon(path.GetClosedCardinalSpline(*this, aTension),
1434 flags & 0xff);
1435 break;
1436 }
1439 {
1440 sal_uInt32 imageAttributesId;
1441 sal_Int32 sourceUnit;
1442 rMS.ReadUInt32(imageAttributesId).ReadInt32(sourceUnit);
1443 SAL_INFO("drawinglayer.emf",
1444 "EMF+\t " << (type == EmfPlusRecordTypeDrawImage ? "DrawImage"
1445 : "DrawImagePoints")
1446 << " image attributes Id: " << imageAttributesId
1447 << " source unit: " << sourceUnit);
1448 SAL_INFO("drawinglayer.emf", "EMF+\t TODO: use image attributes");
1449
1450 // Source unit of measurement type must be 1 pixel
1451 if (EMFPImage* image = sourceUnit == UnitTypePixel ?
1452 dynamic_cast<EMFPImage*>(maEMFPObjects[flags & 0xff].get()) :
1453 nullptr)
1454 {
1455 float sx, sy, sw, sh;
1456 ReadRectangle(rMS, sx, sy, sw, sh);
1457
1458 ::tools::Rectangle aSource(Point(sx, sy), Size(sw + 1, sh + 1));
1459 SAL_INFO("drawinglayer.emf",
1460 "EMF+\t "
1461 << (type == EmfPlusRecordTypeDrawImage ? "DrawImage"
1462 : "DrawImagePoints")
1463 << " source rectangle: " << sx << "," << sy << " " << sw << "x"
1464 << sh);
1465
1466 float dx(0.), dy(0.), dw(0.), dh(0.);
1467 double fShearX = 0.0;
1468 double fShearY = 0.0;
1470 {
1471 sal_uInt32 aCount;
1472 rMS.ReadUInt32(aCount);
1473
1474 // Number of points used by DrawImagePoints. Exactly 3 points must be specified.
1475 if (aCount != 3)
1476 {
1477 SAL_WARN("drawinglayer.emf", "EMF+\t Wrong EMF+ file. Expected "
1478 "3 points, received: "
1479 << aCount);
1480 break;
1481 }
1482 float x1, y1, x2, y2, x3, y3;
1483
1484 ReadPoint(rMS, x1, y1, flags); // upper-left point
1485 ReadPoint(rMS, x2, y2, flags); // upper-right
1486 ReadPoint(rMS, x3, y3, flags); // lower-left
1487
1488 SAL_INFO("drawinglayer.emf", "EMF+\t destination points: "
1489 << x1 << "," << y1 << " " << x2 << ","
1490 << y2 << " " << x3 << "," << y3);
1491 dx = x1;
1492 dy = y2;
1493 dw = x2 - x1;
1494 dh = y3 - y1;
1495 fShearX = x3 - x1;
1496 fShearY = y2 - y1;
1497 }
1498 else if (type == EmfPlusRecordTypeDrawImage)
1499 ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
1500
1501 SAL_INFO("drawinglayer.emf",
1502 "EMF+\t Rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
1503 Size aSize;
1504 if (image->type == ImageDataTypeBitmap)
1505 {
1506 aSize = image->graphic.GetBitmapEx().GetSizePixel();
1507 SAL_INFO("drawinglayer.emf", "EMF+\t Bitmap size: " << aSize.Width()
1508 << "x"
1509 << aSize.Height());
1510 if (sx < 0)
1511 {
1512 // If src position is negative then we need shift image to right
1513 dx = dx + ((-sx) / sw) * dw;
1514 if (sx + sw <= aSize.Width())
1515 dw = ((sw + sx) / sw) * dw;
1516 else
1517 dw = (aSize.Width() / sw) * dw;
1518 }
1519 else if (sx + sw > aSize.Width())
1520 // If the src image is smaller that what we want to cut, then we need to scale down
1521 dw = ((aSize.Width() - sx) / sw) * dw;
1522
1523 if (sy < 0)
1524 {
1525 dy = dy + ((-sy) / sh) * dh;
1526 if (sy + sh <= aSize.Height())
1527 dh = ((sh + sy) / sh) * dh;
1528 else
1529 dh = (aSize.Height() / sh) * dh;
1530 }
1531 else if (sy + sh > aSize.Height())
1532 dh = ((aSize.Height() - sy) / sh) * dh;
1533 }
1534 else
1535 SAL_INFO(
1536 "drawinglayer.emf",
1537 "EMF+\t TODO: Add support for SrcRect to ImageDataTypeMetafile");
1538 const ::basegfx::B2DPoint aDstPoint(dx, dy);
1539 const ::basegfx::B2DSize aDstSize(dw, dh);
1540
1541 const basegfx::B2DHomMatrix aTransformMatrix
1544 /* Row 0, Column 0 */ aDstSize.getWidth(),
1545 /* Row 0, Column 1 */ fShearX,
1546 /* Row 0, Column 2 */ aDstPoint.getX(),
1547 /* Row 1, Column 0 */ fShearY,
1548 /* Row 1, Column 1 */ aDstSize.getHeight(),
1549 /* Row 1, Column 2 */ aDstPoint.getY());
1550
1551 if (image->type == ImageDataTypeBitmap)
1552 {
1553 BitmapEx aBmp(image->graphic.GetBitmapEx());
1554 aBmp.Crop(aSource);
1555 aSize = aBmp.GetSizePixel();
1556 if (aSize.Width() > 0 && aSize.Height() > 0)
1557 {
1560 aBmp, aTransformMatrix));
1561 }
1562 else
1563 SAL_WARN("drawinglayer.emf", "EMF+\t warning: empty bitmap");
1564 }
1565 else if (image->type == ImageDataTypeMetafile)
1566 {
1567 GDIMetaFile aGDI(image->graphic.GetGDIMetaFile());
1568 aGDI.Clip(aSource);
1571 aGDI));
1572 }
1573 }
1574 else
1575 {
1576 SAL_WARN("drawinglayer.emf",
1577 "EMF+\tDrawImage(Points) Wrong EMF+ file. Only Unit Type Pixel is "
1578 "support by EMF+ specification for DrawImage(Points)");
1579 }
1580 break;
1581 }
1583 {
1584 sal_uInt32 brushId, formatId, stringLength;
1585 rMS.ReadUInt32(brushId).ReadUInt32(formatId).ReadUInt32(stringLength);
1586 SAL_INFO("drawinglayer.emf", "EMF+\t FontId: " << OUString::number(flags & 0xFF));
1587 SAL_INFO("drawinglayer.emf", "EMF+\t BrushId: " << BrushIDToString(flags, brushId));
1588 SAL_INFO("drawinglayer.emf", "EMF+\t FormatId: " << formatId);
1589 SAL_INFO("drawinglayer.emf", "EMF+\t Length: " << stringLength);
1590
1591 // read the layout rectangle
1592 float lx, ly, lw, lh;
1593 rMS.ReadFloat(lx).ReadFloat(ly).ReadFloat(lw).ReadFloat(lh);
1594
1595 SAL_INFO("drawinglayer.emf", "EMF+\t DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
1596 // parse the string
1597 const OUString text = read_uInt16s_ToOUString(rMS, stringLength);
1598 SAL_INFO("drawinglayer.emf", "EMF+\t DrawString string: " << text);
1599 // get the stringFormat from the Object table ( this is OPTIONAL and may be nullptr )
1600 const EMFPStringFormat *stringFormat = dynamic_cast<EMFPStringFormat*>(maEMFPObjects[formatId & 0xff].get());
1601 // get the font from the flags
1602 const EMFPFont *font = dynamic_cast<EMFPFont*>(maEMFPObjects[flags & 0xff].get());
1603 if (!font)
1604 {
1605 break;
1606 }
1608
1610 font->family, // font family
1611 "", // (no) font style
1612 font->Bold() ? 8u : 1u, // weight: 8 = bold
1613 font->family == "SYMBOL", // symbol
1614 stringFormat && stringFormat->DirectionVertical(), // vertical
1615 font->Italic(), // italic
1616 false, // monospaced
1617 false, // outline = false, no such thing in MS-EMFPLUS
1618 stringFormat && stringFormat->DirectionRightToLeft(), // right-to-left
1619 false); // BiDiStrong
1620
1621 css::lang::Locale locale;
1622 double stringAlignmentHorizontalOffset = 0.0;
1623 double stringAlignmentVerticalOffset = font->emSize;
1624 if (stringFormat)
1625 {
1626 LanguageTag aLanguageTag(static_cast<LanguageType>(stringFormat->language));
1627 locale = aLanguageTag.getLocale();
1629
1630 aTextLayouter.setFontAttribute(fontAttribute, font->emSize,
1631 font->emSize, locale);
1632
1633 double fTextWidth = aTextLayouter.getTextWidth(text, 0, stringLength);
1634 SAL_WARN_IF(stringFormat->DirectionRightToLeft(), "drawinglayer.emf",
1635 "EMF+\t DrawString Alignment TODO For a right-to-left layout rectangle, the origin should be at the upper right.");
1636 if (stringFormat->stringAlignment == StringAlignmentNear)
1637 // Alignment is to the left side of the layout rectangle (lx, ly, lw, lh)
1638 stringAlignmentHorizontalOffset = stringFormat->leadingMargin * font->emSize;
1639 else if (stringFormat->stringAlignment == StringAlignmentCenter)
1640 // Alignment is centered between the origin and extent of the layout rectangle
1641 stringAlignmentHorizontalOffset = 0.5 * lw + (stringFormat->leadingMargin - stringFormat->trailingMargin) * font->emSize - 0.5 * fTextWidth;
1642 else if (stringFormat->stringAlignment == StringAlignmentFar)
1643 // Alignment is to the right side of the layout rectangle
1644 stringAlignmentHorizontalOffset = lw - stringFormat->trailingMargin * font->emSize - fTextWidth;
1645
1646 if (stringFormat->lineAlign == StringAlignmentNear)
1647 stringAlignmentVerticalOffset = font->emSize;
1648 else if (stringFormat->lineAlign == StringAlignmentCenter)
1649 stringAlignmentVerticalOffset = 0.5 * lh + 0.5 * font->emSize;
1650 else if (stringFormat->lineAlign == StringAlignmentFar)
1651 stringAlignmentVerticalOffset = lh;
1652 }
1653 else
1654 {
1655 // By default LeadingMargin is 1/6 inch
1656 // TODO for typographic fonts set value to 0.
1657 stringAlignmentHorizontalOffset = 16.0;
1658
1659 // use system default
1661 }
1662
1664 ::basegfx::B2DVector(font->emSize, font->emSize),
1665 ::basegfx::B2DPoint(lx + stringAlignmentHorizontalOffset,
1666 ly + stringAlignmentVerticalOffset));
1667
1668 Color uncorrectedColor = EMFPGetBrushColorOrARGBColor(flags, brushId);
1669 Color color;
1670
1672 {
1673 const auto gammaVal = mnTextContrast / 1000;
1674 const basegfx::BColorModifier_gamma gamma(gammaVal);
1675
1676 // gamma correct transparency color
1677 sal_uInt16 alpha = uncorrectedColor.GetAlpha();
1678 alpha = std::clamp(std::pow(alpha, 1.0 / gammaVal), 0.0, 1.0) * 255;
1679
1680 basegfx::BColor modifiedColor(gamma.getModifiedColor(uncorrectedColor.getBColor()));
1681 color.SetRed(modifiedColor.getRed() * 255);
1682 color.SetGreen(modifiedColor.getGreen() * 255);
1683 color.SetBlue(modifiedColor.getBlue() * 255);
1684 color.SetAlpha(alpha);
1685 }
1686 else
1687 {
1688 color = uncorrectedColor;
1689 }
1690
1693
1694 if (color.GetAlpha() > 0)
1695 {
1696 std::vector<double> emptyVector;
1698 if (font->Underline() || font->Strikeout())
1699 {
1701 transformMatrix,
1702 text,
1703 0, // text always starts at 0
1704 stringLength,
1705 std::move(emptyVector), // EMF-PLUS has no DX-array
1706 {},
1707 fontAttribute,
1708 locale,
1709 color.getBColor(), // Font Color
1710 COL_TRANSPARENT, // Fill Color
1711 color.getBColor(), // OverlineColor
1712 color.getBColor(), // TextlineColor
1715 false,
1717 }
1718 else
1719 {
1721 transformMatrix,
1722 text,
1723 0, // text always starts at 0
1724 stringLength,
1725 std::move(emptyVector), // EMF-PLUS has no DX-array
1726 {},
1727 fontAttribute,
1728 locale,
1729 color.getBColor());
1730 }
1731 drawinglayer::primitive2d::Primitive2DReference aPrimitiveText(pBaseText);
1732 if (color.IsTransparent())
1733 {
1736 (255 - color.GetAlpha()) / 255.0);
1737 }
1738
1743 }
1744 break;
1745 }
1747 {
1749 SAL_INFO("drawinglayer.emf", "EMF+\t Scale: " << mfPageScale << " unit: " << UnitTypeToString(flags));
1750
1751 if ((flags == UnitTypeDisplay) || (flags == UnitTypeWorld))
1752 {
1753 SAL_WARN("drawinglayer.emf", "EMF+\t file error. UnitTypeDisplay and UnitTypeWorld are not supported by SetPageTransform in EMF+ specification.");
1754 }
1755 else
1756 {
1757 mnMmX *= mfPageScale * getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnHDPI);
1758 mnMmY *= mfPageScale * getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnVDPI);
1760 }
1761 break;
1762 }
1764 {
1766 SAL_INFO("drawinglayer.emf", "EMF+\t SetRenderingOrigin, [x,y]: " << mnOriginX << "," << mnOriginY);
1767 break;
1768 }
1770 {
1771 const sal_uInt16 LOWERGAMMA = 1000;
1772 const sal_uInt16 UPPERGAMMA = 2200;
1773
1774 mbSetTextContrast = true;
1775 mnTextContrast = flags & 0xFFF;
1776 SAL_WARN_IF(mnTextContrast > UPPERGAMMA || mnTextContrast < LOWERGAMMA,
1777 "drawinglayer.emf", "EMF+\t Gamma value is not with bounds 1000 to 2200, value is " << mnTextContrast);
1778 mnTextContrast = std::min(mnTextContrast, UPPERGAMMA);
1779 mnTextContrast = std::max(mnTextContrast, LOWERGAMMA);
1780 SAL_INFO("drawinglayer.emf", "EMF+\t Text contrast: " << (mnTextContrast / 1000) << " gamma");
1781 break;
1782 }
1784 {
1785 sal_uInt8 nTextRenderingHint = (flags & 0xFF) >> 1;
1786 SAL_INFO("drawinglayer.emf", "EMF+\t Text rendering hint: " << TextRenderingHintToString(nTextRenderingHint));
1787 SAL_WARN("drawinglayer.emf", "EMF+\t TODO SetTextRenderingHint");
1788 break;
1789 }
1791 {
1792 bool bUseAntiAlias = (flags & 0x0001);
1793 sal_uInt8 nSmoothingMode = (flags & 0xFE00) >> 1;
1794 SAL_INFO("drawinglayer.emf", "EMF+\t Antialiasing: " << (bUseAntiAlias ? "enabled" : "disabled"));
1795 SAL_INFO("drawinglayer.emf", "EMF+\t Smoothing mode: " << SmoothingModeToString(nSmoothingMode));
1796 SAL_WARN("drawinglayer.emf", "EMF+\t TODO SetAntiAliasMode");
1797 break;
1798 }
1800 {
1801 sal_uInt16 nInterpolationMode = flags & 0xFF;
1802 SAL_INFO("drawinglayer.emf", "EMF+\t Interpolation mode: " << InterpolationModeToString(nInterpolationMode));
1803 SAL_WARN("drawinglayer.emf", "EMF+\t TODO InterpolationMode");
1804 break;
1805 }
1807 {
1808 SAL_INFO("drawinglayer.emf", "EMF+\t Pixel offset mode: " << PixelOffsetModeToString(flags));
1809 SAL_WARN("drawinglayer.emf", "EMF+\t TODO SetPixelOffsetMode");
1810 break;
1811 }
1813 {
1814 SAL_INFO("drawinglayer.emf", "EMF+\t TODO SetCompositingQuality");
1815 break;
1816 }
1818 {
1819 sal_uInt32 stackIndex;
1820 rMS.ReadUInt32(stackIndex);
1821 SAL_INFO("drawinglayer.emf", "EMF+\t Save stack index: " << stackIndex);
1822
1823 GraphicStatePush(mGSStack, stackIndex);
1824
1825 break;
1826 }
1828 {
1829 sal_uInt32 stackIndex;
1830 rMS.ReadUInt32(stackIndex);
1831 SAL_INFO("drawinglayer.emf", "EMF+\t Restore stack index: " << stackIndex);
1832
1833 GraphicStatePop(mGSStack, stackIndex);
1834 break;
1835 }
1837 {
1838 float dx, dy, dw, dh;
1839 ReadRectangle(rMS, dx, dy, dw, dh);
1840 SAL_INFO("drawinglayer.emf", "EMF+\t Dest RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1841
1842 float sx, sy, sw, sh;
1843 ReadRectangle(rMS, sx, sy, sw, sh);
1844 SAL_INFO("drawinglayer.emf", "EMF+\t Source RectData: " << sx << "," << sy << " " << sw << "x" << sh);
1845
1846 sal_uInt32 stackIndex;
1847 rMS.ReadUInt32(stackIndex);
1848 SAL_INFO("drawinglayer.emf", "EMF+\t Begin Container stack index: " << stackIndex << ", PageUnit: " << flags);
1849
1850 if ((flags == UnitTypeDisplay) || (flags == UnitTypeWorld))
1851 {
1852 SAL_WARN("drawinglayer.emf", "EMF+\t file error. UnitTypeDisplay and UnitTypeWorld are not supported by BeginContainer in EMF+ specification.");
1853 break;
1854 }
1855 const float aPageScaleX = getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnHDPI);
1856 const float aPageScaleY = getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnVDPI);
1859 aPageScaleX * ( dw / sw ), aPageScaleY * ( dh / sh ),
1860 aPageScaleX * ( dx - sx ), aPageScaleY * ( dy - sy) );
1861 maWorldTransform *= transform;
1863 break;
1864 }
1866 {
1867 sal_uInt32 stackIndex;
1868 rMS.ReadUInt32(stackIndex);
1869 SAL_INFO("drawinglayer.emf", "EMF+\t Begin Container No Params stack index: " << stackIndex);
1870
1872 break;
1873 }
1875 {
1876 sal_uInt32 stackIndex;
1877 rMS.ReadUInt32(stackIndex);
1878 SAL_INFO("drawinglayer.emf", "EMF+\t End Container stack index: " << stackIndex);
1879
1881 break;
1882 }
1884 {
1885 SAL_INFO("drawinglayer.emf", "EMF+\t SetWorldTransform, Post multiply: " << bool(flags & 0x2000));
1888 SAL_INFO("drawinglayer.emf", "EMF+\t\t: " << maWorldTransform);
1889 break;
1890 }
1892 {
1894 SAL_INFO("drawinglayer.emf", "EMF+\t World transform: " << maWorldTransform);
1896 break;
1897 }
1899 {
1900 SAL_INFO("drawinglayer.emf", "EMF+\t MultiplyWorldTransform, post multiply: " << bool(flags & 0x2000));
1901 basegfx::B2DHomMatrix transform;
1902 readXForm(rMS, transform);
1903
1904 SAL_INFO("drawinglayer.emf",
1905 "EMF+\t Transform matrix: " << transform);
1906
1907 if (flags & 0x2000)
1908 {
1909 // post multiply
1910 maWorldTransform *= transform;
1911 }
1912 else
1913 {
1914 // pre multiply
1915 transform *= maWorldTransform;
1916 maWorldTransform = transform;
1917 }
1918
1920
1921 SAL_INFO("drawinglayer.emf",
1922 "EMF+\t World transform matrix: " << maWorldTransform);
1923 break;
1924 }
1926 {
1927 SAL_INFO("drawinglayer.emf", "EMF+\t TranslateWorldTransform, Post multiply: " << bool(flags & 0x2000));
1928
1929 basegfx::B2DHomMatrix transform;
1930 float eDx, eDy;
1931 rMS.ReadFloat(eDx).ReadFloat(eDy);
1932 transform.set(0, 2, eDx);
1933 transform.set(1, 2, eDy);
1934
1935 SAL_INFO("drawinglayer.emf",
1936 "EMF+\t Translate matrix: " << transform);
1937
1938 if (flags & 0x2000)
1939 {
1940 // post multiply
1941 maWorldTransform *= transform;
1942 }
1943 else
1944 {
1945 // pre multiply
1946 transform *= maWorldTransform;
1947 maWorldTransform = transform;
1948 }
1949
1951
1952 SAL_INFO("drawinglayer.emf",
1953 "EMF+\t World transform matrix: " << maWorldTransform);
1954 break;
1955 }
1957 {
1958 basegfx::B2DHomMatrix transform;
1959 float eSx, eSy;
1960 rMS.ReadFloat(eSx).ReadFloat(eSy);
1961 transform.set(0, 0, eSx);
1962 transform.set(1, 1, eSy);
1963
1964 SAL_INFO("drawinglayer.emf", "EMF+\t ScaleWorldTransform Sx: " << eSx <<
1965 " Sy: " << eSy << ", Post multiply:" << bool(flags & 0x2000));
1966 SAL_INFO("drawinglayer.emf",
1967 "EMF+\t World transform matrix: " << maWorldTransform);
1968
1969 if (flags & 0x2000)
1970 {
1971 // post multiply
1972 maWorldTransform *= transform;
1973 }
1974 else
1975 {
1976 // pre multiply
1977 transform *= maWorldTransform;
1978 maWorldTransform = transform;
1979 }
1980
1982
1983 SAL_INFO("drawinglayer.emf",
1984 "EMF+\t World transform matrix: " << maWorldTransform);
1985 break;
1986 }
1988 {
1989 // Angle of rotation in degrees
1990 float eAngle;
1991 rMS.ReadFloat(eAngle);
1992
1993 SAL_INFO("drawinglayer.emf", "EMF+\t RotateWorldTransform Angle: " << eAngle <<
1994 ", post multiply: " << bool(flags & 0x2000));
1995 // Skipping flags & 0x2000
1996 // For rotation transformation there is no difference between post and pre multiply
1999
2000 SAL_INFO("drawinglayer.emf",
2001 "EMF+\t " << maWorldTransform);
2002 break;
2003 }
2005 {
2006 SAL_INFO("drawinglayer.emf", "EMF+ ResetClip");
2007 // We don't need to read anything more, as Size needs to be set 0x0000000C
2008 // and DataSize must be set to 0.
2009
2010 // Resets the current clipping region for the world space to infinity.
2012 break;
2013 }
2017 {
2018 int combineMode = (flags >> 8) & 0xf;
2019 ::basegfx::B2DPolyPolygon polyPolygon;
2021 {
2022 SAL_INFO("drawinglayer.emf", "EMF+\t SetClipRect");
2023
2024 float dx, dy, dw, dh;
2025 ReadRectangle(rMS, dx, dy, dw, dh);
2026 SAL_INFO("drawinglayer.emf",
2027 "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
2028 ::basegfx::B2DPoint mappedPoint1(Map(dx, dy));
2029 ::basegfx::B2DPoint mappedPoint2(Map(dx + dw, dy + dh));
2030
2031 polyPolygon
2032 = ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(
2033 ::basegfx::B2DRectangle(mappedPoint1.getX(), mappedPoint1.getY(),
2034 mappedPoint2.getX(), mappedPoint2.getY())));
2035 }
2037 {
2038 SAL_INFO("drawinglayer.emf", "EMF+\tSetClipPath " << (flags & 0xff));
2039
2040 EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get());
2041 if (!path)
2042 {
2043 SAL_WARN("drawinglayer.emf",
2044 "EMF+\t TODO Unable to find path in slot: " << (flags & 0xff));
2045 break;
2046 }
2047 polyPolygon = path->GetPolygon(*this);
2048 }
2050 {
2051 SAL_INFO("drawinglayer.emf", "EMF+\t Region in slot: " << (flags & 0xff));
2052 EMFPRegion* region
2053 = dynamic_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get());
2054 if (!region)
2055 {
2056 SAL_WARN(
2057 "drawinglayer.emf",
2058 "EMF+\t TODO Unable to find region in slot: " << (flags & 0xff));
2059 break;
2060 }
2061 polyPolygon = region->regionPolyPolygon;
2062 }
2063 SAL_INFO("drawinglayer.emf", "EMF+\t Combine mode: " << combineMode);
2064 ::basegfx::B2DPolyPolygon aClippedPolyPolygon;
2066 {
2067 aClippedPolyPolygon
2069 combineMode, polyPolygon);
2070 }
2071 else
2072 {
2073 //Combine with infinity
2074 switch (combineMode)
2075 {
2078 {
2079 aClippedPolyPolygon = polyPolygon;
2080 break;
2081 }
2083 {
2084 // Disable clipping as the clipping is infinity
2085 aClippedPolyPolygon = ::basegfx::B2DPolyPolygon();
2086 break;
2087 }
2090 {
2091 //TODO It is not correct and it should be fixed
2092 aClippedPolyPolygon = polyPolygon;
2093 break;
2094 }
2096 {
2097 //TODO It is not correct and it should be fixed
2098 aClippedPolyPolygon = ::basegfx::B2DPolyPolygon();
2099 break;
2100 }
2101 }
2102 }
2104 break;
2105 }
2107 {
2108 float dx, dy;
2109 rMS.ReadFloat(dx).ReadFloat(dy);
2110 SAL_INFO("drawinglayer.emf", "EMF+\tOffset x:" << dx << ", y:" << dy);
2111
2112 basegfx::B2DPolyPolygon aPolyPolygon(
2114
2115 SAL_INFO("drawinglayer.emf",
2116 "EMF+\t PolyPolygon before translate: " << aPolyPolygon);
2117
2118 basegfx::B2DPoint aOffset = Map(dx, dy);
2119 basegfx::B2DHomMatrix transformMatrix;
2120 transformMatrix.set(0, 2, aOffset.getX());
2121 transformMatrix.set(1, 2, aOffset.getY());
2122 aPolyPolygon.transform(transformMatrix);
2123
2124 SAL_INFO("drawinglayer.emf",
2125 "EMF+\t PolyPolygon after translate: " << aPolyPolygon <<
2126 ", mapped offset x" << aOffset.getX() << ", mapped offset y" << aOffset.getY());
2128 break;
2129 }
2131 {
2132 sal_uInt32 brushIndexOrColor;
2133 sal_uInt32 optionFlags;
2134 sal_uInt32 hasMatrix;
2135 sal_uInt32 glyphsCount;
2136 rMS.ReadUInt32(brushIndexOrColor).ReadUInt32(optionFlags).ReadUInt32(hasMatrix).ReadUInt32(glyphsCount);
2137 SAL_INFO("drawinglayer.emf", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
2138 SAL_INFO("drawinglayer.emf", "EMF+\t Option flags: 0x" << std::hex << optionFlags << std::dec);
2139 SAL_INFO("drawinglayer.emf", "EMF+\t Has matrix: " << hasMatrix);
2140 SAL_INFO("drawinglayer.emf", "EMF+\t Glyphs: " << glyphsCount);
2141
2142 if ((optionFlags & 1) && glyphsCount > 0)
2143 {
2144 std::unique_ptr<float[]> charsPosX(new float[glyphsCount]);
2145 std::unique_ptr<float[]> charsPosY(new float[glyphsCount]);
2146 OUString text = read_uInt16s_ToOUString(rMS, glyphsCount);
2147 SAL_INFO("drawinglayer.emf", "EMF+\t DrawDriverString string: " << text);
2148
2149 for (sal_uInt32 i = 0; i<glyphsCount; i++)
2150 {
2151 rMS.ReadFloat(charsPosX[i]).ReadFloat(charsPosY[i]);
2152 SAL_INFO("drawinglayer.emf", "EMF+\t\t glyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
2153 }
2154
2155 basegfx::B2DHomMatrix transform;
2156
2157 if (hasMatrix)
2158 {
2159 readXForm(rMS, transform);
2160 SAL_INFO("drawinglayer.emf", "EMF+\tmatrix: " << transform);
2161 }
2162
2163 // get the font from the flags
2164 EMFPFont *font = dynamic_cast<EMFPFont*>(maEMFPObjects[flags & 0xff].get());
2165 if (!font)
2166 {
2167 break;
2168 }
2169 // done reading
2170
2172 font->family, // font family
2173 "", // (no) font style
2174 font->Bold() ? 8u : 1u, // weight: 8 = bold
2175 font->family == "SYMBOL", // symbol
2176 optionFlags & 0x2, // vertical
2177 font->Italic(), // italic
2178 false, // monospaced
2179 false, // outline = false, no such thing in MS-EMFPLUS
2180 false, // right-to-left
2181 false); // BiDiStrong
2182
2183 const Color color = EMFPGetBrushColorOrARGBColor(flags, brushIndexOrColor);
2184
2185 // generate TextSimplePortionPrimitive2Ds or TextDecoratedPortionPrimitive2D
2186 // for all portions of text with the same charsPosY values
2187 sal_uInt32 pos = 0;
2188 while (pos < glyphsCount)
2189 {
2190 //determine the current length
2191 sal_uInt32 aLength = 1;
2192 while (pos + aLength < glyphsCount && std::abs( charsPosY[pos + aLength] - charsPosY[pos] ) < std::numeric_limits< float >::epsilon())
2193 aLength++;
2194
2195 // generate the DX-Array
2196 std::vector<double> aDXArray;
2197 for (size_t i = 0; i < aLength - 1; i++)
2198 {
2199 aDXArray.push_back(charsPosX[pos + i + 1] - charsPosX[pos]);
2200 }
2201 // last entry
2202 aDXArray.push_back(0);
2203
2205 ::basegfx::B2DVector(font->emSize, font->emSize),
2206 ::basegfx::B2DPoint(charsPosX[pos], charsPosY[pos]));
2207 if (hasMatrix)
2208 transformMatrix *= transform;
2209 if (color.GetAlpha() > 0)
2210 {
2212 if (font->Underline() || font->Strikeout())
2213 {
2215 transformMatrix,
2216 text,
2217 pos, // take character at current pos
2218 aLength, // use determined length
2219 std::move(aDXArray), // generated DXArray
2220 {},
2221 fontAttribute,
2223 color.getBColor(),
2225 color.getBColor(),
2226 color.getBColor(),
2229 false,
2231 }
2232 else
2233 {
2235 transformMatrix,
2236 text,
2237 pos, // take character at current pos
2238 aLength, // use determined length
2239 std::move(aDXArray), // generated DXArray
2240 {},
2241 fontAttribute,
2243 color.getBColor());
2244 }
2245 drawinglayer::primitive2d::Primitive2DReference aPrimitiveText(pBaseText);
2246 if (color.IsTransparent())
2247 {
2250 (255 - color.GetAlpha()) / 255.0);
2251 }
2256 }
2257
2258 // update pos
2259 pos += aLength;
2260 }
2261 }
2262 else
2263 {
2264 SAL_WARN("drawinglayer.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
2265 }
2266 break;
2267 }
2268 default:
2269 {
2270 SAL_WARN("drawinglayer.emf", "EMF+ TODO unhandled record type: 0x" << std::hex << type << std::dec);
2271 }
2272 }
2273 }
2274
2275 rMS.Seek(next);
2276
2277 if (size <= length)
2278 {
2279 length -= size;
2280 }
2281 else
2282 {
2283 SAL_WARN("drawinglayer.emf", "ImplRenderer::processEMFPlus: "
2284 "size " << size << " > length " << length);
2285 length = 0;
2286 }
2287 }
2288 }
2289}
2290
2291/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr sal_Int8 header[]
const LanguageTag & GetLanguageTag() const
static const AllSettings & GetSettings()
bool Crop(const tools::Rectangle &rRectPixel)
const Size & GetSizePixel() const
basegfx::BColor getBColor() const
void Merge(const Color &rMergeColor, sal_uInt8 cTransparency)
sal_uInt8 GetAlpha() const
bool IsTransparent() const
void Clip(const tools::Rectangle &)
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const void * GetData()
sal_uInt64 GetSize()
sal_uInt64 Tell() const
SvStream & ReadInt16(sal_Int16 &rInt16)
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & ReadFloat(float &rFloat)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
sal_uInt64 Seek(sal_uInt64 nPos)
SvStream & ReadInt32(sal_Int32 &rInt32)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
SvStream & ReadUChar(unsigned char &rChar)
double c() const
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
double a() const
void rotate(double fRadiant)
double d() const
double b() const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
void transform(const basegfx::B2DHomMatrix &rMatrix)
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
void setClosed(bool bNew)
void appendBezierSegment(const basegfx::B2DPoint &rNextControlPoint, const basegfx::B2DPoint &rPrevControlPoint, const basegfx::B2DPoint &rPoint)
double getBlue() const
void setBlue(double fNew)
double getRed() const
void setGreen(double fNew)
double getGreen() const
void setRed(double fNew)
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getHeight() const
TYPE getX() const
TYPE getY() const
void setFontAttribute(const attribute::FontAttribute &rFontAttribute, double fFontScaleX, double fFontScaleY, const css::lang::Locale &rLocale)
double getTextWidth(const OUString &rText, sal_uInt32 nIndex, sal_uInt32 nLength) const
::basegfx::B2DPolyPolygon & GetClosedCardinalSpline(EmfPlusHelperData const &rR, float fTension)
Definition: emfppath.cxx:288
::basegfx::B2DPolyPolygon & GetPolygon(EmfPlusHelperData const &rR, bool bMapIt=true, bool bAddLineToCloseShape=false)
Definition: emfppath.cxx:132
::basegfx::B2DPolyPolygon & GetCardinalSpline(EmfPlusHelperData const &rR, float fTension, sal_uInt32 aOffset, sal_uInt32 aNumSegments)
Definition: emfppath.cxx:256
void Read(SvStream &s, sal_uInt32 pathFlags)
Definition: emfppath.cxx:84
helper class for graphic context
void setFont(const vcl::Font &rFont)
const basegfx::B2DHomMatrix & getTransformation() const
read/write accesses
const basegfx::B2DPolyPolygon & getClipPolyPolygon() const
void setLineColorActive(bool bNew)
void setTransformation(const basegfx::B2DHomMatrix &rNew)
void setFillColorActive(bool bNew)
void setFillColor(const basegfx::BColor &rNew)
void setLineColor(const basegfx::BColor &rNew)
void setTextColor(const basegfx::BColor &rNew)
void setTextColorActive(bool bNew)
void append(const rtl::Reference< drawinglayer::primitive2d::BasePrimitive2D > &pCandidate)
Helper class which builds a stack on the TargetHolder class.
ColorAlpha
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
float y
float x
#define EmfPlusRecordTypeSetPageTransform
#define EmfPlusRecordTypeSetTextContrast
#define EmfPlusRecordTypeDrawPie
#define EmfPlusRecordTypeDrawArc
#define EmfPlusRecordTypeDrawDriverString
#define EmfPlusRecordTypeDrawImage
#define EmfPlusRecordTypeDrawLines
#define EmfPlusRecordTypeFillRects
#define EmfPlusRecordTypeSetRenderingOrigin
#define EmfPlusObjectTypePath
#define EmfPlusRecordTypeSave
#define EmfPlusRecordTypeGetDC
#define EmfPlusObjectTypeFont
#define EmfPlusRecordTypeBeginContainerNoParams
#define EmfPlusRecordTypeEndContainer
#define EmfPlusRecordTypeSetClipRegion
#define EmfPlusRecordTypeScaleWorldTransform
#define EmfPlusRecordTypeSetWorldTransform
#define EmfPlusRecordTypeDrawCurve
#define EmfPlusRecordTypeDrawImagePoints
#define EmfPlusRecordTypeSetClipRect
#define EmfPlusRecordTypeDrawClosedCurve
#define EmfPlusObjectTypeCustomLineCap
#define EmfPlusRecordTypeSetCompositingQuality
#define EmfPlusObjectTypeBrush
#define EmfPlusRecordTypeFillEllipse
#define EmfPlusRecordTypeDrawRects
#define EmfPlusRecordTypeFillPath
#define EmfPlusRecordTypeDrawString
#define EmfPlusRecordTypeRestore
#define EmfPlusRecordTypeDrawBeziers
#define EmfPlusRecordTypeEndOfFile
#define EmfPlusRecordTypeObject
#define EmfPlusRecordTypeSetClipPath
#define EmfPlusRecordTypeFillRegion
#define EmfPlusRecordTypeBeginContainer
#define EmfPlusRecordTypeSetAntiAliasMode
#define EmfPlusRecordTypeDrawPath
#define EmfPlusObjectTypeImageAttributes
#define EmfPlusRecordTypeTranslateWorldTransform
#define EmfPlusRecordTypeHeader
#define EmfPlusRecordTypeResetWorldTransform
#define EmfPlusRecordTypeRotateWorldTransform
#define EmfPlusObjectTypeStringFormat
#define EmfPlusObjectTypePen
#define EmfPlusObjectTypeImage
#define EmfPlusRecordTypeSetPixelOffsetMode
#define EmfPlusRecordTypeResetClip
#define EmfPlusRecordTypeFillClosedCurve
#define EmfPlusRecordTypeDrawEllipse
#define EmfPlusRecordTypeFillPie
#define EmfPlusRecordTypeSetInterpolationMode
#define EmfPlusRecordTypeSetTextRenderingHint
#define EmfPlusRecordTypeMultiplyWorldTransform
#define EmfPlusObjectTypeRegion
#define EmfPlusRecordTypeComment
#define EmfPlusRecordTypeFillPolygon
#define EmfPlusRecordTypeOffsetClip
FilterGroup & rTarget
bool isColor
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
def text(shape, orig_st)
B2DHomMatrix createScaleTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fTranslateX, double fTranslateY)
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke, size_t *pPointLimit)
constexpr double rad2deg(double v)
constexpr double deg2rad(double v)
size
::std::vector< SvgGradientEntry > SvgGradientEntryVector
static bool IsBrush(sal_uInt16 flags)
static OUString emfObjectToName(sal_uInt16 type)
static OUString SmoothingModeToString(sal_uInt16 nSmoothMode)
@ TextRenderingHintAntialiasGridFit
@ TextRenderingHintSingleBitPerPixel
@ TextRenderingHintClearTypeGridFit
@ TextRenderingHintSingleBitPerPixelGridFit
OUString UnitTypeToString(sal_uInt16 nType)
const sal_uInt32 EmfPlusPenDataCustomStartCap
Definition: emfppen.hxx:55
const char * emfTypeToName(sal_uInt16 type)
const sal_uInt32 EmfPlusPenDataEndCap
Definition: emfppen.hxx:46
static OUString TextRenderingHintToString(sal_uInt16 nHint)
@ LineCapTypeRound
Definition: emfppen.hxx:62
@ LineCapTypeSquareAnchor
Definition: emfppen.hxx:65
@ LineCapTypeSquare
Definition: emfppen.hxx:61
@ LineCapTypeTriangle
Definition: emfppen.hxx:63
@ LineCapTypeDiamondAnchor
Definition: emfppen.hxx:67
@ LineCapTypeArrowAnchor
Definition: emfppen.hxx:68
@ LineCapTypeRoundAnchor
Definition: emfppen.hxx:66
std::map< int, wmfemfhelper::PropertyHolder > GraphicStateMap
constexpr double alpha[nDetails]
Definition: emfppath.cxx:41
@ ImageDataTypeMetafile
Definition: emfpimage.hxx:32
const sal_uInt32 EmfPlusPenDataStartCap
Definition: emfppen.hxx:45
@ InterpolationModeHighQualityBicubic
@ InterpolationModeNearestNeighbor
@ InterpolationModeHighQualityBilinear
@ BrushTypeLinearGradient
Definition: emfpbrush.hxx:90
@ BrushTypePathGradient
Definition: emfpbrush.hxx:89
@ BrushTypeTextureFill
Definition: emfpbrush.hxx:88
const sal_uInt32 EmfPlusPenDataCustomEndCap
Definition: emfppen.hxx:56
static OUString BrushIDToString(sal_uInt16 flags, sal_uInt32 brushid)
static OUString PixelOffsetModeToString(sal_uInt16 nPixelOffset)
static OUString InterpolationModeToString(sal_uInt16 nMode)
int i
index
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
void HandleNewClipRegion(const basegfx::B2DPolyPolygon &rClipPolyPolygon, TargetHolders &rTargetHolders, PropertyHolders &rPropertyHolders)
helper to take needed action on ClipRegion change.
QPRO_FUNC_TYPE nType
std::map< OUString, rtl::Reference< Entity > > map
TOOLS_DLLPUBLIC OUString read_uInt16s_ToOUString(SvStream &rStrm, std::size_t nUnits)
std::unique_ptr< float[]> blendPositions
Definition: emfpbrush.hxx:108
const ::Color & GetColor() const
Definition: emfpbrush.hxx:122
void Read(SvStream &s, EmfPlusHelperData const &rR)
Definition: emfpbrush.cxx:64
sal_uInt32 GetType() const
Definition: emfpbrush.hxx:121
sal_uInt32 additionalFlags
Definition: emfpbrush.hxx:99
std::unique_ptr< float[]> colorblendPositions
Definition: emfpbrush.hxx:111
basegfx::B2DHomMatrix brush_transformation
Definition: emfpbrush.hxx:105
std::unique_ptr<::Color[]> colorblendColors
Definition: emfpbrush.hxx:112
EmfPlusHatchStyle hatchStyle
Definition: emfpbrush.hxx:116
bool Underline() const
Definition: emfpfont.hxx:43
bool Italic() const
Definition: emfpfont.hxx:42
void Read(SvMemoryStream &s)
Definition: emfpfont.cxx:45
bool Strikeout() const
Definition: emfpfont.hxx:44
void Read(SvMemoryStream &s, sal_uInt32 dataSize, bool bUseWholeStream)
Definition: emfpimage.cxx:25
basegfx::B2DLineJoin maLineJoin
Definition: emfppen.hxx:107
std::unique_ptr< EMFPCustomLineCap > customEndCap
Definition: emfppen.hxx:118
std::unique_ptr< EMFPCustomLineCap > customStartCap
Definition: emfppen.hxx:116
void Read(SvStream &s, EmfPlusHelperData const &rR)
Definition: emfppen.cxx:183
sal_uInt32 penDataFlags
Definition: emfppen.hxx:102
drawinglayer::attribute::StrokeAttribute GetStrokeAttribute(const double aTransformation) const
Definition: emfppen.cxx:145
::basegfx::B2DPolyPolygon regionPolyPolygon
Definition: emfpregion.hxx:41
void ReadRegion(SvStream &s, EmfPlusHelperData &rR)
Definition: emfpregion.cxx:123
void GraphicStatePush(GraphicStateMap &map, sal_Int32 index)
basegfx::B2DHomMatrix maBaseTransform
static bool readXForm(SvStream &rIn, basegfx::B2DHomMatrix &rTarget)
void GraphicStatePop(GraphicStateMap &map, sal_Int32 index)
::basegfx::B2DPoint Map(double ix, double iy) const
void EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon &polygon, sal_uInt32 penIndex)
EmfPlusHelperData(SvMemoryStream &rMS, wmfemfhelper::TargetHolders &rTargetHolders, wmfemfhelper::PropertyHolders &rPropertyHolders)
basegfx::B2DHomMatrix maWorldTransform
void EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon &polygon, const bool isColor, const sal_uInt32 brushIndexOrColor)
void processEmfPlusData(SvMemoryStream &rMS, const drawinglayer::geometry::ViewInformation2D &rViewInformation)
wmfemfhelper::PropertyHolders & mrPropertyHolders
void EMFPPlusFillPolygonSolidColor(const ::basegfx::B2DPolyPolygon &polygon, Color const &color)
basegfx::B2DHomMatrix maMapTransform
static void ReadRectangle(SvStream &s, float &x, float &y, float &width, float &height, bool bCompressed=false)
std::unique_ptr< EMFPObject > maEMFPObjects[256]
static void ReadPoint(SvStream &s, float &x, float &y, sal_uInt32 flags)
wmfemfhelper::TargetHolders & mrTargetHolders
data holders
::basegfx::B2DPolyPolygon combineClip(::basegfx::B2DPolyPolygon const &leftPolygon, int combineMode, ::basegfx::B2DPolyPolygon const &rightPolygon)
void processObjectRecord(SvMemoryStream &rObjectStream, sal_uInt16 flags, sal_uInt32 dataSize, bool bUseWholeStream=false)
Color EMFPGetBrushColorOrARGBColor(const sal_uInt16 flags, const sal_uInt32 brushIndexOrColor) const
static float getUnitToPixelMultiplier(const UnitType aUnitType, const sal_uInt32 aDPI)
wmfemfhelper::PropertyHolder aGetDCState
drawinglayer::attribute::LineStartEndAttribute CreateLineEnd(const sal_Int32 aCap, const float aPenWidth) const
unsigned char sal_uInt8
ResultType type
size_t pos