1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/pdf/SkPDFUtils.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 11cb93a386Sopenharmony_ci#include "include/core/SkData.h" 12cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 13cb93a386Sopenharmony_ci#include "include/core/SkString.h" 14cb93a386Sopenharmony_ci#include "include/private/SkFixed.h" 15cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 16cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 17cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 18cb93a386Sopenharmony_ci#include "src/pdf/SkPDFResourceDict.h" 19cb93a386Sopenharmony_ci#include "src/pdf/SkPDFTypes.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci#include <cmath> 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciconst char* SkPDFUtils::BlendModeName(SkBlendMode mode) { 24cb93a386Sopenharmony_ci // PDF32000.book section 11.3.5 "Blend Mode" 25cb93a386Sopenharmony_ci switch (mode) { 26cb93a386Sopenharmony_ci case SkBlendMode::kSrcOver: return "Normal"; 27cb93a386Sopenharmony_ci case SkBlendMode::kXor: return "Normal"; // (unsupported mode) 28cb93a386Sopenharmony_ci case SkBlendMode::kPlus: return "Normal"; // (unsupported mode) 29cb93a386Sopenharmony_ci case SkBlendMode::kScreen: return "Screen"; 30cb93a386Sopenharmony_ci case SkBlendMode::kOverlay: return "Overlay"; 31cb93a386Sopenharmony_ci case SkBlendMode::kDarken: return "Darken"; 32cb93a386Sopenharmony_ci case SkBlendMode::kLighten: return "Lighten"; 33cb93a386Sopenharmony_ci case SkBlendMode::kColorDodge: return "ColorDodge"; 34cb93a386Sopenharmony_ci case SkBlendMode::kColorBurn: return "ColorBurn"; 35cb93a386Sopenharmony_ci case SkBlendMode::kHardLight: return "HardLight"; 36cb93a386Sopenharmony_ci case SkBlendMode::kSoftLight: return "SoftLight"; 37cb93a386Sopenharmony_ci case SkBlendMode::kDifference: return "Difference"; 38cb93a386Sopenharmony_ci case SkBlendMode::kExclusion: return "Exclusion"; 39cb93a386Sopenharmony_ci case SkBlendMode::kMultiply: return "Multiply"; 40cb93a386Sopenharmony_ci case SkBlendMode::kHue: return "Hue"; 41cb93a386Sopenharmony_ci case SkBlendMode::kSaturation: return "Saturation"; 42cb93a386Sopenharmony_ci case SkBlendMode::kColor: return "Color"; 43cb93a386Sopenharmony_ci case SkBlendMode::kLuminosity: return "Luminosity"; 44cb93a386Sopenharmony_ci // Other blendmodes are handled in SkPDFDevice::setUpContentEntry. 45cb93a386Sopenharmony_ci default: return nullptr; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci} 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_cistd::unique_ptr<SkPDFArray> SkPDFUtils::RectToArray(const SkRect& r) { 50cb93a386Sopenharmony_ci return SkPDFMakeArray(r.left(), r.top(), r.right(), r.bottom()); 51cb93a386Sopenharmony_ci} 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_cistd::unique_ptr<SkPDFArray> SkPDFUtils::MatrixToArray(const SkMatrix& matrix) { 54cb93a386Sopenharmony_ci SkScalar a[6]; 55cb93a386Sopenharmony_ci if (!matrix.asAffine(a)) { 56cb93a386Sopenharmony_ci SkMatrix::SetAffineIdentity(a); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci return SkPDFMakeArray(a[0], a[1], a[2], a[3], a[4], a[5]); 59cb93a386Sopenharmony_ci} 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_civoid SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) { 62cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(x, content); 63cb93a386Sopenharmony_ci content->writeText(" "); 64cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(y, content); 65cb93a386Sopenharmony_ci content->writeText(" m\n"); 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_civoid SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) { 69cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(x, content); 70cb93a386Sopenharmony_ci content->writeText(" "); 71cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(y, content); 72cb93a386Sopenharmony_ci content->writeText(" l\n"); 73cb93a386Sopenharmony_ci} 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_cistatic void append_cubic(SkScalar ctl1X, SkScalar ctl1Y, 76cb93a386Sopenharmony_ci SkScalar ctl2X, SkScalar ctl2Y, 77cb93a386Sopenharmony_ci SkScalar dstX, SkScalar dstY, SkWStream* content) { 78cb93a386Sopenharmony_ci SkString cmd("y\n"); 79cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(ctl1X, content); 80cb93a386Sopenharmony_ci content->writeText(" "); 81cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(ctl1Y, content); 82cb93a386Sopenharmony_ci content->writeText(" "); 83cb93a386Sopenharmony_ci if (ctl2X != dstX || ctl2Y != dstY) { 84cb93a386Sopenharmony_ci cmd.set("c\n"); 85cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(ctl2X, content); 86cb93a386Sopenharmony_ci content->writeText(" "); 87cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(ctl2Y, content); 88cb93a386Sopenharmony_ci content->writeText(" "); 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(dstX, content); 91cb93a386Sopenharmony_ci content->writeText(" "); 92cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(dstY, content); 93cb93a386Sopenharmony_ci content->writeText(" "); 94cb93a386Sopenharmony_ci content->writeText(cmd.c_str()); 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_cistatic void append_quad(const SkPoint quad[], SkWStream* content) { 98cb93a386Sopenharmony_ci SkPoint cubic[4]; 99cb93a386Sopenharmony_ci SkConvertQuadToCubic(quad, cubic); 100cb93a386Sopenharmony_ci append_cubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, 101cb93a386Sopenharmony_ci cubic[3].fX, cubic[3].fY, content); 102cb93a386Sopenharmony_ci} 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_civoid SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) { 105cb93a386Sopenharmony_ci // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. 106cb93a386Sopenharmony_ci SkScalar bottom = std::min(rect.fBottom, rect.fTop); 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(rect.fLeft, content); 109cb93a386Sopenharmony_ci content->writeText(" "); 110cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(bottom, content); 111cb93a386Sopenharmony_ci content->writeText(" "); 112cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(rect.width(), content); 113cb93a386Sopenharmony_ci content->writeText(" "); 114cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(rect.height(), content); 115cb93a386Sopenharmony_ci content->writeText(" re\n"); 116cb93a386Sopenharmony_ci} 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_civoid SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, 119cb93a386Sopenharmony_ci bool doConsumeDegerates, SkWStream* content, 120cb93a386Sopenharmony_ci SkScalar tolerance) { 121cb93a386Sopenharmony_ci if (path.isEmpty() && SkPaint::kFill_Style == paintStyle) { 122cb93a386Sopenharmony_ci SkPDFUtils::AppendRectangle({0, 0, 0, 0}, content); 123cb93a386Sopenharmony_ci return; 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci // Filling a path with no area results in a drawing in PDF renderers but 126cb93a386Sopenharmony_ci // Chrome expects to be able to draw some such entities with no visible 127cb93a386Sopenharmony_ci // result, so we detect those cases and discard the drawing for them. 128cb93a386Sopenharmony_ci // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y). 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci SkRect rect; 131cb93a386Sopenharmony_ci bool isClosed; // Both closure and direction need to be checked. 132cb93a386Sopenharmony_ci SkPathDirection direction; 133cb93a386Sopenharmony_ci if (path.isRect(&rect, &isClosed, &direction) && 134cb93a386Sopenharmony_ci isClosed && 135cb93a386Sopenharmony_ci (SkPathDirection::kCW == direction || 136cb93a386Sopenharmony_ci SkPathFillType::kEvenOdd == path.getFillType())) 137cb93a386Sopenharmony_ci { 138cb93a386Sopenharmony_ci SkPDFUtils::AppendRectangle(rect, content); 139cb93a386Sopenharmony_ci return; 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci enum SkipFillState { 143cb93a386Sopenharmony_ci kEmpty_SkipFillState, 144cb93a386Sopenharmony_ci kSingleLine_SkipFillState, 145cb93a386Sopenharmony_ci kNonSingleLine_SkipFillState, 146cb93a386Sopenharmony_ci }; 147cb93a386Sopenharmony_ci SkipFillState fillState = kEmpty_SkipFillState; 148cb93a386Sopenharmony_ci //if (paintStyle != SkPaint::kFill_Style) { 149cb93a386Sopenharmony_ci // fillState = kNonSingleLine_SkipFillState; 150cb93a386Sopenharmony_ci //} 151cb93a386Sopenharmony_ci SkPoint lastMovePt = SkPoint::Make(0,0); 152cb93a386Sopenharmony_ci SkDynamicMemoryWStream currentSegment; 153cb93a386Sopenharmony_ci SkPoint args[4]; 154cb93a386Sopenharmony_ci SkPath::Iter iter(path, false); 155cb93a386Sopenharmony_ci for (SkPath::Verb verb = iter.next(args); 156cb93a386Sopenharmony_ci verb != SkPath::kDone_Verb; 157cb93a386Sopenharmony_ci verb = iter.next(args)) { 158cb93a386Sopenharmony_ci // args gets all the points, even the implicit first point. 159cb93a386Sopenharmony_ci switch (verb) { 160cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 161cb93a386Sopenharmony_ci MoveTo(args[0].fX, args[0].fY, ¤tSegment); 162cb93a386Sopenharmony_ci lastMovePt = args[0]; 163cb93a386Sopenharmony_ci fillState = kEmpty_SkipFillState; 164cb93a386Sopenharmony_ci break; 165cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 166cb93a386Sopenharmony_ci if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 2)) { 167cb93a386Sopenharmony_ci AppendLine(args[1].fX, args[1].fY, ¤tSegment); 168cb93a386Sopenharmony_ci if ((fillState == kEmpty_SkipFillState) && (args[0] != lastMovePt)) { 169cb93a386Sopenharmony_ci fillState = kSingleLine_SkipFillState; 170cb93a386Sopenharmony_ci break; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci fillState = kNonSingleLine_SkipFillState; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci break; 175cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 176cb93a386Sopenharmony_ci if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 3)) { 177cb93a386Sopenharmony_ci append_quad(args, ¤tSegment); 178cb93a386Sopenharmony_ci fillState = kNonSingleLine_SkipFillState; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci break; 181cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 182cb93a386Sopenharmony_ci if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 3)) { 183cb93a386Sopenharmony_ci SkAutoConicToQuads converter; 184cb93a386Sopenharmony_ci const SkPoint* quads = converter.computeQuads(args, iter.conicWeight(), tolerance); 185cb93a386Sopenharmony_ci for (int i = 0; i < converter.countQuads(); ++i) { 186cb93a386Sopenharmony_ci append_quad(&quads[i * 2], ¤tSegment); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci fillState = kNonSingleLine_SkipFillState; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci break; 191cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 192cb93a386Sopenharmony_ci if (!doConsumeDegerates || !SkPathPriv::AllPointsEq(args, 4)) { 193cb93a386Sopenharmony_ci append_cubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY, 194cb93a386Sopenharmony_ci args[3].fX, args[3].fY, ¤tSegment); 195cb93a386Sopenharmony_ci fillState = kNonSingleLine_SkipFillState; 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci break; 198cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 199cb93a386Sopenharmony_ci ClosePath(¤tSegment); 200cb93a386Sopenharmony_ci currentSegment.writeToStream(content); 201cb93a386Sopenharmony_ci currentSegment.reset(); 202cb93a386Sopenharmony_ci break; 203cb93a386Sopenharmony_ci default: 204cb93a386Sopenharmony_ci SkASSERT(false); 205cb93a386Sopenharmony_ci break; 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci if (currentSegment.bytesWritten() > 0) { 209cb93a386Sopenharmony_ci currentSegment.writeToStream(content); 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci} 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_civoid SkPDFUtils::ClosePath(SkWStream* content) { 214cb93a386Sopenharmony_ci content->writeText("h\n"); 215cb93a386Sopenharmony_ci} 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_civoid SkPDFUtils::PaintPath(SkPaint::Style style, SkPathFillType fill, SkWStream* content) { 218cb93a386Sopenharmony_ci if (style == SkPaint::kFill_Style) { 219cb93a386Sopenharmony_ci content->writeText("f"); 220cb93a386Sopenharmony_ci } else if (style == SkPaint::kStrokeAndFill_Style) { 221cb93a386Sopenharmony_ci content->writeText("B"); 222cb93a386Sopenharmony_ci } else if (style == SkPaint::kStroke_Style) { 223cb93a386Sopenharmony_ci content->writeText("S"); 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ci if (style != SkPaint::kStroke_Style) { 227cb93a386Sopenharmony_ci NOT_IMPLEMENTED(fill == SkPathFillType::kInverseEvenOdd, false); 228cb93a386Sopenharmony_ci NOT_IMPLEMENTED(fill == SkPathFillType::kInverseWinding, false); 229cb93a386Sopenharmony_ci if (fill == SkPathFillType::kEvenOdd) { 230cb93a386Sopenharmony_ci content->writeText("*"); 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci content->writeText("\n"); 234cb93a386Sopenharmony_ci} 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_civoid SkPDFUtils::StrokePath(SkWStream* content) { 237cb93a386Sopenharmony_ci SkPDFUtils::PaintPath(SkPaint::kStroke_Style, SkPathFillType::kWinding, content); 238cb93a386Sopenharmony_ci} 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_civoid SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) { 241cb93a386Sopenharmony_ci SkPDFWriteResourceName(content, SkPDFResourceType::kExtGState, objectIndex); 242cb93a386Sopenharmony_ci content->writeText(" gs\n"); 243cb93a386Sopenharmony_ci} 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_civoid SkPDFUtils::ApplyPattern(int objectIndex, SkWStream* content) { 246cb93a386Sopenharmony_ci // Select Pattern color space (CS, cs) and set pattern object as current 247cb93a386Sopenharmony_ci // color (SCN, scn) 248cb93a386Sopenharmony_ci content->writeText("/Pattern CS/Pattern cs"); 249cb93a386Sopenharmony_ci SkPDFWriteResourceName(content, SkPDFResourceType::kPattern, objectIndex); 250cb93a386Sopenharmony_ci content->writeText(" SCN"); 251cb93a386Sopenharmony_ci SkPDFWriteResourceName(content, SkPDFResourceType::kPattern, objectIndex); 252cb93a386Sopenharmony_ci content->writeText(" scn\n"); 253cb93a386Sopenharmony_ci} 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci// return "x/pow(10, places)", given 0<x<pow(10, places) 256cb93a386Sopenharmony_ci// result points to places+2 chars. 257cb93a386Sopenharmony_cistatic size_t print_permil_as_decimal(int x, char* result, unsigned places) { 258cb93a386Sopenharmony_ci result[0] = '.'; 259cb93a386Sopenharmony_ci for (int i = places; i > 0; --i) { 260cb93a386Sopenharmony_ci result[i] = '0' + x % 10; 261cb93a386Sopenharmony_ci x /= 10; 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci int j; 264cb93a386Sopenharmony_ci for (j = places; j > 1; --j) { 265cb93a386Sopenharmony_ci if (result[j] != '0') { 266cb93a386Sopenharmony_ci break; 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci result[j + 1] = '\0'; 270cb93a386Sopenharmony_ci return j + 1; 271cb93a386Sopenharmony_ci} 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_cistatic constexpr int int_pow(int base, unsigned exp, int acc = 1) { 275cb93a386Sopenharmony_ci return exp < 1 ? acc 276cb93a386Sopenharmony_ci : int_pow(base * base, 277cb93a386Sopenharmony_ci exp / 2, 278cb93a386Sopenharmony_ci (exp % 2) ? acc * base : acc); 279cb93a386Sopenharmony_ci} 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_cisize_t SkPDFUtils::ColorToDecimalF(float value, char result[kFloatColorDecimalCount + 2]) { 283cb93a386Sopenharmony_ci static constexpr int kFactor = int_pow(10, kFloatColorDecimalCount); 284cb93a386Sopenharmony_ci int x = sk_float_round2int(value * kFactor); 285cb93a386Sopenharmony_ci if (x >= kFactor || x <= 0) { // clamp to 0-1 286cb93a386Sopenharmony_ci result[0] = x > 0 ? '1' : '0'; 287cb93a386Sopenharmony_ci result[1] = '\0'; 288cb93a386Sopenharmony_ci return 1; 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci return print_permil_as_decimal(x, result, kFloatColorDecimalCount); 291cb93a386Sopenharmony_ci} 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_cisize_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) { 294cb93a386Sopenharmony_ci if (value == 255 || value == 0) { 295cb93a386Sopenharmony_ci result[0] = value ? '1' : '0'; 296cb93a386Sopenharmony_ci result[1] = '\0'; 297cb93a386Sopenharmony_ci return 1; 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci // int x = 0.5 + (1000.0 / 255.0) * value; 300cb93a386Sopenharmony_ci int x = SkFixedRoundToInt((SK_Fixed1 * 1000 / 255) * value); 301cb93a386Sopenharmony_ci return print_permil_as_decimal(x, result, 3); 302cb93a386Sopenharmony_ci} 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_cibool SkPDFUtils::InverseTransformBBox(const SkMatrix& matrix, SkRect* bbox) { 305cb93a386Sopenharmony_ci SkMatrix inverse; 306cb93a386Sopenharmony_ci if (!matrix.invert(&inverse)) { 307cb93a386Sopenharmony_ci return false; 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci inverse.mapRect(bbox); 310cb93a386Sopenharmony_ci return true; 311cb93a386Sopenharmony_ci} 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_civoid SkPDFUtils::PopulateTilingPatternDict(SkPDFDict* pattern, 314cb93a386Sopenharmony_ci SkRect& bbox, 315cb93a386Sopenharmony_ci std::unique_ptr<SkPDFDict> resources, 316cb93a386Sopenharmony_ci const SkMatrix& matrix) { 317cb93a386Sopenharmony_ci const int kTiling_PatternType = 1; 318cb93a386Sopenharmony_ci const int kColoredTilingPattern_PaintType = 1; 319cb93a386Sopenharmony_ci const int kConstantSpacing_TilingType = 1; 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci pattern->insertName("Type", "Pattern"); 322cb93a386Sopenharmony_ci pattern->insertInt("PatternType", kTiling_PatternType); 323cb93a386Sopenharmony_ci pattern->insertInt("PaintType", kColoredTilingPattern_PaintType); 324cb93a386Sopenharmony_ci pattern->insertInt("TilingType", kConstantSpacing_TilingType); 325cb93a386Sopenharmony_ci pattern->insertObject("BBox", SkPDFUtils::RectToArray(bbox)); 326cb93a386Sopenharmony_ci pattern->insertScalar("XStep", bbox.width()); 327cb93a386Sopenharmony_ci pattern->insertScalar("YStep", bbox.height()); 328cb93a386Sopenharmony_ci pattern->insertObject("Resources", std::move(resources)); 329cb93a386Sopenharmony_ci if (!matrix.isIdentity()) { 330cb93a386Sopenharmony_ci pattern->insertObject("Matrix", SkPDFUtils::MatrixToArray(matrix)); 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci} 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_cibool SkPDFUtils::ToBitmap(const SkImage* img, SkBitmap* dst) { 335cb93a386Sopenharmony_ci SkASSERT(img); 336cb93a386Sopenharmony_ci SkASSERT(dst); 337cb93a386Sopenharmony_ci SkBitmap bitmap; 338cb93a386Sopenharmony_ci // TODO: support GPU images 339cb93a386Sopenharmony_ci if(as_IB(img)->getROPixels(nullptr, &bitmap)) { 340cb93a386Sopenharmony_ci SkASSERT(bitmap.dimensions() == img->dimensions()); 341cb93a386Sopenharmony_ci SkASSERT(!bitmap.drawsNothing()); 342cb93a386Sopenharmony_ci *dst = std::move(bitmap); 343cb93a386Sopenharmony_ci return true; 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci return false; 346cb93a386Sopenharmony_ci} 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci#ifdef SK_PDF_BASE85_BINARY 349cb93a386Sopenharmony_civoid SkPDFUtils::Base85Encode(std::unique_ptr<SkStreamAsset> stream, SkDynamicMemoryWStream* dst) { 350cb93a386Sopenharmony_ci SkASSERT(dst); 351cb93a386Sopenharmony_ci SkASSERT(stream); 352cb93a386Sopenharmony_ci dst->writeText("\n"); 353cb93a386Sopenharmony_ci int column = 0; 354cb93a386Sopenharmony_ci while (true) { 355cb93a386Sopenharmony_ci uint8_t src[4] = {0, 0, 0, 0}; 356cb93a386Sopenharmony_ci size_t count = stream->read(src, 4); 357cb93a386Sopenharmony_ci SkASSERT(count < 5); 358cb93a386Sopenharmony_ci if (0 == count) { 359cb93a386Sopenharmony_ci dst->writeText("~>\n"); 360cb93a386Sopenharmony_ci return; 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci uint32_t v = ((uint32_t)src[0] << 24) | ((uint32_t)src[1] << 16) | 363cb93a386Sopenharmony_ci ((uint32_t)src[2] << 8) | src[3]; 364cb93a386Sopenharmony_ci if (v == 0 && count == 4) { 365cb93a386Sopenharmony_ci dst->writeText("z"); 366cb93a386Sopenharmony_ci column += 1; 367cb93a386Sopenharmony_ci } else { 368cb93a386Sopenharmony_ci char buffer[5]; 369cb93a386Sopenharmony_ci for (int n = 4; n > 0; --n) { 370cb93a386Sopenharmony_ci buffer[n] = (v % 85) + '!'; 371cb93a386Sopenharmony_ci v /= 85; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci buffer[0] = v + '!'; 374cb93a386Sopenharmony_ci dst->write(buffer, count + 1); 375cb93a386Sopenharmony_ci column += count + 1; 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci if (column > 74) { 378cb93a386Sopenharmony_ci dst->writeText("\n"); 379cb93a386Sopenharmony_ci column = 0; 380cb93a386Sopenharmony_ci } 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci} 383cb93a386Sopenharmony_ci#endif // SK_PDF_BASE85_BINARY 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_civoid SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) { 386cb93a386Sopenharmony_ci SkScalar values[6]; 387cb93a386Sopenharmony_ci if (!matrix.asAffine(values)) { 388cb93a386Sopenharmony_ci SkMatrix::SetAffineIdentity(values); 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci for (SkScalar v : values) { 391cb93a386Sopenharmony_ci SkPDFUtils::AppendScalar(v, content); 392cb93a386Sopenharmony_ci content->writeText(" "); 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci content->writeText("cm\n"); 395cb93a386Sopenharmony_ci} 396