49#include <initializer_list>
61static const int32_t kPdfSymbolic = 4;
66 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
69inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
116 if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
121 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics =
typeface->getAdvancedMetrics();
123 metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
126 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
131 if (0 == metrics->fStemV) {
134 int16_t stemV = SHRT_MAX;
135 for (
char c : {
'i',
'I',
'!',
'1'}) {
136 uint16_t g = font.unicharToGlyph(c);
138 font.getBounds(&g, 1, &bounds,
nullptr);
141 metrics->fStemV = stemV;
143 if (0 == metrics->fCapHeight) {
146 for (
char c : {
'M',
'X'}) {
147 uint16_t g = font.unicharToGlyph(c);
149 font.getBounds(&g, 1, &bounds,
nullptr);
150 capHeight += bounds.height();
191 return metrics.
fType;
195 return gid != 0 ? gid - (gid - 1) % 255 : 1;
214 uint64_t typefaceID = (
static_cast<uint64_t
>(face->
uniqueID()) << 16) | subsetCode;
217 SkASSERT(multibyte == found->multiByteGlyphs());
231 firstNonZeroGlyph = 1;
233 firstNonZeroGlyph = subsetCode;
234 lastGlyph =
SkToU16(std::min<int>((
int)lastGlyph, 254 + (
int)subsetCode));
246 : fTypeface(
std::move(typeface))
247 , fGlyphUsage(firstGlyphID, lastGlyphID)
248 , fIndirectReference(indirectReference)
249 , fFontType(fontType)
258 int16_t defaultWidth) {
260 descriptor->
insertInt(
"Flags", (
size_t)(metrics.
fStyle | kPdfSymbolic));
262 scaleFromFontUnits(metrics.
fAscent, emSize));
264 scaleFromFontUnits(metrics.
fDescent, emSize));
266 scaleFromFontUnits(metrics.
fStemV, emSize));
268 scaleFromFontUnits(metrics.
fCapHeight, emSize));
272 scaleFromFontUnits(metrics.
fBBox.
bottom(), emSize),
273 scaleFromFontUnits(metrics.
fBBox.
right(), emSize),
274 scaleFromFontUnits(metrics.
fBBox.
top(), emSize)));
275 if (defaultWidth > 0) {
277 scaleFromFontUnits(defaultWidth, emSize));
288 (void)stream->rewind();
290 size_t size = stream->getLength();
291 if (
const void*
base = stream->getMemoryBase()) {
303 if (!metricsPtr) {
return; }
311 uint16_t emSize =
SkToU16(font.typeface()->getUnitsPerEm());
315 std::unique_ptr<SkStreamAsset> fontAsset = face->
openStream(&ttcIndex);
316 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
318 SkDebugf(
"Error: (SkTypeface)(%p)::openStream() returned "
319 "empty stream (%p) when identified as kType1CID_Font "
320 "or kTrueType_Font.\n", face, fontAsset.get());
332 if (subsetFontData) {
334 tmp->insertInt(
"Length1",
SkToInt(subsetFontData->size()));
335 descriptor->insertRef(
345 SkASSERT(fontAsset->getLength() == fontSize);
346 if (!fontAsset || fontAsset->getLength() == 0) {
break; }
349 tmp->insertInt(
"Length1", fontSize);
350 descriptor->insertRef(
"FontFile2",
357 tmp->insertName(
"Subtype",
"CIDFontType0C");
358 descriptor->insertRef(
"FontFile3",
369 newCIDFont->insertRef(
"FontDescriptor", doc->
emit(*descriptor));
374 newCIDFont->insertName(
"Subtype",
"CIDFontType0");
378 newCIDFont->insertName(
"Subtype",
"CIDFontType2");
379 newCIDFont->insertName(
"CIDToGIDMap",
"Identity");
386 sysInfo->insertByteString(
"Registry",
"Adobe");
387 sysInfo->insertByteString(
"Ordering",
"Identity");
388 sysInfo->insertInt(
"Supplement", 0);
389 newCIDFont->insertObject(
"CIDSystemInfo", std::move(sysInfo));
392 int32_t defaultWidth = 0;
395 *face, font.glyphUsage(), &defaultWidth);
397 newCIDFont->insertObject(
"W", std::move(
widths));
399 newCIDFont->insertInt(
"DW", defaultWidth);
407 fontDict.
insertName(
"Encoding",
"Identity-H");
409 descendantFonts->appendRef(doc->
emit(*newCIDFont));
410 fontDict.
insertObject(
"DescendantFonts", std::move(descendantFonts));
412 const std::vector<SkUnichar>& glyphToUnicode =
415 std::unique_ptr<SkStreamAsset> toUnicode =
418 font.multiByteGlyphs(),
423 doc->
emit(fontDict, font.indirectReference());
432struct SingleByteGlyphIdIterator {
434 : fFirst(first), fLast(last) {
440 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
445 return fCurrent != rhs.fCurrent;
447 Iter(
SkGlyphID f,
int c) : fFirst(
f), fCurrent(c) {}
452 Iter
begin()
const {
return Iter(fFirst, 0); }
453 Iter
end()
const {
return Iter(fFirst, (
int)fLast + 1); }
468 return {
nullptr, {0, 0}};
476 for (
int x8 = 0; x8 < bm.
width(); x8 += 8) {
477 uint8_t v = *mask.
getAddr1(x8 + bounds.x(),
y + bounds.y());
478 int e = std::min(x8 + 8, bm.
width());
479 for (
int x = x8;
x < e; ++
x) {
480 *bm.
getAddr8(
x,
y) = (v >> (
x & 0x7)) & 0x1 ? 0xFF : 0x00;
485 return {bm.
asImage(), {bounds.x(), bounds.y()}};
491 {bounds.x(), bounds.y()}};
497 {bounds.x(), bounds.y()}};
502 return {
nullptr, {0, 0}};
514 int32_t fontDescriptorFlags = kPdfSymbolic;
524 static constexpr const char* stretchNames[9] = {
535 const char* stretchName = stretchNames[typeface->
fontStyle().
width() - 1];
536 descriptor.
insertName(
"FontStretch", stretchName);
544 descriptor.
insertName(
"FontName", metrics->fPostScriptName);
545 descriptor.
insertInt(
"ItalicAngle", metrics->fItalicAngle);
546 fontDescriptorFlags |= (int32_t)metrics->fStyle;
549 if (metrics->fCapHeight != 0) { descriptor.
insertInt(
"CapHeight", metrics->fCapHeight); }
550 if (metrics->fStemV != 0) { descriptor.
insertInt(
"StemV", metrics->fStemV); }
555 descriptor.
insertInt(
"Flags", fontDescriptorFlags);
561#ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
562static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
583 SkASSERT(lastGlyphID >= firstGlyphID);
586 while (lastGlyphID > firstGlyphID && !subset.
has(lastGlyphID)) {
594 SkScalar xHeight = strike->getFontMetrics().fXHeight;
605 font.insertName(
"Subtype",
"Type3");
618 SkASSERT(lastGlyphID >= firstGlyphID);
619 int glyphCount = lastGlyphID - firstGlyphID + 2;
621 encDiffs->reserve(glyphCount + 1);
622 encDiffs->appendInt(0);
625 widthArray->reserve(glyphCount);
629 std::vector<std::pair<SkGlyphID, SkPDFIndirectReference>> imageGlyphs;
630 for (
SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
631 bool skipGlyph = gID != 0 && !subset.
has(gID);
636 characterName.
set(
"g0");
638 characterName.
printf(
"g%X", gID);
640 const SkGlyph* drawableGlyph = metricsAndDrawables.
glyph(gID);
642 glyphBBox = pathGlyph->
iRect();
643 bbox.
join(glyphBBox);
653 doc, glyphDevice->content(),
655 glyphDevice->makeResourceDict(),
657 imageGlyphs.emplace_back(gID, xobject);
659 content.writeText(
" 0 d0\n1 0 0 1 0 0 cm\n/X");
662 }
else if (path && !path->isEmpty()) {
663 setGlyphWidthAndBoundingBox(pathGlyph->
advanceX(), glyphBBox, &
content);
667 auto pimg =
to_image(gID, &smallGlyphs);
669 setGlyphWidthAndBoundingBox(pathGlyph->
advanceX(), glyphBBox, &
content);
675 AppendScalar(pimg.fImage->width() * bitmapScale, &
content);
677 AppendScalar(-pimg.fImage->height() * bitmapScale, &
content);
679 AppendScalar(pimg.fOffset.x() * bitmapScale, &
content);
681 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,
689 content.detachAsStream(), doc));
691 encDiffs->appendName(std::move(characterName));
692 widthArray->appendScalar(advance);
695 if (!imageGlyphs.empty()) {
697 for (
const auto& pair : imageGlyphs) {
701 d1->insertObject(
"XObject", std::move(d0));
702 font.insertObject(
"Resources", std::move(d1));
705 encoding->insertObject(
"Differences", std::move(encDiffs));
706 font.insertInt(
"FirstChar", 0);
707 font.insertInt(
"LastChar", lastGlyphID - firstGlyphID + 1);
718 font.insertName(
"CIDToGIDMap",
"Identity");
727 font.insertRef(
"ToUnicode",
SkPDFStreamOut(
nullptr, std::move(toUnicodeCmap), doc));
729 font.insertObject(
"Widths", std::move(widthArray));
730 font.insertObject(
"Encoding", std::move(encoding));
731 font.insertObject(
"CharProcs", std::move(charProcs));
742#ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
@ kNone
glyph outlines unchanged
SkPDFIndirectReference SkPDFSerializeImage(const SkImage *img, SkPDFDocument *doc, int encodingQuality)
static SkSize operator*(SkISize u, SkScalar s)
SkStrikeSpec make_small_strike(const SkTypeface &typeface)
static SkPDFIndirectReference type3_descriptor(SkPDFDocument *doc, const SkTypeface *typeface, SkScalar xHeight)
static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages *smallGlyphs)
static void emit_subset_type3(const SkPDFFont &pdfFont, SkPDFDocument *doc)
static void emit_subset_type0(const SkPDFFont &font, SkPDFDocument *doc)
static constexpr float kBitmapFontSize
static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)
static bool can_embed(const SkAdvancedTypefaceMetrics &metrics)
static sk_sp< SkData > stream_to_data(std::unique_ptr< SkStreamAsset > stream)
std::unique_ptr< SkPDFArray > SkPDFMakeCIDGlyphWidthsArray(const SkTypeface &typeface, const SkPDFGlyphUse &subset, int32_t *defaultAdvance)
std::unique_ptr< SkStreamAsset > SkPDFMakeToUnicodeCmap(const SkUnichar *glyphToUnicode, const SkPDFGlyphUse *subset, bool multiByteGlyphs, SkGlyphID firstGlyphID, SkGlyphID lastGlyphID)
sk_sp< SkData > SkPDFSubsetFont(sk_sp< SkData >, const SkPDFGlyphUse &, SkPDF::Metadata::Subsetter, int)
void SkPDFEmitType1Font(const SkPDFFont &pdfFont, SkPDFDocument *doc)
static SkScalar from_font_units(SkScalar scaled, uint16_t emSize)
SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr< SkPDFDict > dict, std::unique_ptr< SkStreamAsset > content, SkPDFDocument *doc, SkPDFSteamCompressionEnabled compress)
static std::unique_ptr< SkPDFDict > SkPDFMakeDict(const char *type=nullptr)
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
bool operator!=(const sk_sp< T > &a, const sk_sp< U > &b)
sk_sp< T > sk_ref_sp(T *obj)
#define SkScalarInvert(x)
#define SkScalarRoundToInt(x)
@ kFakeGammaAndBoostContrast
SK_API SkString static SkString SkStringPrintf()
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
constexpr size_t SkToSizeT(S x)
constexpr uint16_t SkToU16(S x)
constexpr int SkToInt(S x)
static constexpr bool SkToBool(const T &x)
constexpr int16_t SkToS16(S x)
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
sk_sp< SkImage > asImage() const
uint8_t * getAddr8(int x, int y) const
const SkGlyph * glyph(SkGlyphID glyphID)
const SkGlyph * glyph(SkPackedGlyphID packedID)
const SkGlyph * glyph(SkGlyphID glyphID)
void translate(SkScalar dx, SkScalar dy)
void drawDrawable(SkDrawable *drawable, const SkMatrix *matrix=nullptr)
void(* ReleaseProc)(const void *ptr, void *context)
static sk_sp< SkData > MakeWithProc(const void *ptr, size_t length, ReleaseProc proc, void *ctx)
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
@ kAlias
no transparent pixels on glyph edges
SkGlyphID getGlyphID() const
const SkPath * path() const
SkScalar advanceX() const
SkDrawable * drawable() const
static SkMatrix Translate(SkScalar dx, SkScalar dy)
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
static const SkMatrix & I()
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
void insertName(const char key[], const char nameValue[])
void insertObject(const char key[], std::unique_ptr< SkPDFObject > &&)
void insertInt(const char key[], int32_t value)
void insertRef(const char key[], SkPDFIndirectReference)
void insertScalar(const char key[], SkScalar value)
void insertByteString(const char key[], const char value[])
SkPDFIndirectReference emit(const SkPDFObject &, SkPDFIndirectReference)
const SkPDF::Metadata & metadata() const
skia_private::THashMap< uint64_t, SkPDFFont > fFontMap
skia_private::THashMap< uint32_t, std::vector< SkUnichar > > fToUnicodeMap
SkString nextFontSubsetTag()
skia_private::THashMap< uint32_t, SkPDFIndirectReference > fType3FontDescriptors
SkPDFIndirectReference reserveRef()
skia_private::THashMap< uint32_t, std::unique_ptr< SkAdvancedTypefaceMetrics > > fTypefaceMetrics
void noteGlyphUsage(SkGlyphID glyph)
static const SkAdvancedTypefaceMetrics * GetMetrics(const SkTypeface *typeface, SkPDFDocument *canon)
static void PopulateCommonFontDescriptor(SkPDFDict *descriptor, const SkAdvancedTypefaceMetrics &, uint16_t emSize, int16_t defaultWidth)
static SkPDFFont * GetFontResource(SkPDFDocument *doc, const SkGlyph *glyphs, SkTypeface *typeface)
SkPDFIndirectReference indirectReference() const
static SkAdvancedTypefaceMetrics::FontType FontType(const SkTypeface &, const SkAdvancedTypefaceMetrics &)
static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type)
static const std::vector< SkUnichar > & GetUnicodeMap(const SkTypeface *typeface, SkPDFDocument *canon)
SkPDFFont & operator=(SkPDFFont &&)
SkGlyphID lastGlyphID() const
SkGlyphID firstGlyphID() const
void emitSubset(SkPDFDocument *) const
const SkPDFGlyphUse & glyphUsage() const
static void GetType1GlyphNames(const SkTypeface &, SkString *)
SkTypeface * typeface() const
static bool CanEmbedTypeface(SkTypeface *, SkPDFDocument *)
bool has(SkGlyphID gid) const
@ kFill_Style
set to fill geometry
static SkStrikeSpec MakeMask(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix)
sk_sp< SkStrike > findOrCreateStrike() const
static SkStrikeSpec MakePDFVector(const SkTypeface &typeface, int *size)
void printf(const char format[],...) SK_PRINTF_LIKE(2
void set(const SkString &src)
const char * c_str() const
virtual void getPostScriptGlyphNames(SkString *) const =0
SkTypefaceID uniqueID() const
virtual void getGlyphToUnicodeMap(SkUnichar *dstArray) const =0
void getFamilyName(SkString *name) const
SkFontStyle fontStyle() const
size_t getTableSize(SkFontTableTag) const
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
V * find(const K &key) const
static const char * begin(const StringSlice &s)
static const uint8_t buffer[]
union flutter::testing::@2838::KeyboardChange::@76 content
SK_API sk_sp< SkImage > RasterFromData(const SkImageInfo &info, sk_sp< SkData > pixels, size_t rowBytes)
std::unique_ptr< SkPDFArray > MatrixToArray(const SkMatrix &matrix)
void EmitPath(const SkPath &path, SkPaint::Style paintStyle, bool doConsumeDegerates, SkWStream *content, SkScalar tolerance=0.25f)
void PaintPath(SkPaint::Style style, SkPathFillType fill, SkWStream *content)
void AppendScalar(SkScalar value, SkWStream *stream)
@ kNotEmbeddable_FontFlag
May not be embedded.
@ kAltDataFormat_FontFlag
Data compressed. Table access may still work.
@ kNotSubsettable_FontFlag
May not be subset.
@ kVariable_FontFlag
May be true for Type1, CFF, or TrueType fonts.
int32_t fBottom
larger y-axis bounds
constexpr int32_t top() const
constexpr SkISize size() const
constexpr int32_t bottom() const
constexpr int32_t height() const
constexpr int32_t right() const
int32_t fTop
smaller y-axis bounds
void join(const SkIRect &r)
static constexpr SkIRect MakeEmpty()
constexpr int32_t width() const
int32_t fLeft
smaller x-axis bounds
constexpr int32_t left() const
int32_t fRight
larger x-axis bounds
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo MakeA8(int width, int height)
@ k3D_Format
3 8bit per pixl planes: alpha, mul, add
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
@ kLCD16_Format
565 alpha for r/g/b
@ kARGB32_Format
SkPMColor.
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
const uint8_t * getAddr1(int x, int y) const
uint8_t const *const fImage
size_t computeTotalImageSize() const