blob: 4bc1bb412ab694143f7e37b14134397106da9395 [file] [log] [blame]
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +00006 */
7
Hal Canary4f29c202017-07-18 10:28:31 -04008#include "SkPDFUtils.h"
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
vandebo@chromium.org683001c2012-05-09 17:17:51 +000010#include "SkData.h"
halcanaryeb92cb32016-07-15 13:41:27 -070011#include "SkFixed.h"
reed@google.coma44ea512011-07-27 18:24:25 +000012#include "SkGeometry.h"
Hal Canary4f29c202017-07-18 10:28:31 -040013#include "SkImage_Base.h"
commit-bot@chromium.org47401352013-07-23 21:49:29 +000014#include "SkPDFResourceDict.h"
Hal Canary4f29c202017-07-18 10:28:31 -040015#include "SkPDFTypes.h"
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000016#include "SkStream.h"
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000017#include "SkString.h"
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000018
halcanary8e9f5e32016-02-24 15:46:46 -080019#include <cmath>
20
halcanary8103a342016-03-08 15:10:16 -080021sk_sp<SkPDFArray> SkPDFUtils::RectToArray(const SkRect& rect) {
22 auto result = sk_make_sp<SkPDFArray>();
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +000023 result->reserve(4);
24 result->appendScalar(rect.fLeft);
25 result->appendScalar(rect.fTop);
26 result->appendScalar(rect.fRight);
27 result->appendScalar(rect.fBottom);
28 return result;
29}
30
halcanary8103a342016-03-08 15:10:16 -080031sk_sp<SkPDFArray> SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000032 SkScalar values[6];
bungeman@google.com1ddd7c32011-07-13 19:41:55 +000033 if (!matrix.asAffine(values)) {
34 SkMatrix::SetAffineIdentity(values);
35 }
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000036
halcanary8103a342016-03-08 15:10:16 -080037 auto result = sk_make_sp<SkPDFArray>();
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000038 result->reserve(6);
39 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
reed@google.comc789cf12011-07-20 12:14:33 +000040 result->appendScalar(values[i]);
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000041 }
42 return result;
43}
44
45// static
vandebo@chromium.org75f97e42011-04-11 23:24:18 +000046void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
47 SkScalar values[6];
bungeman@google.com1ddd7c32011-07-13 19:41:55 +000048 if (!matrix.asAffine(values)) {
49 SkMatrix::SetAffineIdentity(values);
50 }
vandebo@chromium.org75f97e42011-04-11 23:24:18 +000051 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
halcanarybc4696b2015-05-06 10:56:04 -070052 SkPDFUtils::AppendScalar(values[i], content);
vandebo@chromium.org75f97e42011-04-11 23:24:18 +000053 content->writeText(" ");
54 }
55 content->writeText("cm\n");
56}
57
58// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000059void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
halcanarybc4696b2015-05-06 10:56:04 -070060 SkPDFUtils::AppendScalar(x, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000061 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -070062 SkPDFUtils::AppendScalar(y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000063 content->writeText(" m\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000064}
65
66// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000067void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) {
halcanarybc4696b2015-05-06 10:56:04 -070068 SkPDFUtils::AppendScalar(x, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000069 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -070070 SkPDFUtils::AppendScalar(y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000071 content->writeText(" l\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000072}
73
74// static
75void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
76 SkScalar ctl2X, SkScalar ctl2Y,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000077 SkScalar dstX, SkScalar dstY, SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000078 SkString cmd("y\n");
halcanarybc4696b2015-05-06 10:56:04 -070079 SkPDFUtils::AppendScalar(ctl1X, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000080 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -070081 SkPDFUtils::AppendScalar(ctl1Y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000082 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000083 if (ctl2X != dstX || ctl2Y != dstY) {
84 cmd.set("c\n");
halcanarybc4696b2015-05-06 10:56:04 -070085 SkPDFUtils::AppendScalar(ctl2X, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000086 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -070087 SkPDFUtils::AppendScalar(ctl2Y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000088 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000089 }
halcanarybc4696b2015-05-06 10:56:04 -070090 SkPDFUtils::AppendScalar(dstX, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000091 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -070092 SkPDFUtils::AppendScalar(dstY, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000093 content->writeText(" ");
94 content->writeText(cmd.c_str());
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000095}
96
reed40c85e42015-01-05 10:01:25 -080097static void append_quad(const SkPoint quad[], SkWStream* content) {
98 SkPoint cubic[4];
99 SkConvertQuadToCubic(quad, cubic);
100 SkPDFUtils::AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY,
101 cubic[3].fX, cubic[3].fY, content);
102}
103
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000104// static
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000105void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
106 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
107 SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop);
108
halcanarybc4696b2015-05-06 10:56:04 -0700109 SkPDFUtils::AppendScalar(rect.fLeft, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000110 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -0700111 SkPDFUtils::AppendScalar(bottom, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000112 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -0700113 SkPDFUtils::AppendScalar(rect.width(), content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000114 content->writeText(" ");
halcanarybc4696b2015-05-06 10:56:04 -0700115 SkPDFUtils::AppendScalar(rect.height(), content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000116 content->writeText(" re\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000117}
118
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000119// static
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000120void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle,
Hal Canary385468f2017-02-13 11:03:23 -0500121 bool doConsumeDegerates, SkWStream* content,
122 SkScalar tolerance) {
Hal Canary4e83ff12018-03-09 12:16:42 -0500123 if (path.isEmpty() && SkPaint::kFill_Style == paintStyle) {
124 SkPDFUtils::AppendRectangle({0, 0, 0, 0}, content);
125 return;
126 }
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000127 // Filling a path with no area results in a drawing in PDF renderers but
128 // Chrome expects to be able to draw some such entities with no visible
129 // result, so we detect those cases and discard the drawing for them.
130 // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y).
Hal Canary970225b2016-11-10 11:46:21 -0500131
132 SkRect rect;
133 bool isClosed; // Both closure and direction need to be checked.
134 SkPath::Direction direction;
135 if (path.isRect(&rect, &isClosed, &direction) &&
Hal Canaryfc3afa92017-07-19 14:19:14 -0400136 isClosed &&
137 (SkPath::kCW_Direction == direction ||
138 SkPath::kEvenOdd_FillType == path.getFillType()))
Hal Canary970225b2016-11-10 11:46:21 -0500139 {
140 SkPDFUtils::AppendRectangle(rect, content);
141 return;
Hal Canary385468f2017-02-13 11:03:23 -0500142 }
Hal Canary970225b2016-11-10 11:46:21 -0500143
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000144 enum SkipFillState {
halcanary8b2bc252015-10-06 09:41:47 -0700145 kEmpty_SkipFillState,
146 kSingleLine_SkipFillState,
147 kNonSingleLine_SkipFillState,
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000148 };
149 SkipFillState fillState = kEmpty_SkipFillState;
halcanary8b2bc252015-10-06 09:41:47 -0700150 //if (paintStyle != SkPaint::kFill_Style) {
151 // fillState = kNonSingleLine_SkipFillState;
152 //}
sugoi@google.come2e81132013-03-05 18:35:55 +0000153 SkPoint lastMovePt = SkPoint::Make(0,0);
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000154 SkDynamicMemoryWStream currentSegment;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000155 SkPoint args[4];
156 SkPath::Iter iter(path, false);
halcanary8b2bc252015-10-06 09:41:47 -0700157 for (SkPath::Verb verb = iter.next(args, doConsumeDegerates);
158 verb != SkPath::kDone_Verb;
159 verb = iter.next(args, doConsumeDegerates)) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000160 // args gets all the points, even the implicit first point.
161 switch (verb) {
162 case SkPath::kMove_Verb:
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000163 MoveTo(args[0].fX, args[0].fY, &currentSegment);
164 lastMovePt = args[0];
165 fillState = kEmpty_SkipFillState;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000166 break;
167 case SkPath::kLine_Verb:
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000168 AppendLine(args[1].fX, args[1].fY, &currentSegment);
halcanary8b2bc252015-10-06 09:41:47 -0700169 if ((fillState == kEmpty_SkipFillState) && (args[0] != lastMovePt)) {
170 fillState = kSingleLine_SkipFillState;
171 break;
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000172 }
halcanary8b2bc252015-10-06 09:41:47 -0700173 fillState = kNonSingleLine_SkipFillState;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000174 break;
reed40c85e42015-01-05 10:01:25 -0800175 case SkPath::kQuad_Verb:
176 append_quad(args, &currentSegment);
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000177 fillState = kNonSingleLine_SkipFillState;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000178 break;
reed40c85e42015-01-05 10:01:25 -0800179 case SkPath::kConic_Verb: {
reed40c85e42015-01-05 10:01:25 -0800180 SkAutoConicToQuads converter;
Hal Canary385468f2017-02-13 11:03:23 -0500181 const SkPoint* quads = converter.computeQuads(args, iter.conicWeight(), tolerance);
reed40c85e42015-01-05 10:01:25 -0800182 for (int i = 0; i < converter.countQuads(); ++i) {
183 append_quad(&quads[i * 2], &currentSegment);
184 }
halcanary8b2bc252015-10-06 09:41:47 -0700185 fillState = kNonSingleLine_SkipFillState;
reed40c85e42015-01-05 10:01:25 -0800186 } break;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000187 case SkPath::kCubic_Verb:
188 AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000189 args[3].fX, args[3].fY, &currentSegment);
190 fillState = kNonSingleLine_SkipFillState;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000191 break;
192 case SkPath::kClose_Verb:
Hal Canary385468f2017-02-13 11:03:23 -0500193 ClosePath(&currentSegment);
halcanary8b2bc252015-10-06 09:41:47 -0700194 currentSegment.writeToStream(content);
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000195 currentSegment.reset();
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000196 break;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000197 default:
198 SkASSERT(false);
199 break;
200 }
201 }
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000202 if (currentSegment.bytesWritten() > 0) {
halcanary7af21502015-02-23 12:17:59 -0800203 currentSegment.writeToStream(content);
vandebo@chromium.org683001c2012-05-09 17:17:51 +0000204 }
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000205}
206
207// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000208void SkPDFUtils::ClosePath(SkWStream* content) {
209 content->writeText("h\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000210}
211
212// static
213void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000214 SkWStream* content) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000215 if (style == SkPaint::kFill_Style) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000216 content->writeText("f");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000217 } else if (style == SkPaint::kStrokeAndFill_Style) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000218 content->writeText("B");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000219 } else if (style == SkPaint::kStroke_Style) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000220 content->writeText("S");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000221 }
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000222
223 if (style != SkPaint::kStroke_Style) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000224 NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
225 NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000226 if (fill == SkPath::kEvenOdd_FillType) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000227 content->writeText("*");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000228 }
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000229 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000230 content->writeText("\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000231}
232
233// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000234void SkPDFUtils::StrokePath(SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000235 SkPDFUtils::PaintPath(
236 SkPaint::kStroke_Style, SkPath::kWinding_FillType, content);
237}
vandebo@chromium.org6112c212011-05-13 03:50:38 +0000238
239// static
240void SkPDFUtils::DrawFormXObject(int objectIndex, SkWStream* content) {
commit-bot@chromium.org47401352013-07-23 21:49:29 +0000241 content->writeText("/");
242 content->writeText(SkPDFResourceDict::getResourceName(
243 SkPDFResourceDict::kXObject_ResourceType,
244 objectIndex).c_str());
vandebo@chromium.org6112c212011-05-13 03:50:38 +0000245 content->writeText(" Do\n");
246}
247
248// static
249void SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) {
commit-bot@chromium.org47401352013-07-23 21:49:29 +0000250 content->writeText("/");
251 content->writeText(SkPDFResourceDict::getResourceName(
252 SkPDFResourceDict::kExtGState_ResourceType,
253 objectIndex).c_str());
vandebo@chromium.org6112c212011-05-13 03:50:38 +0000254 content->writeText(" gs\n");
255}
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000256
257// static
258void SkPDFUtils::ApplyPattern(int objectIndex, SkWStream* content) {
259 // Select Pattern color space (CS, cs) and set pattern object as current
260 // color (SCN, scn)
261 SkString resourceName = SkPDFResourceDict::getResourceName(
262 SkPDFResourceDict::kPattern_ResourceType,
263 objectIndex);
264 content->writeText("/Pattern CS/Pattern cs/");
265 content->writeText(resourceName.c_str());
266 content->writeText(" SCN/");
267 content->writeText(resourceName.c_str());
268 content->writeText(" scn\n");
269}
halcanarybc4696b2015-05-06 10:56:04 -0700270
halcanaryeb92cb32016-07-15 13:41:27 -0700271size_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) {
272 if (value == 255 || value == 0) {
273 result[0] = value ? '1' : '0';
274 result[1] = '\0';
275 return 1;
276 }
277 // int x = 0.5 + (1000.0 / 255.0) * value;
278 int x = SkFixedRoundToInt((SK_Fixed1 * 1000 / 255) * value);
279 result[0] = '.';
280 for (int i = 3; i > 0; --i) {
281 result[i] = '0' + x % 10;
282 x /= 10;
283 }
284 int j;
285 for (j = 3; j > 1; --j) {
286 if (result[j] != '0') {
287 break;
288 }
289 }
290 result[j + 1] = '\0';
291 return j + 1;
292}
293
halcanaryee41b752016-06-23 14:08:11 -0700294void SkPDFUtils::WriteString(SkWStream* wStream, const char* cin, size_t len) {
halcanarybc4696b2015-05-06 10:56:04 -0700295 SkDEBUGCODE(static const size_t kMaxLen = 65535;)
296 SkASSERT(len <= kMaxLen);
297
halcanaryee41b752016-06-23 14:08:11 -0700298 size_t extraCharacterCount = 0;
halcanarybc4696b2015-05-06 10:56:04 -0700299 for (size_t i = 0; i < len; i++) {
300 if (cin[i] > '~' || cin[i] < ' ') {
halcanaryee41b752016-06-23 14:08:11 -0700301 extraCharacterCount += 3;
halcanarybc4696b2015-05-06 10:56:04 -0700302 }
303 if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') {
halcanaryee41b752016-06-23 14:08:11 -0700304 ++extraCharacterCount;
halcanarybc4696b2015-05-06 10:56:04 -0700305 }
306 }
halcanaryee41b752016-06-23 14:08:11 -0700307 if (extraCharacterCount <= len) {
308 wStream->writeText("(");
halcanarybc4696b2015-05-06 10:56:04 -0700309 for (size_t i = 0; i < len; i++) {
halcanaryee41b752016-06-23 14:08:11 -0700310 if (cin[i] > '~' || cin[i] < ' ') {
311 uint8_t c = static_cast<uint8_t>(cin[i]);
312 uint8_t octal[4];
313 octal[0] = '\\';
314 octal[1] = '0' + ( c >> 6 );
315 octal[2] = '0' + ((c >> 3) & 0x07);
316 octal[3] = '0' + ( c & 0x07);
317 wStream->write(octal, 4);
318 } else {
319 if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') {
320 wStream->writeText("\\");
321 }
322 wStream->write(&cin[i], 1);
halcanarybc4696b2015-05-06 10:56:04 -0700323 }
halcanarybc4696b2015-05-06 10:56:04 -0700324 }
halcanaryee41b752016-06-23 14:08:11 -0700325 wStream->writeText(")");
halcanarybc4696b2015-05-06 10:56:04 -0700326 } else {
halcanaryee41b752016-06-23 14:08:11 -0700327 wStream->writeText("<");
halcanarybc4696b2015-05-06 10:56:04 -0700328 for (size_t i = 0; i < len; i++) {
329 uint8_t c = static_cast<uint8_t>(cin[i]);
Hal Canaryd6e6e662017-06-17 10:38:13 -0400330 char hexValue[2] = { SkHexadecimalDigits::gUpper[c >> 4],
331 SkHexadecimalDigits::gUpper[c & 0xF] };
halcanaryee41b752016-06-23 14:08:11 -0700332 wStream->write(hexValue, 2);
halcanarybc4696b2015-05-06 10:56:04 -0700333 }
halcanaryee41b752016-06-23 14:08:11 -0700334 wStream->writeText(">");
halcanarybc4696b2015-05-06 10:56:04 -0700335 }
halcanarybc4696b2015-05-06 10:56:04 -0700336}
Hal Canary94fd66c2017-07-05 11:25:42 -0400337
338bool SkPDFUtils::InverseTransformBBox(const SkMatrix& matrix, SkRect* bbox) {
339 SkMatrix inverse;
340 if (!matrix.invert(&inverse)) {
341 return false;
342 }
343 inverse.mapRect(bbox);
344 return true;
345}
346
347void SkPDFUtils::PopulateTilingPatternDict(SkPDFDict* pattern,
348 SkRect& bbox,
349 sk_sp<SkPDFDict> resources,
350 const SkMatrix& matrix) {
351 const int kTiling_PatternType = 1;
352 const int kColoredTilingPattern_PaintType = 1;
353 const int kConstantSpacing_TilingType = 1;
354
355 pattern->insertName("Type", "Pattern");
356 pattern->insertInt("PatternType", kTiling_PatternType);
357 pattern->insertInt("PaintType", kColoredTilingPattern_PaintType);
358 pattern->insertInt("TilingType", kConstantSpacing_TilingType);
359 pattern->insertObject("BBox", SkPDFUtils::RectToArray(bbox));
360 pattern->insertScalar("XStep", bbox.width());
361 pattern->insertScalar("YStep", bbox.height());
362 pattern->insertObject("Resources", std::move(resources));
363 if (!matrix.isIdentity()) {
364 pattern->insertObject("Matrix", SkPDFUtils::MatrixToArray(matrix));
365 }
366}
Hal Canary4f29c202017-07-18 10:28:31 -0400367
368bool SkPDFUtils::ToBitmap(const SkImage* img, SkBitmap* dst) {
369 SkASSERT(img);
370 SkASSERT(dst);
371 SkBitmap bitmap;
372 if(as_IB(img)->getROPixels(&bitmap, nullptr)) {
373 SkASSERT(bitmap.dimensions() == img->dimensions());
374 SkASSERT(!bitmap.drawsNothing());
375 *dst = std::move(bitmap);
376 return true;
377 }
378 return false;
379}