Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkPDFUtils.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
12#include "include/core/SkData.h"
17#include "src/core/SkGeometry.h"
18#include "src/core/SkPathPriv.h"
21#include "src/pdf/SkPDFTypes.h"
22
23#if defined(SK_BUILD_FOR_WIN)
25#endif
26
27#include <cmath>
28#include <ctime>
29
31 // PDF32000.book section 11.3.5 "Blend Mode"
32 switch (mode) {
33 case SkBlendMode::kSrcOver: return "Normal";
34 case SkBlendMode::kXor: return "Normal"; // (unsupported mode)
35 case SkBlendMode::kPlus: return "Normal"; // (unsupported mode)
36 case SkBlendMode::kScreen: return "Screen";
37 case SkBlendMode::kOverlay: return "Overlay";
38 case SkBlendMode::kDarken: return "Darken";
39 case SkBlendMode::kLighten: return "Lighten";
40 case SkBlendMode::kColorDodge: return "ColorDodge";
41 case SkBlendMode::kColorBurn: return "ColorBurn";
42 case SkBlendMode::kHardLight: return "HardLight";
43 case SkBlendMode::kSoftLight: return "SoftLight";
44 case SkBlendMode::kDifference: return "Difference";
45 case SkBlendMode::kExclusion: return "Exclusion";
46 case SkBlendMode::kMultiply: return "Multiply";
47 case SkBlendMode::kHue: return "Hue";
48 case SkBlendMode::kSaturation: return "Saturation";
49 case SkBlendMode::kColor: return "Color";
50 case SkBlendMode::kLuminosity: return "Luminosity";
51 // Other blendmodes are handled in SkPDFDevice::setUpContentEntry.
52 default: return nullptr;
53 }
54}
55
56std::unique_ptr<SkPDFArray> SkPDFUtils::RectToArray(const SkRect& r) {
57 return SkPDFMakeArray(r.left(), r.top(), r.right(), r.bottom());
58}
59
60std::unique_ptr<SkPDFArray> SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
61 SkScalar a[6];
62 if (!matrix.asAffine(a)) {
64 }
65 return SkPDFMakeArray(a[0], a[1], a[2], a[3], a[4], a[5]);
66}
67
74
81
82static void append_cubic(SkScalar ctl1X, SkScalar ctl1Y,
83 SkScalar ctl2X, SkScalar ctl2Y,
84 SkScalar dstX, SkScalar dstY, SkWStream* content) {
85 SkString cmd("y\n");
87 content->writeText(" ");
89 content->writeText(" ");
90 if (ctl2X != dstX || ctl2Y != dstY) {
91 cmd.set("c\n");
93 content->writeText(" ");
95 content->writeText(" ");
96 }
98 content->writeText(" ");
100 content->writeText(" ");
101 content->writeText(cmd.c_str());
102}
103
104static void append_quad(const SkPoint quad[], SkWStream* content) {
105 SkPoint cubic[4];
106 SkConvertQuadToCubic(quad, cubic);
107 append_cubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY,
108 cubic[3].fX, cubic[3].fY, content);
109}
110
112 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
113 SkScalar bottom = std::min(rect.fBottom, rect.fTop);
114
116 content->writeText(" ");
118 content->writeText(" ");
119 SkPDFUtils::AppendScalar(rect.width(), content);
120 content->writeText(" ");
121 SkPDFUtils::AppendScalar(rect.height(), content);
122 content->writeText(" re\n");
123}
124
125void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle,
126 bool doConsumeDegerates, SkWStream* content,
127 SkScalar tolerance) {
128 if (path.isEmpty() && SkPaint::kFill_Style == paintStyle) {
130 return;
131 }
132 // Filling a path with no area results in a drawing in PDF renderers but
133 // Chrome expects to be able to draw some such entities with no visible
134 // result, so we detect those cases and discard the drawing for them.
135 // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y).
136
137 SkRect rect;
138 bool isClosed; // Both closure and direction need to be checked.
139 SkPathDirection direction;
140 if (path.isRect(&rect, &isClosed, &direction) &&
141 isClosed &&
142 (SkPathDirection::kCW == direction ||
143 SkPathFillType::kEvenOdd == path.getFillType()))
144 {
146 return;
147 }
148
149 enum SkipFillState {
150 kEmpty_SkipFillState,
151 kSingleLine_SkipFillState,
152 kNonSingleLine_SkipFillState,
153 };
154 SkipFillState fillState = kEmpty_SkipFillState;
155 //if (paintStyle != SkPaint::kFill_Style) {
156 // fillState = kNonSingleLine_SkipFillState;
157 //}
158 SkPoint lastMovePt = SkPoint::Make(0,0);
159 SkDynamicMemoryWStream currentSegment;
160 SkPoint args[4];
161 SkPath::Iter iter(path, false);
162 for (SkPath::Verb verb = iter.next(args);
163 verb != SkPath::kDone_Verb;
164 verb = iter.next(args)) {
165 // args gets all the points, even the implicit first point.
166 switch (verb) {
168 MoveTo(args[0].fX, args[0].fY, &currentSegment);
169 lastMovePt = args[0];
170 fillState = kEmpty_SkipFillState;
171 break;
173 if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 2)) {
174 AppendLine(args[1].fX, args[1].fY, &currentSegment);
175 if ((fillState == kEmpty_SkipFillState) && (args[0] != lastMovePt)) {
176 fillState = kSingleLine_SkipFillState;
177 break;
178 }
179 fillState = kNonSingleLine_SkipFillState;
180 }
181 break;
183 if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 3)) {
184 append_quad(args, &currentSegment);
185 fillState = kNonSingleLine_SkipFillState;
186 }
187 break;
189 if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 3)) {
190 SkAutoConicToQuads converter;
191 const SkPoint* quads = converter.computeQuads(args, iter.conicWeight(), tolerance);
192 for (int i = 0; i < converter.countQuads(); ++i) {
193 append_quad(&quads[i * 2], &currentSegment);
194 }
195 fillState = kNonSingleLine_SkipFillState;
196 }
197 break;
199 if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 4)) {
200 append_cubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
201 args[3].fX, args[3].fY, &currentSegment);
202 fillState = kNonSingleLine_SkipFillState;
203 }
204 break;
206 ClosePath(&currentSegment);
207 currentSegment.writeToStream(content);
208 currentSegment.reset();
209 break;
210 default:
211 SkASSERT(false);
212 break;
213 }
214 }
215 if (currentSegment.bytesWritten() > 0) {
216 currentSegment.writeToStream(content);
217 }
218}
219
221 content->writeText("h\n");
222}
223
225 if (style == SkPaint::kFill_Style) {
226 content->writeText("f");
227 } else if (style == SkPaint::kStrokeAndFill_Style) {
228 content->writeText("B");
229 } else if (style == SkPaint::kStroke_Style) {
230 content->writeText("S");
231 }
232
233 if (style != SkPaint::kStroke_Style) {
236 if (fill == SkPathFillType::kEvenOdd) {
237 content->writeText("*");
238 }
239 }
240 content->writeText("\n");
241}
242
246
249 content->writeText(" gs\n");
250}
251
253 // Select Pattern color space (CS, cs) and set pattern object as current
254 // color (SCN, scn)
255 content->writeText("/Pattern CS/Pattern cs");
257 content->writeText(" SCN");
259 content->writeText(" scn\n");
260}
261
262// return "x/pow(10, places)", given 0<x<pow(10, places)
263// result points to places+2 chars.
264static size_t print_permil_as_decimal(int x, char* result, unsigned places) {
265 result[0] = '.';
266 for (int i = places; i > 0; --i) {
267 result[i] = '0' + x % 10;
268 x /= 10;
269 }
270 int j;
271 for (j = places; j > 1; --j) {
272 if (result[j] != '0') {
273 break;
274 }
275 }
276 result[j + 1] = '\0';
277 return j + 1;
278}
279
280
281static constexpr int int_pow(int base, unsigned exp, int acc = 1) {
282 return exp < 1 ? acc
283 : int_pow(base * base,
284 exp / 2,
285 (exp % 2) ? acc * base : acc);
286}
287
288
289size_t SkPDFUtils::ColorToDecimalF(float value, char result[kFloatColorDecimalCount + 2]) {
290 static constexpr int kFactor = int_pow(10, kFloatColorDecimalCount);
291 int x = sk_float_round2int(value * kFactor);
292 if (x >= kFactor || x <= 0) { // clamp to 0-1
293 result[0] = x > 0 ? '1' : '0';
294 result[1] = '\0';
295 return 1;
296 }
297 return print_permil_as_decimal(x, result, kFloatColorDecimalCount);
298}
299
300size_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) {
301 if (value == 255 || value == 0) {
302 result[0] = value ? '1' : '0';
303 result[1] = '\0';
304 return 1;
305 }
306 // int x = 0.5 + (1000.0 / 255.0) * value;
307 int x = SkFixedRoundToInt((SK_Fixed1 * 1000 / 255) * value);
308 return print_permil_as_decimal(x, result, 3);
309}
310
312 SkMatrix inverse;
313 if (!matrix.invert(&inverse)) {
314 return false;
315 }
316 inverse.mapRect(bbox);
317 return true;
318}
319
321 SkRect& bbox,
322 std::unique_ptr<SkPDFDict> resources,
323 const SkMatrix& matrix) {
324 const int kTiling_PatternType = 1;
325 const int kColoredTilingPattern_PaintType = 1;
326 const int kConstantSpacing_TilingType = 1;
327
328 pattern->insertName("Type", "Pattern");
329 pattern->insertInt("PatternType", kTiling_PatternType);
330 pattern->insertInt("PaintType", kColoredTilingPattern_PaintType);
331 pattern->insertInt("TilingType", kConstantSpacing_TilingType);
332 pattern->insertObject("BBox", SkPDFUtils::RectToArray(bbox));
333 pattern->insertScalar("XStep", bbox.width());
334 pattern->insertScalar("YStep", bbox.height());
335 pattern->insertObject("Resources", std::move(resources));
336 if (!matrix.isIdentity()) {
337 pattern->insertObject("Matrix", SkPDFUtils::MatrixToArray(matrix));
338 }
339}
340
341bool SkPDFUtils::ToBitmap(const SkImage* img, SkBitmap* dst) {
342 SkASSERT(img);
343 SkASSERT(dst);
345 // TODO: support GPU images
346 if(as_IB(img)->getROPixels(nullptr, &bitmap)) {
347 SkASSERT(bitmap.dimensions() == img->dimensions());
348 SkASSERT(!bitmap.drawsNothing());
349 *dst = std::move(bitmap);
350 return true;
351 }
352 return false;
353}
354
355#ifdef SK_PDF_BASE85_BINARY
356void SkPDFUtils::Base85Encode(std::unique_ptr<SkStreamAsset> stream, SkDynamicMemoryWStream* dst) {
357 SkASSERT(dst);
358 SkASSERT(stream);
359 dst->writeText("\n");
360 int column = 0;
361 while (true) {
362 uint8_t src[4] = {0, 0, 0, 0};
363 size_t count = stream->read(src, 4);
364 SkASSERT(count < 5);
365 if (0 == count) {
366 dst->writeText("~>\n");
367 return;
368 }
369 uint32_t v = ((uint32_t)src[0] << 24) | ((uint32_t)src[1] << 16) |
370 ((uint32_t)src[2] << 8) | src[3];
371 if (v == 0 && count == 4) {
372 dst->writeText("z");
373 column += 1;
374 } else {
375 char buffer[5];
376 for (int n = 4; n > 0; --n) {
377 buffer[n] = (v % 85) + '!';
378 v /= 85;
379 }
380 buffer[0] = v + '!';
381 dst->write(buffer, count + 1);
382 column += count + 1;
383 }
384 if (column > 74) {
385 dst->writeText("\n");
386 column = 0;
387 }
388 }
389}
390#endif // SK_PDF_BASE85_BINARY
391
393 SkScalar values[6];
394 if (!matrix.asAffine(values)) {
396 }
397 for (SkScalar v : values) {
399 content->writeText(" ");
400 }
401 content->writeText("cm\n");
402}
403
404
405#if defined(SK_BUILD_FOR_WIN)
406
408 if (dt) {
409 SYSTEMTIME st;
410 GetSystemTime(&st);
411 dt->fTimeZoneMinutes = 0;
412 dt->fYear = st.wYear;
413 dt->fMonth = SkToU8(st.wMonth);
414 dt->fDayOfWeek = SkToU8(st.wDayOfWeek);
415 dt->fDay = SkToU8(st.wDay);
416 dt->fHour = SkToU8(st.wHour);
417 dt->fMinute = SkToU8(st.wMinute);
418 dt->fSecond = SkToU8(st.wSecond);
419 }
420}
421
422#else // SK_BUILD_FOR_WIN
423
425 if (dt) {
426 time_t m_time;
427 time(&m_time);
428 struct tm tstruct;
429 gmtime_r(&m_time, &tstruct);
430 dt->fTimeZoneMinutes = 0;
431 dt->fYear = tstruct.tm_year + 1900;
432 dt->fMonth = SkToU8(tstruct.tm_mon + 1);
433 dt->fDayOfWeek = SkToU8(tstruct.tm_wday);
434 dt->fDay = SkToU8(tstruct.tm_mday);
435 dt->fHour = SkToU8(tstruct.tm_hour);
436 dt->fMinute = SkToU8(tstruct.tm_min);
437 dt->fSecond = SkToU8(tstruct.tm_sec);
438 }
439}
440#endif // SK_BUILD_FOR_WIN
int count
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
@ kExclusion
rc = s + d - two(s*d), ra = kSrcOver
@ kSaturation
saturation of source with hue and luminosity of destination
@ kColorBurn
darken destination to reflect source
@ kPlus
r = min(s + d, 1)
@ kLighten
rc = s + d - min(s*da, d*sa), ra = kSrcOver
@ kHue
hue of source with saturation and luminosity of destination
@ kMultiply
r = s*(1-da) + d*(1-sa) + s*d
@ kColorDodge
brighten destination to reflect source
@ kScreen
r = s + d - s*d
@ kSrcOver
r = s + (1-sa)*d
@ kXor
r = s*(1-da) + d*(1-sa)
@ kLuminosity
luminosity of source with hue and saturation of destination
@ kSoftLight
lighten or darken, depending on source
@ kDifference
rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver
@ kOverlay
multiply or screen, depending on destination
@ kColor
hue and saturation of source with luminosity of destination
@ kHardLight
multiply or screen, depending on source
@ kDarken
rc = s + d - max(s*da, d*sa), ra = kSrcOver
#define SK_Fixed1
Definition SkFixed.h:26
#define SkFixedRoundToInt(x)
Definition SkFixed.h:76
#define sk_float_round2int(x)
void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4])
static SkImage_Base * as_IB(SkImage *image)
void SkPDFWriteResourceName(SkWStream *dst, SkPDFResourceType type, int key)
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition SkPDFTypes.h:135
static size_t print_permil_as_decimal(int x, char *result, unsigned places)
static void append_quad(const SkPoint quad[], SkWStream *content)
static void append_cubic(SkScalar ctl1X, SkScalar ctl1Y, SkScalar ctl2X, SkScalar ctl2Y, SkScalar dstX, SkScalar dstY, SkWStream *content)
static constexpr int int_pow(int base, unsigned exp, int acc=1)
#define NOT_IMPLEMENTED(condition, assert)
Definition SkPDFUtils.h:39
SkPathDirection
Definition SkPathTypes.h:34
SkPathFillType
Definition SkPathTypes.h:11
constexpr uint8_t SkToU8(S x)
Definition SkTo.h:22
size_t bytesWritten() const override
Definition SkStream.cpp:526
bool writeToStream(SkWStream *dst) const
Definition SkStream.cpp:642
SkISize dimensions() const
Definition SkImage.h:297
static void SetAffineIdentity(SkScalar affine[6])
Definition SkMatrix.cpp:746
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
void insertName(const char key[], const char nameValue[])
void insertObject(const char key[], std::unique_ptr< SkPDFObject > &&)
void insertInt(const char key[], int32_t value)
void insertScalar(const char key[], SkScalar value)
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
@ kStrokeAndFill_Style
sets to stroke and fill geometry
Definition SkPaint.h:195
static bool AllPointsEq(const SkPoint pts[], int count)
Definition SkPathPriv.h:339
Verb next(SkPoint pts[4])
Definition SkPath.cpp:1837
SkScalar conicWeight() const
Definition SkPath.h:1527
@ kClose_Verb
Definition SkPath.h:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kConic_Verb
Definition SkPath.h:1461
@ kDone_Verb
Definition SkPath.h:1464
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
float SkScalar
Definition extension.cpp:12
struct MyStruct a[10]
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
union flutter::testing::@2838::KeyboardChange::@76 content
double y
double x
void GetDateTime(SkPDF::DateTime *)
void ApplyGraphicState(int objectIndex, SkWStream *content)
void PopulateTilingPatternDict(SkPDFDict *pattern, SkRect &bbox, std::unique_ptr< SkPDFDict > resources, const SkMatrix &matrix)
size_t ColorToDecimalF(float value, char result[kFloatColorDecimalCount+2])
size_t ColorToDecimal(uint8_t value, char result[5])
const char * BlendModeName(SkBlendMode)
std::unique_ptr< SkPDFArray > MatrixToArray(const SkMatrix &matrix)
void EmitPath(const SkPath &path, SkPaint::Style paintStyle, bool doConsumeDegerates, SkWStream *content, SkScalar tolerance=0.25f)
void AppendRectangle(const SkRect &rect, SkWStream *content)
void PaintPath(SkPaint::Style style, SkPathFillType fill, SkWStream *content)
void AppendScalar(SkScalar value, SkWStream *stream)
Definition SkPDFUtils.h:86
void MoveTo(SkScalar x, SkScalar y, SkWStream *content)
void AppendLine(SkScalar x, SkScalar y, SkWStream *content)
void AppendTransform(const SkMatrix &, SkWStream *)
void ApplyPattern(int objectIndex, SkWStream *content)
bool ToBitmap(const SkImage *img, SkBitmap *dst)
bool InverseTransformBBox(const SkMatrix &matrix, SkRect *bbox)
void ClosePath(SkWStream *content)
void StrokePath(SkWStream *content)
std::unique_ptr< SkPDFArray > RectToArray(const SkRect &rect)
dst
Definition cp.py:12
uint8_t fMinute
0..59
uint8_t fMonth
1..12
uint8_t fDay
1..31
uint16_t fYear
e.g. 2005
uint8_t fSecond
0..59
int16_t fTimeZoneMinutes
uint8_t fHour
0..23
uint8_t fDayOfWeek
0..6, 0==Sunday
static constexpr SkPoint Make(float x, float y)
constexpr float left() const
Definition SkRect.h:734
constexpr float top() const
Definition SkRect.h:741
constexpr float height() const
Definition SkRect.h:769
constexpr float right() const
Definition SkRect.h:748
constexpr float width() const
Definition SkRect.h:762
constexpr float bottom() const
Definition SkRect.h:755