1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFFont.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkDrawable.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMetrics.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontStyle.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMaskFilter.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkJpegEncoder.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkBitmaskEnum.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDescriptor.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDevice.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGlyph.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMask.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMaskFilterBase.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathEffectBase.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStrike.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStrikeSpec.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFBitmap.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFDevice.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFDocumentPriv.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFFormXObject.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFGraphicState.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFMakeToUnicodeCmap.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFSubsetFont.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFType1Font.h"
60*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFUtils.h"
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker #include <limits.h>
63*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
64*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
65*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
66*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
67*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
70*c8dee2aaSAndroid Build Coastguard Worker
GetType1GlyphNames(const SkTypeface & face,SkString * dst)71*c8dee2aaSAndroid Build Coastguard Worker void SkPDFFont::GetType1GlyphNames(const SkTypeface& face, SkString* dst) {
72*c8dee2aaSAndroid Build Coastguard Worker face.getPostScriptGlyphNames(dst);
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker namespace {
76*c8dee2aaSAndroid Build Coastguard Worker // PDF's notion of symbolic vs non-symbolic is related to the character set, not
77*c8dee2aaSAndroid Build Coastguard Worker // symbols vs. characters. Rarely is a font the right character set to call it
78*c8dee2aaSAndroid Build Coastguard Worker // non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
79*c8dee2aaSAndroid Build Coastguard Worker static const int32_t kPdfSymbolic = 4;
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker // scale from em-units to base-1000, returning as a SkScalar
from_font_units(SkScalar scaled,uint16_t emSize)82*c8dee2aaSAndroid Build Coastguard Worker inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
83*c8dee2aaSAndroid Build Coastguard Worker return emSize == 1000 ? scaled : scaled * 1000 / emSize;
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
scaleFromFontUnits(int16_t val,uint16_t emSize)86*c8dee2aaSAndroid Build Coastguard Worker inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
87*c8dee2aaSAndroid Build Coastguard Worker return from_font_units(SkIntToScalar(val), emSize);
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker
setGlyphWidthAndBoundingBox(SkScalar width,SkIRect box,SkDynamicMemoryWStream * content)90*c8dee2aaSAndroid Build Coastguard Worker void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
91*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream* content) {
92*c8dee2aaSAndroid Build Coastguard Worker // Specify width and bounding box for the glyph.
93*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::AppendScalar(width, content);
94*c8dee2aaSAndroid Build Coastguard Worker content->writeText(" 0 ");
95*c8dee2aaSAndroid Build Coastguard Worker content->writeDecAsText(box.fLeft);
96*c8dee2aaSAndroid Build Coastguard Worker content->writeText(" ");
97*c8dee2aaSAndroid Build Coastguard Worker content->writeDecAsText(box.fTop);
98*c8dee2aaSAndroid Build Coastguard Worker content->writeText(" ");
99*c8dee2aaSAndroid Build Coastguard Worker content->writeDecAsText(box.fRight);
100*c8dee2aaSAndroid Build Coastguard Worker content->writeText(" ");
101*c8dee2aaSAndroid Build Coastguard Worker content->writeDecAsText(box.fBottom);
102*c8dee2aaSAndroid Build Coastguard Worker content->writeText(" d1\n");
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker } // namespace
106*c8dee2aaSAndroid Build Coastguard Worker
scale_paint(SkPaint & paint,SkScalar fontToEMScale)107*c8dee2aaSAndroid Build Coastguard Worker static bool scale_paint(SkPaint& paint, SkScalar fontToEMScale) {
108*c8dee2aaSAndroid Build Coastguard Worker // What we really want here is a way ask the path effect or mask filter for a scaled
109*c8dee2aaSAndroid Build Coastguard Worker // version of itself (if it is linearly scalable).
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker if (SkMaskFilterBase* mfb = as_MFB(paint.getMaskFilter())) {
112*c8dee2aaSAndroid Build Coastguard Worker SkMaskFilterBase::BlurRec blurRec;
113*c8dee2aaSAndroid Build Coastguard Worker if (mfb->asABlur(&blurRec)) {
114*c8dee2aaSAndroid Build Coastguard Worker // asABlur returns false if ignoring the CTM
115*c8dee2aaSAndroid Build Coastguard Worker blurRec.fSigma *= fontToEMScale;
116*c8dee2aaSAndroid Build Coastguard Worker paint.setMaskFilter(SkMaskFilter::MakeBlur(blurRec.fStyle, blurRec.fSigma, true));
117*c8dee2aaSAndroid Build Coastguard Worker } else {
118*c8dee2aaSAndroid Build Coastguard Worker return false;
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker if (SkPathEffectBase* peb = as_PEB(paint.getPathEffect())) {
122*c8dee2aaSAndroid Build Coastguard Worker AutoSTMalloc<4, SkScalar> intervals;
123*c8dee2aaSAndroid Build Coastguard Worker SkPathEffectBase::DashInfo dashInfo(intervals, 4, 0);
124*c8dee2aaSAndroid Build Coastguard Worker if (peb->asADash(&dashInfo) == SkPathEffectBase::DashType::kDash) {
125*c8dee2aaSAndroid Build Coastguard Worker if (dashInfo.fCount > 4) {
126*c8dee2aaSAndroid Build Coastguard Worker intervals.realloc(dashInfo.fCount);
127*c8dee2aaSAndroid Build Coastguard Worker peb->asADash(&dashInfo);
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker for (int32_t i = 0; i < dashInfo.fCount; ++i) {
130*c8dee2aaSAndroid Build Coastguard Worker dashInfo.fIntervals[i] *= fontToEMScale;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker dashInfo.fPhase *= fontToEMScale;
133*c8dee2aaSAndroid Build Coastguard Worker paint.setPathEffect(
134*c8dee2aaSAndroid Build Coastguard Worker SkDashPathEffect::Make(dashInfo.fIntervals, dashInfo.fCount, dashInfo.fPhase));
135*c8dee2aaSAndroid Build Coastguard Worker } else {
136*c8dee2aaSAndroid Build Coastguard Worker return false;
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker
140*c8dee2aaSAndroid Build Coastguard Worker if (paint.getStyle() != SkPaint::kFill_Style && paint.getStrokeWidth() > 0) {
141*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeMiter(paint.getStrokeMiter() * fontToEMScale);
142*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(paint.getStrokeWidth() * fontToEMScale);
143*c8dee2aaSAndroid Build Coastguard Worker }
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker return true;
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker
SkPDFStrikeSpec(SkStrikeSpec strikeSpec,SkScalar em)149*c8dee2aaSAndroid Build Coastguard Worker SkPDFStrikeSpec::SkPDFStrikeSpec(SkStrikeSpec strikeSpec, SkScalar em)
150*c8dee2aaSAndroid Build Coastguard Worker : fStrikeSpec(std::move(strikeSpec))
151*c8dee2aaSAndroid Build Coastguard Worker , fUnitsPerEM(em)
152*c8dee2aaSAndroid Build Coastguard Worker {}
153*c8dee2aaSAndroid Build Coastguard Worker
Make(SkPDFDocument * doc,const SkFont & font,const SkPaint & paint)154*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPDFStrike> SkPDFStrike::Make(SkPDFDocument* doc, const SkFont& font, const SkPaint& paint) {
155*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
156*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
157*c8dee2aaSAndroid Build Coastguard Worker #else
158*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kBitmapFontSize = 64;
159*c8dee2aaSAndroid Build Coastguard Worker #endif
160*c8dee2aaSAndroid Build Coastguard Worker
161*c8dee2aaSAndroid Build Coastguard Worker SkScalar unitsPerEm = static_cast<SkScalar>(font.getTypeface()->getUnitsPerEm());
162*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 < unitsPerEm);
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker SkFont canonFont(font);
165*c8dee2aaSAndroid Build Coastguard Worker canonFont.setBaselineSnap(false); // canonicalize
166*c8dee2aaSAndroid Build Coastguard Worker canonFont.setEdging(SkFont::Edging::kAntiAlias); // canonicalize
167*c8dee2aaSAndroid Build Coastguard Worker canonFont.setEmbeddedBitmaps(false); // canonicalize
168*c8dee2aaSAndroid Build Coastguard Worker //canonFont.setEmbolden(); // applied by scaler context, sets glyph path to modified
169*c8dee2aaSAndroid Build Coastguard Worker canonFont.setForceAutoHinting(false); // canonicalize
170*c8dee2aaSAndroid Build Coastguard Worker canonFont.setHinting(SkFontHinting::kNone); // canonicalize
171*c8dee2aaSAndroid Build Coastguard Worker canonFont.setLinearMetrics(true); // canonicalize
172*c8dee2aaSAndroid Build Coastguard Worker canonFont.setScaleX(1.0f); // original value applied by SkPDFDevice
173*c8dee2aaSAndroid Build Coastguard Worker //canonFont.setSize(unitsPerEm); // canonicalize below, adjusted by SkPDFDevice
174*c8dee2aaSAndroid Build Coastguard Worker canonFont.setSkewX(0.0f); // original value applied by SkPDFDevice
175*c8dee2aaSAndroid Build Coastguard Worker canonFont.setSubpixel(false); // canonicalize
176*c8dee2aaSAndroid Build Coastguard Worker //canonFont.setTypeface();
177*c8dee2aaSAndroid Build Coastguard Worker
178*c8dee2aaSAndroid Build Coastguard Worker SkPaint pathPaint(paint);
179*c8dee2aaSAndroid Build Coastguard Worker if (scale_paint(pathPaint, unitsPerEm / font.getSize())) {
180*c8dee2aaSAndroid Build Coastguard Worker canonFont.setSize(unitsPerEm);
181*c8dee2aaSAndroid Build Coastguard Worker } else {
182*c8dee2aaSAndroid Build Coastguard Worker canonFont.setSize(font.getSize());
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker SkScalar pathStrikeEM = canonFont.getSize();
185*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec pathStrikeSpec = SkStrikeSpec::MakeWithNoDevice(canonFont, &pathPaint);
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker if (sk_sp<SkPDFStrike>* strike = doc->fStrikes.find(pathStrikeSpec.descriptor())) {
188*c8dee2aaSAndroid Build Coastguard Worker return *strike;
189*c8dee2aaSAndroid Build Coastguard Worker }
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker if (kBitmapFontSize <= 0) {
192*c8dee2aaSAndroid Build Coastguard Worker // old code path compatibility
193*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPDFStrike> strike(new SkPDFStrike(SkPDFStrikeSpec(pathStrikeSpec, pathStrikeEM),
194*c8dee2aaSAndroid Build Coastguard Worker SkPDFStrikeSpec(pathStrikeSpec, pathStrikeEM),
195*c8dee2aaSAndroid Build Coastguard Worker pathPaint.getMaskFilter(), doc));
196*c8dee2aaSAndroid Build Coastguard Worker doc->fStrikes.set(strike);
197*c8dee2aaSAndroid Build Coastguard Worker return strike;
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker
200*c8dee2aaSAndroid Build Coastguard Worker SkPaint imagePaint(paint);
201*c8dee2aaSAndroid Build Coastguard Worker if (scale_paint(imagePaint, kBitmapFontSize / font.getSize())) {
202*c8dee2aaSAndroid Build Coastguard Worker canonFont.setSize(kBitmapFontSize);
203*c8dee2aaSAndroid Build Coastguard Worker } else {
204*c8dee2aaSAndroid Build Coastguard Worker canonFont.setSize(font.getSize());
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker SkScalar imageStrikeEM = canonFont.getSize();
207*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec imageStrikeSpec = SkStrikeSpec::MakeWithNoDevice(canonFont, &imagePaint);
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPDFStrike> strike(new SkPDFStrike(SkPDFStrikeSpec(pathStrikeSpec, pathStrikeEM),
210*c8dee2aaSAndroid Build Coastguard Worker SkPDFStrikeSpec(imageStrikeSpec, imageStrikeEM),
211*c8dee2aaSAndroid Build Coastguard Worker pathPaint.getMaskFilter(), doc));
212*c8dee2aaSAndroid Build Coastguard Worker doc->fStrikes.set(strike);
213*c8dee2aaSAndroid Build Coastguard Worker return strike;
214*c8dee2aaSAndroid Build Coastguard Worker
215*c8dee2aaSAndroid Build Coastguard Worker }
216*c8dee2aaSAndroid Build Coastguard Worker
SkPDFStrike(SkPDFStrikeSpec path,SkPDFStrikeSpec image,bool hasMaskFilter,SkPDFDocument * doc)217*c8dee2aaSAndroid Build Coastguard Worker SkPDFStrike::SkPDFStrike(SkPDFStrikeSpec path, SkPDFStrikeSpec image, bool hasMaskFilter,
218*c8dee2aaSAndroid Build Coastguard Worker SkPDFDocument* doc)
219*c8dee2aaSAndroid Build Coastguard Worker : fPath(std::move(path))
220*c8dee2aaSAndroid Build Coastguard Worker , fImage(std::move(image))
221*c8dee2aaSAndroid Build Coastguard Worker , fHasMaskFilter(hasMaskFilter)
222*c8dee2aaSAndroid Build Coastguard Worker , fDoc(doc)
223*c8dee2aaSAndroid Build Coastguard Worker {
224*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fDoc);
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker
GetKey(const sk_sp<SkPDFStrike> & strike)227*c8dee2aaSAndroid Build Coastguard Worker const SkDescriptor& SkPDFStrike::Traits::GetKey(const sk_sp<SkPDFStrike>& strike) {
228*c8dee2aaSAndroid Build Coastguard Worker return strike->fPath.fStrikeSpec.descriptor();
229*c8dee2aaSAndroid Build Coastguard Worker }
Hash(const SkDescriptor & descriptor)230*c8dee2aaSAndroid Build Coastguard Worker uint32_t SkPDFStrike::Traits::Hash(const SkDescriptor& descriptor) {
231*c8dee2aaSAndroid Build Coastguard Worker return descriptor.getChecksum();
232*c8dee2aaSAndroid Build Coastguard Worker }
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
235*c8dee2aaSAndroid Build Coastguard Worker // class SkPDFFont
236*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
237*c8dee2aaSAndroid Build Coastguard Worker
238*c8dee2aaSAndroid Build Coastguard Worker /* Resources are canonicalized and uniqueified by pointer so there has to be
239*c8dee2aaSAndroid Build Coastguard Worker * some additional state indicating which subset of the font is used. It
240*c8dee2aaSAndroid Build Coastguard Worker * must be maintained at the document granularity.
241*c8dee2aaSAndroid Build Coastguard Worker */
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::~SkPDFFont() = default;
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::SkPDFFont(SkPDFFont&&) = default;
246*c8dee2aaSAndroid Build Coastguard Worker
can_embed(const SkAdvancedTypefaceMetrics & metrics)247*c8dee2aaSAndroid Build Coastguard Worker static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
248*c8dee2aaSAndroid Build Coastguard Worker return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
249*c8dee2aaSAndroid Build Coastguard Worker }
250*c8dee2aaSAndroid Build Coastguard Worker
can_subset(const SkAdvancedTypefaceMetrics & metrics)251*c8dee2aaSAndroid Build Coastguard Worker static bool can_subset(const SkAdvancedTypefaceMetrics& metrics) {
252*c8dee2aaSAndroid Build Coastguard Worker return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag);
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker
GetMetrics(const SkTypeface & typeface,SkPDFDocument * canon)255*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(const SkTypeface& typeface,
256*c8dee2aaSAndroid Build Coastguard Worker SkPDFDocument* canon) {
257*c8dee2aaSAndroid Build Coastguard Worker SkTypefaceID id = typeface.uniqueID();
258*c8dee2aaSAndroid Build Coastguard Worker if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
259*c8dee2aaSAndroid Build Coastguard Worker return ptr->get(); // canon retains ownership.
260*c8dee2aaSAndroid Build Coastguard Worker }
261*c8dee2aaSAndroid Build Coastguard Worker
262*c8dee2aaSAndroid Build Coastguard Worker int count = typeface.countGlyphs();
263*c8dee2aaSAndroid Build Coastguard Worker if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
264*c8dee2aaSAndroid Build Coastguard Worker // Cache nullptr to skip this check. Use SkSafeUnref().
265*c8dee2aaSAndroid Build Coastguard Worker canon->fTypefaceMetrics.set(id, nullptr);
266*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
267*c8dee2aaSAndroid Build Coastguard Worker }
268*c8dee2aaSAndroid Build Coastguard Worker
269*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface.getAdvancedMetrics();
270*c8dee2aaSAndroid Build Coastguard Worker if (!metrics) {
271*c8dee2aaSAndroid Build Coastguard Worker metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
274*c8dee2aaSAndroid Build Coastguard Worker SkFont font;
275*c8dee2aaSAndroid Build Coastguard Worker font.setHinting(SkFontHinting::kNone);
276*c8dee2aaSAndroid Build Coastguard Worker font.setTypeface(sk_ref_sp(&typeface));
277*c8dee2aaSAndroid Build Coastguard Worker font.setSize(1000); // glyph coordinate system
278*c8dee2aaSAndroid Build Coastguard Worker if (0 == metrics->fStemV) {
279*c8dee2aaSAndroid Build Coastguard Worker // Figure out a good guess for StemV - Min width of i, I, !, 1.
280*c8dee2aaSAndroid Build Coastguard Worker // This probably isn't very good with an italic font.
281*c8dee2aaSAndroid Build Coastguard Worker int16_t stemV = SHRT_MAX;
282*c8dee2aaSAndroid Build Coastguard Worker for (char c : {'i', 'I', '!', '1'}) {
283*c8dee2aaSAndroid Build Coastguard Worker uint16_t g = font.unicharToGlyph(c);
284*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds;
285*c8dee2aaSAndroid Build Coastguard Worker font.getBounds(&g, 1, &bounds, nullptr);
286*c8dee2aaSAndroid Build Coastguard Worker stemV = std::min(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker metrics->fStemV = stemV;
289*c8dee2aaSAndroid Build Coastguard Worker }
290*c8dee2aaSAndroid Build Coastguard Worker if (0 == metrics->fCapHeight) {
291*c8dee2aaSAndroid Build Coastguard Worker // Figure out a good guess for CapHeight: average the height of M and X.
292*c8dee2aaSAndroid Build Coastguard Worker SkScalar capHeight = 0;
293*c8dee2aaSAndroid Build Coastguard Worker for (char c : {'M', 'X'}) {
294*c8dee2aaSAndroid Build Coastguard Worker uint16_t g = font.unicharToGlyph(c);
295*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds;
296*c8dee2aaSAndroid Build Coastguard Worker font.getBounds(&g, 1, &bounds, nullptr);
297*c8dee2aaSAndroid Build Coastguard Worker capHeight += bounds.height();
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
300*c8dee2aaSAndroid Build Coastguard Worker }
301*c8dee2aaSAndroid Build Coastguard Worker }
302*c8dee2aaSAndroid Build Coastguard Worker // Fonts are always subset, so always prepend the subset tag.
303*c8dee2aaSAndroid Build Coastguard Worker metrics->fPostScriptName.prepend(canon->nextFontSubsetTag());
304*c8dee2aaSAndroid Build Coastguard Worker return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
305*c8dee2aaSAndroid Build Coastguard Worker }
306*c8dee2aaSAndroid Build Coastguard Worker
GetUnicodeMap(const SkTypeface & typeface,SkPDFDocument * canon)307*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface& typeface,
308*c8dee2aaSAndroid Build Coastguard Worker SkPDFDocument* canon) {
309*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(canon);
310*c8dee2aaSAndroid Build Coastguard Worker SkTypefaceID id = typeface.uniqueID();
311*c8dee2aaSAndroid Build Coastguard Worker if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
312*c8dee2aaSAndroid Build Coastguard Worker return *ptr;
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkUnichar> buffer(typeface.countGlyphs());
315*c8dee2aaSAndroid Build Coastguard Worker typeface.getGlyphToUnicodeMap(buffer.data());
316*c8dee2aaSAndroid Build Coastguard Worker return *canon->fToUnicodeMap.set(id, std::move(buffer));
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker
GetUnicodeMapEx(const SkTypeface & typeface,SkPDFDocument * canon)319*c8dee2aaSAndroid Build Coastguard Worker THashMap<SkGlyphID, SkString>& SkPDFFont::GetUnicodeMapEx(const SkTypeface& typeface,
320*c8dee2aaSAndroid Build Coastguard Worker SkPDFDocument* canon) {
321*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(canon);
322*c8dee2aaSAndroid Build Coastguard Worker SkTypefaceID id = typeface.uniqueID();
323*c8dee2aaSAndroid Build Coastguard Worker if (THashMap<SkGlyphID, SkString>* ptr = canon->fToUnicodeMapEx.find(id)) {
324*c8dee2aaSAndroid Build Coastguard Worker return *ptr;
325*c8dee2aaSAndroid Build Coastguard Worker }
326*c8dee2aaSAndroid Build Coastguard Worker return *canon->fToUnicodeMapEx.set(id, THashMap<SkGlyphID, SkString>());
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker
FontType(const SkPDFStrike & pdfStrike,const SkAdvancedTypefaceMetrics & metrics)329*c8dee2aaSAndroid Build Coastguard Worker SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkPDFStrike& pdfStrike,
330*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics& metrics) {
331*c8dee2aaSAndroid Build Coastguard Worker if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kVariable_FontFlag) ||
332*c8dee2aaSAndroid Build Coastguard Worker // PDF is actually interested in the encoding of the data, not just the logical format.
333*c8dee2aaSAndroid Build Coastguard Worker // If the TrueType is actually wOFF or wOF2 then it should not be directly embedded in PDF.
334*c8dee2aaSAndroid Build Coastguard Worker // For now export these as Type3 until the subsetter can handle table based fonts.
335*c8dee2aaSAndroid Build Coastguard Worker // See https://github.com/harfbuzz/harfbuzz/issues/3609 and
336*c8dee2aaSAndroid Build Coastguard Worker // https://skia-review.googlesource.com/c/skia/+/543485
337*c8dee2aaSAndroid Build Coastguard Worker SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kAltDataFormat_FontFlag) ||
338*c8dee2aaSAndroid Build Coastguard Worker SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) ||
339*c8dee2aaSAndroid Build Coastguard Worker // Something like 45eeeddb00741493 and 7c86e7641b348ca7b0 to output OpenType should work,
340*c8dee2aaSAndroid Build Coastguard Worker // but requires PDF 1.6 which is still not supported by all printers. One could fix this by
341*c8dee2aaSAndroid Build Coastguard Worker // using bare CFF like 31a170226c22244cbd00497b67f6ae181f0f3e76 which is only PDF 1.3,
342*c8dee2aaSAndroid Build Coastguard Worker // but this only works when the CFF CIDs == CFF index == GlyphID as PDF bare CFF prefers
343*c8dee2aaSAndroid Build Coastguard Worker // CFF CIDs instead of GlyphIDs and Skia doesn't know the CIDs.
344*c8dee2aaSAndroid Build Coastguard Worker metrics.fType == SkAdvancedTypefaceMetrics::kCFF_Font ||
345*c8dee2aaSAndroid Build Coastguard Worker pdfStrike.fHasMaskFilter)
346*c8dee2aaSAndroid Build Coastguard Worker {
347*c8dee2aaSAndroid Build Coastguard Worker // force Type3 fallback.
348*c8dee2aaSAndroid Build Coastguard Worker return SkAdvancedTypefaceMetrics::kOther_Font;
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker return metrics.fType;
351*c8dee2aaSAndroid Build Coastguard Worker }
352*c8dee2aaSAndroid Build Coastguard Worker
first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)353*c8dee2aaSAndroid Build Coastguard Worker static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
354*c8dee2aaSAndroid Build Coastguard Worker return gid != 0 ? gid - (gid - 1) % 255 : 1;
355*c8dee2aaSAndroid Build Coastguard Worker }
356*c8dee2aaSAndroid Build Coastguard Worker
getFontResource(const SkGlyph * glyph)357*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont* SkPDFStrike::getFontResource(const SkGlyph* glyph) {
358*c8dee2aaSAndroid Build Coastguard Worker const SkTypeface& typeface = fPath.fStrikeSpec.typeface();
359*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(typeface, fDoc);
360*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
361*c8dee2aaSAndroid Build Coastguard Worker // GetMetrics only returns null to signify a bad typeface.
362*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
363*c8dee2aaSAndroid Build Coastguard Worker
364*c8dee2aaSAndroid Build Coastguard Worker // Determine the FontType.
365*c8dee2aaSAndroid Build Coastguard Worker // 1. Can the "original" font data be used directly
366*c8dee2aaSAndroid Build Coastguard Worker // (simple OpenType, no non-default variations, not WOFF, etc).
367*c8dee2aaSAndroid Build Coastguard Worker // 2. Is the glyph to be drawn unmodified from the font data
368*c8dee2aaSAndroid Build Coastguard Worker // (no path effect, stroking, fake bolding, extra matrix, mask filter).
369*c8dee2aaSAndroid Build Coastguard Worker // 3. Will PDF viewers draw this glyph the way we want
370*c8dee2aaSAndroid Build Coastguard Worker // (at the moment this means an unmodified glyph path).
371*c8dee2aaSAndroid Build Coastguard Worker SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(*this, metrics);
372*c8dee2aaSAndroid Build Coastguard Worker // Keep the type (and original data) if the glyph is empty or the glyph has an unmodified path.
373*c8dee2aaSAndroid Build Coastguard Worker // Otherwise, fall back to Type3.
374*c8dee2aaSAndroid Build Coastguard Worker if (!(glyph->isEmpty() || (glyph->path() && !glyph->pathIsModified()))) {
375*c8dee2aaSAndroid Build Coastguard Worker type = SkAdvancedTypefaceMetrics::kOther_Font;
376*c8dee2aaSAndroid Build Coastguard Worker }
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker bool multibyte = SkPDFFont::IsMultiByte(type);
379*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID subsetCode =
380*c8dee2aaSAndroid Build Coastguard Worker multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyph->getGlyphID());
381*c8dee2aaSAndroid Build Coastguard Worker if (SkPDFFont* font = fFontMap.find(subsetCode)) {
382*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(multibyte == font->multiByteGlyphs());
383*c8dee2aaSAndroid Build Coastguard Worker return font;
384*c8dee2aaSAndroid Build Coastguard Worker }
385*c8dee2aaSAndroid Build Coastguard Worker
386*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID lastGlyph = SkToU16(typeface.countGlyphs() - 1);
387*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(glyph->getGlyphID() <= lastGlyph); // should be caught by SkPDFDevice::internalDrawText
388*c8dee2aaSAndroid Build Coastguard Worker
389*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID firstNonZeroGlyph;
390*c8dee2aaSAndroid Build Coastguard Worker if (multibyte) {
391*c8dee2aaSAndroid Build Coastguard Worker firstNonZeroGlyph = 1;
392*c8dee2aaSAndroid Build Coastguard Worker } else {
393*c8dee2aaSAndroid Build Coastguard Worker firstNonZeroGlyph = subsetCode;
394*c8dee2aaSAndroid Build Coastguard Worker lastGlyph = SkToU16(std::min<int>((int)lastGlyph, 254 + (int)subsetCode));
395*c8dee2aaSAndroid Build Coastguard Worker }
396*c8dee2aaSAndroid Build Coastguard Worker auto ref = fDoc->reserveRef();
397*c8dee2aaSAndroid Build Coastguard Worker return fFontMap.set(subsetCode, SkPDFFont(this, firstNonZeroGlyph, lastGlyph, type, ref));
398*c8dee2aaSAndroid Build Coastguard Worker }
399*c8dee2aaSAndroid Build Coastguard Worker
SkPDFFont(const SkPDFStrike * strike,SkGlyphID firstGlyphID,SkGlyphID lastGlyphID,SkAdvancedTypefaceMetrics::FontType fontType,SkPDFIndirectReference indirectReference)400*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::SkPDFFont(const SkPDFStrike* strike,
401*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID firstGlyphID,
402*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID lastGlyphID,
403*c8dee2aaSAndroid Build Coastguard Worker SkAdvancedTypefaceMetrics::FontType fontType,
404*c8dee2aaSAndroid Build Coastguard Worker SkPDFIndirectReference indirectReference)
405*c8dee2aaSAndroid Build Coastguard Worker : fStrike(strike)
406*c8dee2aaSAndroid Build Coastguard Worker , fGlyphUsage(firstGlyphID, lastGlyphID)
407*c8dee2aaSAndroid Build Coastguard Worker , fIndirectReference(indirectReference)
408*c8dee2aaSAndroid Build Coastguard Worker , fFontType(fontType)
409*c8dee2aaSAndroid Build Coastguard Worker {
410*c8dee2aaSAndroid Build Coastguard Worker // Always include glyph 0
411*c8dee2aaSAndroid Build Coastguard Worker this->noteGlyphUsage(0);
412*c8dee2aaSAndroid Build Coastguard Worker }
413*c8dee2aaSAndroid Build Coastguard Worker
PopulateCommonFontDescriptor(SkPDFDict * descriptor,const SkAdvancedTypefaceMetrics & metrics,uint16_t emSize,int16_t defaultWidth)414*c8dee2aaSAndroid Build Coastguard Worker void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor,
415*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics& metrics,
416*c8dee2aaSAndroid Build Coastguard Worker uint16_t emSize,
417*c8dee2aaSAndroid Build Coastguard Worker int16_t defaultWidth) {
418*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertName("FontName", metrics.fPostScriptName);
419*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
420*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertScalar("Ascent",
421*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fAscent, emSize));
422*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertScalar("Descent",
423*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fDescent, emSize));
424*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertScalar("StemV",
425*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fStemV, emSize));
426*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertScalar("CapHeight",
427*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fCapHeight, emSize));
428*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
429*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertObject("FontBBox",
430*c8dee2aaSAndroid Build Coastguard Worker SkPDFMakeArray(scaleFromFontUnits(metrics.fBBox.left(), emSize),
431*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fBBox.bottom(), emSize),
432*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fBBox.right(), emSize),
433*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(metrics.fBBox.top(), emSize)));
434*c8dee2aaSAndroid Build Coastguard Worker if (defaultWidth > 0) {
435*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertScalar("MissingWidth",
436*c8dee2aaSAndroid Build Coastguard Worker scaleFromFontUnits(defaultWidth, emSize));
437*c8dee2aaSAndroid Build Coastguard Worker }
438*c8dee2aaSAndroid Build Coastguard Worker }
439*c8dee2aaSAndroid Build Coastguard Worker
440*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
441*c8dee2aaSAndroid Build Coastguard Worker // Type0Font
442*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
443*c8dee2aaSAndroid Build Coastguard Worker
emit_subset_type0(const SkPDFFont & font,SkPDFDocument * doc)444*c8dee2aaSAndroid Build Coastguard Worker static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
445*c8dee2aaSAndroid Build Coastguard Worker const SkTypeface& typeface = font.strike().fPath.fStrikeSpec.typeface();
446*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics* metricsPtr = SkPDFFont::GetMetrics(typeface, doc);
447*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(metricsPtr);
448*c8dee2aaSAndroid Build Coastguard Worker if (!metricsPtr) {
449*c8dee2aaSAndroid Build Coastguard Worker return;
450*c8dee2aaSAndroid Build Coastguard Worker }
451*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
452*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(can_embed(metrics));
453*c8dee2aaSAndroid Build Coastguard Worker SkAdvancedTypefaceMetrics::FontType type = font.getType();
454*c8dee2aaSAndroid Build Coastguard Worker
455*c8dee2aaSAndroid Build Coastguard Worker auto descriptor = SkPDFMakeDict("FontDescriptor");
456*c8dee2aaSAndroid Build Coastguard Worker uint16_t emSize = SkToU16(SkScalarRoundToInt(font.strike().fPath.fUnitsPerEM));
457*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
458*c8dee2aaSAndroid Build Coastguard Worker
459*c8dee2aaSAndroid Build Coastguard Worker int ttcIndex;
460*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkStreamAsset> fontAsset = typeface.openStream(&ttcIndex);
461*c8dee2aaSAndroid Build Coastguard Worker size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
462*c8dee2aaSAndroid Build Coastguard Worker if (0 == fontSize) {
463*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
464*c8dee2aaSAndroid Build Coastguard Worker "empty stream (%p) when identified as kType1CID_Font "
465*c8dee2aaSAndroid Build Coastguard Worker "or kTrueType_Font.\n", &typeface, fontAsset.get());
466*c8dee2aaSAndroid Build Coastguard Worker } else if (type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
467*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> subsetFontData;
468*c8dee2aaSAndroid Build Coastguard Worker if (can_subset(metrics)) {
469*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(font.firstGlyphID() == 1);
470*c8dee2aaSAndroid Build Coastguard Worker subsetFontData = SkPDFSubsetFont(typeface, font.glyphUsage());
471*c8dee2aaSAndroid Build Coastguard Worker }
472*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkStreamAsset> subsetFontAsset;
473*c8dee2aaSAndroid Build Coastguard Worker if (subsetFontData) {
474*c8dee2aaSAndroid Build Coastguard Worker subsetFontAsset = SkMemoryStream::Make(std::move(subsetFontData));
475*c8dee2aaSAndroid Build Coastguard Worker } else {
476*c8dee2aaSAndroid Build Coastguard Worker // If subsetting fails, fall back to original font data.
477*c8dee2aaSAndroid Build Coastguard Worker subsetFontAsset = std::move(fontAsset);
478*c8dee2aaSAndroid Build Coastguard Worker }
479*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
480*c8dee2aaSAndroid Build Coastguard Worker streamDict->insertInt("Length1", subsetFontAsset->getLength());
481*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertRef("FontFile2",
482*c8dee2aaSAndroid Build Coastguard Worker SkPDFStreamOut(std::move(streamDict), std::move(subsetFontAsset),
483*c8dee2aaSAndroid Build Coastguard Worker doc, SkPDFSteamCompressionEnabled::Yes));
484*c8dee2aaSAndroid Build Coastguard Worker } else if (type == SkAdvancedTypefaceMetrics::kType1CID_Font) {
485*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
486*c8dee2aaSAndroid Build Coastguard Worker streamDict->insertName("Subtype", "CIDFontType0C");
487*c8dee2aaSAndroid Build Coastguard Worker descriptor->insertRef("FontFile3",
488*c8dee2aaSAndroid Build Coastguard Worker SkPDFStreamOut(std::move(streamDict), std::move(fontAsset),
489*c8dee2aaSAndroid Build Coastguard Worker doc, SkPDFSteamCompressionEnabled::Yes));
490*c8dee2aaSAndroid Build Coastguard Worker } else {
491*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false);
492*c8dee2aaSAndroid Build Coastguard Worker }
493*c8dee2aaSAndroid Build Coastguard Worker
494*c8dee2aaSAndroid Build Coastguard Worker auto newCIDFont = SkPDFMakeDict("Font");
495*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
496*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
497*c8dee2aaSAndroid Build Coastguard Worker
498*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
499*c8dee2aaSAndroid Build Coastguard Worker case SkAdvancedTypefaceMetrics::kType1CID_Font:
500*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertName("Subtype", "CIDFontType0");
501*c8dee2aaSAndroid Build Coastguard Worker break;
502*c8dee2aaSAndroid Build Coastguard Worker case SkAdvancedTypefaceMetrics::kTrueType_Font:
503*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertName("Subtype", "CIDFontType2");
504*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertName("CIDToGIDMap", "Identity");
505*c8dee2aaSAndroid Build Coastguard Worker break;
506*c8dee2aaSAndroid Build Coastguard Worker default:
507*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false);
508*c8dee2aaSAndroid Build Coastguard Worker }
509*c8dee2aaSAndroid Build Coastguard Worker auto sysInfo = SkPDFMakeDict();
510*c8dee2aaSAndroid Build Coastguard Worker // These are actually ASCII strings.
511*c8dee2aaSAndroid Build Coastguard Worker sysInfo->insertByteString("Registry", "Adobe");
512*c8dee2aaSAndroid Build Coastguard Worker sysInfo->insertByteString("Ordering", "Identity");
513*c8dee2aaSAndroid Build Coastguard Worker sysInfo->insertInt("Supplement", 0);
514*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
515*c8dee2aaSAndroid Build Coastguard Worker
516*c8dee2aaSAndroid Build Coastguard Worker // Unfortunately, poppler enforces DW (default width) must be an integer.
517*c8dee2aaSAndroid Build Coastguard Worker int32_t defaultWidth = 0;
518*c8dee2aaSAndroid Build Coastguard Worker {
519*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
520*c8dee2aaSAndroid Build Coastguard Worker font.strike().fPath, font.glyphUsage(), &defaultWidth);
521*c8dee2aaSAndroid Build Coastguard Worker if (widths && widths->size() > 0) {
522*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertObject("W", std::move(widths));
523*c8dee2aaSAndroid Build Coastguard Worker }
524*c8dee2aaSAndroid Build Coastguard Worker newCIDFont->insertInt("DW", defaultWidth);
525*c8dee2aaSAndroid Build Coastguard Worker }
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////
528*c8dee2aaSAndroid Build Coastguard Worker
529*c8dee2aaSAndroid Build Coastguard Worker SkPDFDict fontDict("Font");
530*c8dee2aaSAndroid Build Coastguard Worker fontDict.insertName("Subtype", "Type0");
531*c8dee2aaSAndroid Build Coastguard Worker fontDict.insertName("BaseFont", metrics.fPostScriptName);
532*c8dee2aaSAndroid Build Coastguard Worker fontDict.insertName("Encoding", "Identity-H");
533*c8dee2aaSAndroid Build Coastguard Worker auto descendantFonts = SkPDFMakeArray();
534*c8dee2aaSAndroid Build Coastguard Worker descendantFonts->appendRef(doc->emit(*newCIDFont));
535*c8dee2aaSAndroid Build Coastguard Worker fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
536*c8dee2aaSAndroid Build Coastguard Worker
537*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkUnichar>& glyphToUnicode =
538*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::GetUnicodeMap(typeface, doc);
539*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(SkToSizeT(typeface.countGlyphs()) == glyphToUnicode.size());
540*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkStreamAsset> toUnicode =
541*c8dee2aaSAndroid Build Coastguard Worker SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
542*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::GetUnicodeMapEx(typeface, doc),
543*c8dee2aaSAndroid Build Coastguard Worker &font.glyphUsage(),
544*c8dee2aaSAndroid Build Coastguard Worker font.multiByteGlyphs(),
545*c8dee2aaSAndroid Build Coastguard Worker font.firstGlyphID(),
546*c8dee2aaSAndroid Build Coastguard Worker font.lastGlyphID());
547*c8dee2aaSAndroid Build Coastguard Worker fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
548*c8dee2aaSAndroid Build Coastguard Worker
549*c8dee2aaSAndroid Build Coastguard Worker doc->emit(fontDict, font.indirectReference());
550*c8dee2aaSAndroid Build Coastguard Worker }
551*c8dee2aaSAndroid Build Coastguard Worker
552*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
553*c8dee2aaSAndroid Build Coastguard Worker // PDFType3Font
554*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
555*c8dee2aaSAndroid Build Coastguard Worker
556*c8dee2aaSAndroid Build Coastguard Worker namespace {
557*c8dee2aaSAndroid Build Coastguard Worker // returns [0, first, first+1, ... last-1, last]
558*c8dee2aaSAndroid Build Coastguard Worker struct SingleByteGlyphIdIterator {
SingleByteGlyphIdIterator__anon63c3b1de0211::SingleByteGlyphIdIterator559*c8dee2aaSAndroid Build Coastguard Worker SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
560*c8dee2aaSAndroid Build Coastguard Worker : fFirst(first), fLast(last) {
561*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fFirst > 0);
562*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fLast >= first);
563*c8dee2aaSAndroid Build Coastguard Worker }
564*c8dee2aaSAndroid Build Coastguard Worker struct Iter {
operator ++__anon63c3b1de0211::SingleByteGlyphIdIterator::Iter565*c8dee2aaSAndroid Build Coastguard Worker void operator++() {
566*c8dee2aaSAndroid Build Coastguard Worker fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
567*c8dee2aaSAndroid Build Coastguard Worker }
568*c8dee2aaSAndroid Build Coastguard Worker // This is an input_iterator
operator *__anon63c3b1de0211::SingleByteGlyphIdIterator::Iter569*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
operator !=__anon63c3b1de0211::SingleByteGlyphIdIterator::Iter570*c8dee2aaSAndroid Build Coastguard Worker bool operator!=(const Iter& rhs) const {
571*c8dee2aaSAndroid Build Coastguard Worker return fCurrent != rhs.fCurrent;
572*c8dee2aaSAndroid Build Coastguard Worker }
Iter__anon63c3b1de0211::SingleByteGlyphIdIterator::Iter573*c8dee2aaSAndroid Build Coastguard Worker Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
574*c8dee2aaSAndroid Build Coastguard Worker private:
575*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID fFirst;
576*c8dee2aaSAndroid Build Coastguard Worker int fCurrent; // must be int to make fLast+1 to fit
577*c8dee2aaSAndroid Build Coastguard Worker };
begin__anon63c3b1de0211::SingleByteGlyphIdIterator578*c8dee2aaSAndroid Build Coastguard Worker Iter begin() const { return Iter(fFirst, 0); }
end__anon63c3b1de0211::SingleByteGlyphIdIterator579*c8dee2aaSAndroid Build Coastguard Worker Iter end() const { return Iter(fFirst, (int)fLast + 1); }
580*c8dee2aaSAndroid Build Coastguard Worker private:
581*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID fFirst;
582*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID fLast;
583*c8dee2aaSAndroid Build Coastguard Worker };
584*c8dee2aaSAndroid Build Coastguard Worker } // namespace
585*c8dee2aaSAndroid Build Coastguard Worker
586*c8dee2aaSAndroid Build Coastguard Worker struct ImageAndOffset {
587*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImage;
588*c8dee2aaSAndroid Build Coastguard Worker SkIPoint fOffset;
589*c8dee2aaSAndroid Build Coastguard Worker };
to_image(SkGlyphID gid,SkBulkGlyphMetricsAndImages * smallGlyphs)590*c8dee2aaSAndroid Build Coastguard Worker static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages* smallGlyphs) {
591*c8dee2aaSAndroid Build Coastguard Worker const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
592*c8dee2aaSAndroid Build Coastguard Worker SkMask mask = glyph->mask();
593*c8dee2aaSAndroid Build Coastguard Worker if (!mask.fImage) {
594*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, {0, 0}};
595*c8dee2aaSAndroid Build Coastguard Worker }
596*c8dee2aaSAndroid Build Coastguard Worker SkIRect bounds = mask.fBounds;
597*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bm;
598*c8dee2aaSAndroid Build Coastguard Worker switch (mask.fFormat) {
599*c8dee2aaSAndroid Build Coastguard Worker case SkMask::kBW_Format: {
600*c8dee2aaSAndroid Build Coastguard Worker // Make a gray image, used to smask a rectangle.
601*c8dee2aaSAndroid Build Coastguard Worker // TODO: emit as MaskImage?
602*c8dee2aaSAndroid Build Coastguard Worker const SkISize size = bounds.size();
603*c8dee2aaSAndroid Build Coastguard Worker bm.allocPixels(SkImageInfo::Make(size, kGray_8_SkColorType, kUnknown_SkAlphaType));
604*c8dee2aaSAndroid Build Coastguard Worker for (int y = 0; y < bm.height(); ++y) {
605*c8dee2aaSAndroid Build Coastguard Worker for (int x8 = 0; x8 < bm.width(); x8 += 8) {
606*c8dee2aaSAndroid Build Coastguard Worker uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
607*c8dee2aaSAndroid Build Coastguard Worker int e = std::min(x8 + 8, bm.width());
608*c8dee2aaSAndroid Build Coastguard Worker for (int x = x8; x < e; ++x) {
609*c8dee2aaSAndroid Build Coastguard Worker *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
610*c8dee2aaSAndroid Build Coastguard Worker }
611*c8dee2aaSAndroid Build Coastguard Worker }
612*c8dee2aaSAndroid Build Coastguard Worker }
613*c8dee2aaSAndroid Build Coastguard Worker bm.setImmutable();
614*c8dee2aaSAndroid Build Coastguard Worker return {bm.asImage(), {bounds.x(), bounds.y()}};
615*c8dee2aaSAndroid Build Coastguard Worker }
616*c8dee2aaSAndroid Build Coastguard Worker case SkMask::kA8_Format:
617*c8dee2aaSAndroid Build Coastguard Worker case SkMask::k3D_Format: // just do the A8 part
618*c8dee2aaSAndroid Build Coastguard Worker // Make a gray image, used to smask a rectangle.
619*c8dee2aaSAndroid Build Coastguard Worker return {SkImages::RasterFromData(
620*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo::Make(bounds.size(), kGray_8_SkColorType, kUnknown_SkAlphaType),
621*c8dee2aaSAndroid Build Coastguard Worker SkData::MakeWithCopy(mask.fImage, mask.computeImageSize()),
622*c8dee2aaSAndroid Build Coastguard Worker mask.fRowBytes),
623*c8dee2aaSAndroid Build Coastguard Worker {bounds.x(), bounds.y()}};
624*c8dee2aaSAndroid Build Coastguard Worker case SkMask::kARGB32_Format:
625*c8dee2aaSAndroid Build Coastguard Worker // These will be drawn as images directly.
626*c8dee2aaSAndroid Build Coastguard Worker return {SkImages::RasterFromData(
627*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo::MakeN32Premul(bounds.size()),
628*c8dee2aaSAndroid Build Coastguard Worker SkData::MakeWithCopy(mask.fImage, mask.computeTotalImageSize()),
629*c8dee2aaSAndroid Build Coastguard Worker mask.fRowBytes),
630*c8dee2aaSAndroid Build Coastguard Worker {bounds.x(), bounds.y()}};
631*c8dee2aaSAndroid Build Coastguard Worker case SkMask::kLCD16_Format:
632*c8dee2aaSAndroid Build Coastguard Worker default:
633*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false);
634*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, {0, 0}};
635*c8dee2aaSAndroid Build Coastguard Worker }
636*c8dee2aaSAndroid Build Coastguard Worker }
637*c8dee2aaSAndroid Build Coastguard Worker
type3_descriptor(SkPDFDocument * doc,const SkTypeface & typeface,SkScalar xHeight)638*c8dee2aaSAndroid Build Coastguard Worker static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
639*c8dee2aaSAndroid Build Coastguard Worker const SkTypeface& typeface,
640*c8dee2aaSAndroid Build Coastguard Worker SkScalar xHeight) {
641*c8dee2aaSAndroid Build Coastguard Worker if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface.uniqueID())) {
642*c8dee2aaSAndroid Build Coastguard Worker return *ptr;
643*c8dee2aaSAndroid Build Coastguard Worker }
644*c8dee2aaSAndroid Build Coastguard Worker
645*c8dee2aaSAndroid Build Coastguard Worker SkPDFDict descriptor("FontDescriptor");
646*c8dee2aaSAndroid Build Coastguard Worker int32_t fontDescriptorFlags = kPdfSymbolic;
647*c8dee2aaSAndroid Build Coastguard Worker
648*c8dee2aaSAndroid Build Coastguard Worker /** PDF32000_2008: FontFamily should be used for Type3 fonts in Tagged PDF documents. */
649*c8dee2aaSAndroid Build Coastguard Worker SkString familyName;
650*c8dee2aaSAndroid Build Coastguard Worker typeface.getFamilyName(&familyName);
651*c8dee2aaSAndroid Build Coastguard Worker if (!familyName.isEmpty()) {
652*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertByteString("FontFamily", familyName);
653*c8dee2aaSAndroid Build Coastguard Worker }
654*c8dee2aaSAndroid Build Coastguard Worker
655*c8dee2aaSAndroid Build Coastguard Worker /** PDF32000_2008: FontStretch should be used for Type3 fonts in Tagged PDF documents. */
656*c8dee2aaSAndroid Build Coastguard Worker static constexpr const char* stretchNames[9] = {
657*c8dee2aaSAndroid Build Coastguard Worker "UltraCondensed",
658*c8dee2aaSAndroid Build Coastguard Worker "ExtraCondensed",
659*c8dee2aaSAndroid Build Coastguard Worker "Condensed",
660*c8dee2aaSAndroid Build Coastguard Worker "SemiCondensed",
661*c8dee2aaSAndroid Build Coastguard Worker "Normal",
662*c8dee2aaSAndroid Build Coastguard Worker "SemiExpanded",
663*c8dee2aaSAndroid Build Coastguard Worker "Expanded",
664*c8dee2aaSAndroid Build Coastguard Worker "ExtraExpanded",
665*c8dee2aaSAndroid Build Coastguard Worker "UltraExpanded",
666*c8dee2aaSAndroid Build Coastguard Worker };
667*c8dee2aaSAndroid Build Coastguard Worker const char* stretchName = stretchNames[typeface.fontStyle().width() - 1];
668*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertName("FontStretch", stretchName);
669*c8dee2aaSAndroid Build Coastguard Worker
670*c8dee2aaSAndroid Build Coastguard Worker /** PDF32000_2008: FontWeight should be used for Type3 fonts in Tagged PDF documents. */
671*c8dee2aaSAndroid Build Coastguard Worker int weight = (typeface.fontStyle().weight() + 50) / 100;
672*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertInt("FontWeight", SkTPin(weight, 1, 9) * 100);
673*c8dee2aaSAndroid Build Coastguard Worker
674*c8dee2aaSAndroid Build Coastguard Worker if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
675*c8dee2aaSAndroid Build Coastguard Worker // Type3 FontDescriptor does not require all the same fields.
676*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertName("FontName", metrics->fPostScriptName);
677*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
678*c8dee2aaSAndroid Build Coastguard Worker fontDescriptorFlags |= (int32_t)metrics->fStyle;
679*c8dee2aaSAndroid Build Coastguard Worker // Adobe requests CapHeight, XHeight, and StemV be added
680*c8dee2aaSAndroid Build Coastguard Worker // to "greatly help our workflow downstream".
681*c8dee2aaSAndroid Build Coastguard Worker if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
682*c8dee2aaSAndroid Build Coastguard Worker if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
683*c8dee2aaSAndroid Build Coastguard Worker if (xHeight != 0) {
684*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertScalar("XHeight", xHeight);
685*c8dee2aaSAndroid Build Coastguard Worker }
686*c8dee2aaSAndroid Build Coastguard Worker }
687*c8dee2aaSAndroid Build Coastguard Worker descriptor.insertInt("Flags", fontDescriptorFlags);
688*c8dee2aaSAndroid Build Coastguard Worker SkPDFIndirectReference ref = doc->emit(descriptor);
689*c8dee2aaSAndroid Build Coastguard Worker doc->fType3FontDescriptors.set(typeface.uniqueID(), ref);
690*c8dee2aaSAndroid Build Coastguard Worker return ref;
691*c8dee2aaSAndroid Build Coastguard Worker }
692*c8dee2aaSAndroid Build Coastguard Worker
emit_subset_type3(const SkPDFFont & pdfFont,SkPDFDocument * doc)693*c8dee2aaSAndroid Build Coastguard Worker static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
694*c8dee2aaSAndroid Build Coastguard Worker const SkPDFStrike& pdfStrike = pdfFont.strike();
695*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
696*c8dee2aaSAndroid Build Coastguard Worker SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
697*c8dee2aaSAndroid Build Coastguard Worker const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
698*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(lastGlyphID >= firstGlyphID);
699*c8dee2aaSAndroid Build Coastguard Worker // Remove unused glyphs at the end of the range.
700*c8dee2aaSAndroid Build Coastguard Worker // Keep the lastGlyphID >= firstGlyphID invariant true.
701*c8dee2aaSAndroid Build Coastguard Worker while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
702*c8dee2aaSAndroid Build Coastguard Worker --lastGlyphID;
703*c8dee2aaSAndroid Build Coastguard Worker }
704*c8dee2aaSAndroid Build Coastguard Worker SkScalar emSize = pdfStrike.fPath.fUnitsPerEM;
705*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkStrike> strike = pdfStrike.fPath.fStrikeSpec.findOrCreateStrike();
706*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(strike);
707*c8dee2aaSAndroid Build Coastguard Worker SkScalar xHeight = strike->getFontMetrics().fXHeight;
708*c8dee2aaSAndroid Build Coastguard Worker SkBulkGlyphMetricsAndPaths metricsAndPaths((sk_sp<SkStrike>(strike)));
709*c8dee2aaSAndroid Build Coastguard Worker SkBulkGlyphMetricsAndDrawables metricsAndDrawables(std::move(strike));
710*c8dee2aaSAndroid Build Coastguard Worker
711*c8dee2aaSAndroid Build Coastguard Worker SkBulkGlyphMetricsAndImages smallGlyphs(pdfFont.strike().fImage.fStrikeSpec);
712*c8dee2aaSAndroid Build Coastguard Worker float bitmapScale = emSize / pdfStrike.fImage.fUnitsPerEM;
713*c8dee2aaSAndroid Build Coastguard Worker
714*c8dee2aaSAndroid Build Coastguard Worker SkPDFDict font("Font");
715*c8dee2aaSAndroid Build Coastguard Worker font.insertName("Subtype", "Type3");
716*c8dee2aaSAndroid Build Coastguard Worker // Flip about the x-axis and scale by 1/emSize.
717*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fontMatrix;
718*c8dee2aaSAndroid Build Coastguard Worker fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
719*c8dee2aaSAndroid Build Coastguard Worker font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
720*c8dee2aaSAndroid Build Coastguard Worker
721*c8dee2aaSAndroid Build Coastguard Worker auto charProcs = SkPDFMakeDict();
722*c8dee2aaSAndroid Build Coastguard Worker auto encoding = SkPDFMakeDict("Encoding");
723*c8dee2aaSAndroid Build Coastguard Worker
724*c8dee2aaSAndroid Build Coastguard Worker auto encDiffs = SkPDFMakeArray();
725*c8dee2aaSAndroid Build Coastguard Worker // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
726*c8dee2aaSAndroid Build Coastguard Worker // plus 1 for glyph 0;
727*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(firstGlyphID > 0);
728*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(lastGlyphID >= firstGlyphID);
729*c8dee2aaSAndroid Build Coastguard Worker int glyphCount = lastGlyphID - firstGlyphID + 2;
730*c8dee2aaSAndroid Build Coastguard Worker // one other entry for the index of first glyph.
731*c8dee2aaSAndroid Build Coastguard Worker encDiffs->reserve(glyphCount + 1);
732*c8dee2aaSAndroid Build Coastguard Worker encDiffs->appendInt(0); // index of first glyph
733*c8dee2aaSAndroid Build Coastguard Worker
734*c8dee2aaSAndroid Build Coastguard Worker auto widthArray = SkPDFMakeArray();
735*c8dee2aaSAndroid Build Coastguard Worker widthArray->reserve(glyphCount);
736*c8dee2aaSAndroid Build Coastguard Worker
737*c8dee2aaSAndroid Build Coastguard Worker SkIRect bbox = SkIRect::MakeEmpty();
738*c8dee2aaSAndroid Build Coastguard Worker
739*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFDict> xobjects = SkPDFMakeDict();
740*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFDict> graphicStates = SkPDFMakeDict();
741*c8dee2aaSAndroid Build Coastguard Worker for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
742*c8dee2aaSAndroid Build Coastguard Worker SkString characterName;
743*c8dee2aaSAndroid Build Coastguard Worker SkScalar advance = 0.0f;
744*c8dee2aaSAndroid Build Coastguard Worker
745*c8dee2aaSAndroid Build Coastguard Worker if (gID != 0 && !subset.has(gID)) {
746*c8dee2aaSAndroid Build Coastguard Worker characterName.set("g0");
747*c8dee2aaSAndroid Build Coastguard Worker advance = 0.0f;
748*c8dee2aaSAndroid Build Coastguard Worker encDiffs->appendName(std::move(characterName));
749*c8dee2aaSAndroid Build Coastguard Worker widthArray->appendScalar(advance);
750*c8dee2aaSAndroid Build Coastguard Worker continue;
751*c8dee2aaSAndroid Build Coastguard Worker }
752*c8dee2aaSAndroid Build Coastguard Worker
753*c8dee2aaSAndroid Build Coastguard Worker const SkGlyph* pathGlyph = metricsAndPaths.glyph(gID);
754*c8dee2aaSAndroid Build Coastguard Worker const SkGlyph* drawableGlyph = metricsAndDrawables.glyph(gID);
755*c8dee2aaSAndroid Build Coastguard Worker
756*c8dee2aaSAndroid Build Coastguard Worker characterName.printf("g%X", gID);
757*c8dee2aaSAndroid Build Coastguard Worker advance = pathGlyph->advanceX();
758*c8dee2aaSAndroid Build Coastguard Worker encDiffs->appendName(characterName);
759*c8dee2aaSAndroid Build Coastguard Worker widthArray->appendScalar(advance);
760*c8dee2aaSAndroid Build Coastguard Worker
761*c8dee2aaSAndroid Build Coastguard Worker SkIRect glyphBBox = pathGlyph->iRect();
762*c8dee2aaSAndroid Build Coastguard Worker bbox.join(glyphBBox);
763*c8dee2aaSAndroid Build Coastguard Worker const SkPath* path = pathGlyph->path();
764*c8dee2aaSAndroid Build Coastguard Worker SkDrawable* drawable = drawableGlyph->drawable();
765*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream content;
766*c8dee2aaSAndroid Build Coastguard Worker if (drawable && !drawable->getBounds().isEmpty()) {
767*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPDFDevice> glyphDevice = sk_make_sp<SkPDFDevice>(glyphBBox.size(), doc);
768*c8dee2aaSAndroid Build Coastguard Worker SkCanvas canvas(glyphDevice);
769*c8dee2aaSAndroid Build Coastguard Worker canvas.translate(-glyphBBox.fLeft, -glyphBBox.fTop);
770*c8dee2aaSAndroid Build Coastguard Worker canvas.drawDrawable(drawable);
771*c8dee2aaSAndroid Build Coastguard Worker SkPDFIndirectReference xobject = SkPDFMakeFormXObject(
772*c8dee2aaSAndroid Build Coastguard Worker doc, glyphDevice->content(),
773*c8dee2aaSAndroid Build Coastguard Worker SkPDFMakeArray(0, 0, glyphBBox.width(), glyphBBox.height()),
774*c8dee2aaSAndroid Build Coastguard Worker glyphDevice->makeResourceDict(),
775*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::Translate(glyphBBox.fLeft, glyphBBox.fTop), nullptr);
776*c8dee2aaSAndroid Build Coastguard Worker xobjects->insertRef(SkStringPrintf("Xg%X", gID), xobject);
777*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::AppendScalar(drawableGlyph->advanceX(), &content);
778*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" 0 d0\n1 0 0 1 0 0 cm\n/X");
779*c8dee2aaSAndroid Build Coastguard Worker content.write(characterName.c_str(), characterName.size());
780*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" Do\n");
781*c8dee2aaSAndroid Build Coastguard Worker } else if (path && !path->isEmpty() && !pdfStrike.fHasMaskFilter) {
782*c8dee2aaSAndroid Build Coastguard Worker setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
783*c8dee2aaSAndroid Build Coastguard Worker SkPaint::Style style = pathGlyph->pathIsHairline() ? SkPaint::kStroke_Style
784*c8dee2aaSAndroid Build Coastguard Worker : SkPaint::kFill_Style;
785*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::EmitPath(*path, style, &content);
786*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::PaintPath(style, path->getFillType(), &content);
787*c8dee2aaSAndroid Build Coastguard Worker } else if (auto pimg = to_image(gID, &smallGlyphs); pimg.fImage) {
788*c8dee2aaSAndroid Build Coastguard Worker using SkPDFUtils::AppendScalar;
789*c8dee2aaSAndroid Build Coastguard Worker if (pimg.fImage->colorType() != kGray_8_SkColorType) {
790*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(pathGlyph->advanceX(), &content);
791*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" 0 d0\n");
792*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(pimg.fImage->width() * bitmapScale, &content);
793*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" 0 0 ");
794*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
795*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" ");
796*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
797*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" ");
798*c8dee2aaSAndroid Build Coastguard Worker AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,&content);
799*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" cm\n");
800*c8dee2aaSAndroid Build Coastguard Worker content.writeText("/X");
801*c8dee2aaSAndroid Build Coastguard Worker content.write(characterName.c_str(), characterName.size());
802*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" Do\n");
803*c8dee2aaSAndroid Build Coastguard Worker SkPDFIndirectReference image = SkPDFSerializeImage(pimg.fImage.get(), doc);
804*c8dee2aaSAndroid Build Coastguard Worker xobjects->insertRef(SkStringPrintf("Xg%X", gID), image);
805*c8dee2aaSAndroid Build Coastguard Worker } else {
806*c8dee2aaSAndroid Build Coastguard Worker // TODO: For A1, put ImageMask on the PDF image and draw the image?
807*c8dee2aaSAndroid Build Coastguard Worker // The A8 mask has been converted to a Gray image
808*c8dee2aaSAndroid Build Coastguard Worker
809*c8dee2aaSAndroid Build Coastguard Worker // This is a `d1` glyph (shaded with the current fill)
810*c8dee2aaSAndroid Build Coastguard Worker const SkGlyph* smallGlyph = smallGlyphs.glyph(SkPackedGlyphID{gID});
811*c8dee2aaSAndroid Build Coastguard Worker SkRect smallBBox = smallGlyph->rect();
812*c8dee2aaSAndroid Build Coastguard Worker SkIRect smallIBox;
813*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::Scale(bitmapScale, bitmapScale).mapRect(smallBBox).roundOut(&smallIBox);
814*c8dee2aaSAndroid Build Coastguard Worker bbox.join(smallIBox);
815*c8dee2aaSAndroid Build Coastguard Worker setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), smallIBox, &content);
816*c8dee2aaSAndroid Build Coastguard Worker
817*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(bitmapScale, &content);
818*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" 0 0 ");
819*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(bitmapScale, &content);
820*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" ");
821*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
822*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" ");
823*c8dee2aaSAndroid Build Coastguard Worker AppendScalar(pimg.fOffset.y() * bitmapScale, &content);
824*c8dee2aaSAndroid Build Coastguard Worker content.writeText(" cm\n");
825*c8dee2aaSAndroid Build Coastguard Worker
826*c8dee2aaSAndroid Build Coastguard Worker // Convert Gray image to jpeg if needed
827*c8dee2aaSAndroid Build Coastguard Worker if (pdfStrike.fHasMaskFilter) {
828*c8dee2aaSAndroid Build Coastguard Worker SkJpegEncoder::Options jpegOptions;
829*c8dee2aaSAndroid Build Coastguard Worker jpegOptions.fQuality = 50; // SK_PDF_MASK_QUALITY
830*c8dee2aaSAndroid Build Coastguard Worker SkImage* image = pimg.fImage.get();
831*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> jpegData = SkJpegEncoder::Encode(nullptr, image, jpegOptions);
832*c8dee2aaSAndroid Build Coastguard Worker if (jpegData) {
833*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> jpegImage = SkImages::DeferredFromEncodedData(jpegData);
834*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(jpegImage);
835*c8dee2aaSAndroid Build Coastguard Worker if (jpegImage) {
836*c8dee2aaSAndroid Build Coastguard Worker pimg.fImage = jpegImage;
837*c8dee2aaSAndroid Build Coastguard Worker }
838*c8dee2aaSAndroid Build Coastguard Worker }
839*c8dee2aaSAndroid Build Coastguard Worker }
840*c8dee2aaSAndroid Build Coastguard Worker
841*c8dee2aaSAndroid Build Coastguard Worker // Draw image into a Form XObject
842*c8dee2aaSAndroid Build Coastguard Worker const SkISize imageSize = pimg.fImage->dimensions();
843*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPDFDevice> glyphDevice = sk_sp(new SkPDFDevice(imageSize, doc));
844*c8dee2aaSAndroid Build Coastguard Worker SkCanvas canvas(glyphDevice);
845*c8dee2aaSAndroid Build Coastguard Worker canvas.drawImage(pimg.fImage, 0, 0);
846*c8dee2aaSAndroid Build Coastguard Worker SkPDFIndirectReference sMask = SkPDFMakeFormXObject(
847*c8dee2aaSAndroid Build Coastguard Worker doc, glyphDevice->content(),
848*c8dee2aaSAndroid Build Coastguard Worker SkPDFMakeArray(0, 0, pimg.fImage->width(), pimg.fImage->height()),
849*c8dee2aaSAndroid Build Coastguard Worker glyphDevice->makeResourceDict(),
850*c8dee2aaSAndroid Build Coastguard Worker SkMatrix(), "DeviceGray");
851*c8dee2aaSAndroid Build Coastguard Worker
852*c8dee2aaSAndroid Build Coastguard Worker // Use Form XObject as SMask (luminosity) on the graphics state
853*c8dee2aaSAndroid Build Coastguard Worker SkPDFIndirectReference smaskGraphicState = SkPDFGraphicState::GetSMaskGraphicState(
854*c8dee2aaSAndroid Build Coastguard Worker sMask, false,
855*c8dee2aaSAndroid Build Coastguard Worker SkPDFGraphicState::kLuminosity_SMaskMode, doc);
856*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::ApplyGraphicState(smaskGraphicState.fValue, &content);
857*c8dee2aaSAndroid Build Coastguard Worker
858*c8dee2aaSAndroid Build Coastguard Worker // Draw a rectangle the size of the glyph (masked by SMask)
859*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::AppendRectangle(SkRect::Make(pimg.fImage->bounds()), &content);
860*c8dee2aaSAndroid Build Coastguard Worker SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPathFillType::kWinding, &content);
861*c8dee2aaSAndroid Build Coastguard Worker
862*c8dee2aaSAndroid Build Coastguard Worker // Add glyph resources to font resource dict
863*c8dee2aaSAndroid Build Coastguard Worker xobjects->insertRef(SkStringPrintf("Xg%X", gID), sMask);
864*c8dee2aaSAndroid Build Coastguard Worker // TODO: name must match ApplyGraphicState
865*c8dee2aaSAndroid Build Coastguard Worker graphicStates->insertRef(SkStringPrintf("G%d", smaskGraphicState.fValue),
866*c8dee2aaSAndroid Build Coastguard Worker smaskGraphicState);
867*c8dee2aaSAndroid Build Coastguard Worker }
868*c8dee2aaSAndroid Build Coastguard Worker } else {
869*c8dee2aaSAndroid Build Coastguard Worker setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
870*c8dee2aaSAndroid Build Coastguard Worker }
871*c8dee2aaSAndroid Build Coastguard Worker charProcs->insertRef(std::move(characterName),
872*c8dee2aaSAndroid Build Coastguard Worker SkPDFStreamOut(nullptr, content.detachAsStream(), doc));
873*c8dee2aaSAndroid Build Coastguard Worker }
874*c8dee2aaSAndroid Build Coastguard Worker
875*c8dee2aaSAndroid Build Coastguard Worker if (xobjects->size() || graphicStates->size()) {
876*c8dee2aaSAndroid Build Coastguard Worker auto resources = SkPDFMakeDict();
877*c8dee2aaSAndroid Build Coastguard Worker if (xobjects->size()) {
878*c8dee2aaSAndroid Build Coastguard Worker resources->insertObject("XObject", std::move(xobjects));
879*c8dee2aaSAndroid Build Coastguard Worker }
880*c8dee2aaSAndroid Build Coastguard Worker if (graphicStates->size()) {
881*c8dee2aaSAndroid Build Coastguard Worker resources->insertObject("ExtGState", std::move(graphicStates));
882*c8dee2aaSAndroid Build Coastguard Worker }
883*c8dee2aaSAndroid Build Coastguard Worker font.insertObject("Resources", std::move(resources));
884*c8dee2aaSAndroid Build Coastguard Worker }
885*c8dee2aaSAndroid Build Coastguard Worker
886*c8dee2aaSAndroid Build Coastguard Worker encoding->insertObject("Differences", std::move(encDiffs));
887*c8dee2aaSAndroid Build Coastguard Worker font.insertInt("FirstChar", 0);
888*c8dee2aaSAndroid Build Coastguard Worker font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
889*c8dee2aaSAndroid Build Coastguard Worker /* FontBBox: "A rectangle expressed in the glyph coordinate
890*c8dee2aaSAndroid Build Coastguard Worker system, specifying the font bounding box. This is the smallest
891*c8dee2aaSAndroid Build Coastguard Worker rectangle enclosing the shape that would result if all of the
892*c8dee2aaSAndroid Build Coastguard Worker glyphs of the font were placed with their origins coincident and
893*c8dee2aaSAndroid Build Coastguard Worker then filled." */
894*c8dee2aaSAndroid Build Coastguard Worker font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
895*c8dee2aaSAndroid Build Coastguard Worker bbox.bottom(),
896*c8dee2aaSAndroid Build Coastguard Worker bbox.right(),
897*c8dee2aaSAndroid Build Coastguard Worker bbox.top()));
898*c8dee2aaSAndroid Build Coastguard Worker
899*c8dee2aaSAndroid Build Coastguard Worker font.insertName("CIDToGIDMap", "Identity");
900*c8dee2aaSAndroid Build Coastguard Worker
901*c8dee2aaSAndroid Build Coastguard Worker const SkTypeface& pathTypeface = pdfStrike.fPath.fStrikeSpec.typeface();
902*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(pathTypeface, doc);
903*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(glyphToUnicode.size() == SkToSizeT(pathTypeface.countGlyphs()));
904*c8dee2aaSAndroid Build Coastguard Worker auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
905*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::GetUnicodeMapEx(pathTypeface, doc),
906*c8dee2aaSAndroid Build Coastguard Worker &subset,
907*c8dee2aaSAndroid Build Coastguard Worker false,
908*c8dee2aaSAndroid Build Coastguard Worker firstGlyphID,
909*c8dee2aaSAndroid Build Coastguard Worker lastGlyphID);
910*c8dee2aaSAndroid Build Coastguard Worker font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
911*c8dee2aaSAndroid Build Coastguard Worker font.insertRef("FontDescriptor", type3_descriptor(doc, pathTypeface, xHeight));
912*c8dee2aaSAndroid Build Coastguard Worker font.insertObject("Widths", std::move(widthArray));
913*c8dee2aaSAndroid Build Coastguard Worker font.insertObject("Encoding", std::move(encoding));
914*c8dee2aaSAndroid Build Coastguard Worker font.insertObject("CharProcs", std::move(charProcs));
915*c8dee2aaSAndroid Build Coastguard Worker
916*c8dee2aaSAndroid Build Coastguard Worker doc->emit(font, pdfFont.indirectReference());
917*c8dee2aaSAndroid Build Coastguard Worker }
918*c8dee2aaSAndroid Build Coastguard Worker
emitSubset(SkPDFDocument * doc) const919*c8dee2aaSAndroid Build Coastguard Worker void SkPDFFont::emitSubset(SkPDFDocument* doc) const {
920*c8dee2aaSAndroid Build Coastguard Worker switch (fFontType) {
921*c8dee2aaSAndroid Build Coastguard Worker case SkAdvancedTypefaceMetrics::kType1CID_Font:
922*c8dee2aaSAndroid Build Coastguard Worker case SkAdvancedTypefaceMetrics::kTrueType_Font:
923*c8dee2aaSAndroid Build Coastguard Worker return emit_subset_type0(*this, doc);
924*c8dee2aaSAndroid Build Coastguard Worker #ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
925*c8dee2aaSAndroid Build Coastguard Worker case SkAdvancedTypefaceMetrics::kType1_Font:
926*c8dee2aaSAndroid Build Coastguard Worker return SkPDFEmitType1Font(*this, doc);
927*c8dee2aaSAndroid Build Coastguard Worker #endif
928*c8dee2aaSAndroid Build Coastguard Worker default:
929*c8dee2aaSAndroid Build Coastguard Worker return emit_subset_type3(*this, doc);
930*c8dee2aaSAndroid Build Coastguard Worker }
931*c8dee2aaSAndroid Build Coastguard Worker }
932*c8dee2aaSAndroid Build Coastguard Worker
933*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
934*c8dee2aaSAndroid Build Coastguard Worker
CanEmbedTypeface(const SkTypeface & typeface,SkPDFDocument * doc)935*c8dee2aaSAndroid Build Coastguard Worker bool SkPDFFont::CanEmbedTypeface(const SkTypeface& typeface, SkPDFDocument* doc) {
936*c8dee2aaSAndroid Build Coastguard Worker const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc);
937*c8dee2aaSAndroid Build Coastguard Worker return metrics && can_embed(*metrics);
938*c8dee2aaSAndroid Build Coastguard Worker }
939*c8dee2aaSAndroid Build Coastguard Worker
940