aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2015-10-12 13:05:04 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-12 13:05:04 -0700
commit66a82f3872abf4ebb98b3915b2a9ecc73ad352c5 (patch)
treee8bafe893fcce8e95d9d8b20f0c7f12d80ea8e0e /src/pdf
parent88d064d0e481949184305c7b1d6b282dddffac39 (diff)
SkPDF: fall back on paths for unembeddable fonts.
Add GM, SkPDFFont::CanEmbedTypeface BUG=skia:3866 Review URL: https://codereview.chromium.org/1401763002
Diffstat (limited to 'src/pdf')
-rw-r--r--src/pdf/SkPDFCanon.h2
-rw-r--r--src/pdf/SkPDFDevice.cpp72
-rw-r--r--src/pdf/SkPDFDevice.h2
-rw-r--r--src/pdf/SkPDFFont.cpp37
-rw-r--r--src/pdf/SkPDFFont.h6
5 files changed, 106 insertions, 13 deletions
diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h
index a55024d611..988b2855e1 100644
--- a/src/pdf/SkPDFCanon.h
+++ b/src/pdf/SkPDFCanon.h
@@ -78,6 +78,8 @@ public:
void addPDFBitmap(uint32_t imageUniqueID, SkPDFObject*);
const SkImage* bitmapToImage(const SkBitmap&);
+ SkTHashMap<uint32_t, bool> fCanEmbedTypeface;
+
private:
struct FontRec {
SkPDFFont* fFont;
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 9134d802ff..c27cc64bfb 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1231,8 +1231,57 @@ static SkString format_wide_string(const uint16_t* input,
}
}
+static void draw_transparent_text(SkPDFDevice* device,
+ const SkDraw& d,
+ const void* text, size_t len,
+ SkScalar x, SkScalar y,
+ const SkPaint& srcPaint) {
+
+ SkPaint transparent;
+ if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(),
+ device->getCanon())) {
+ SkDEBUGFAIL("default typeface should be embeddable");
+ return; // Avoid infinite loop in release.
+ }
+ transparent.setTextSize(srcPaint.getTextSize());
+ transparent.setColor(SK_ColorTRANSPARENT);
+ switch (srcPaint.getTextEncoding()) {
+ case SkPaint::kGlyphID_TextEncoding: {
+ // Since a glyphId<->Unicode mapping is typeface-specific,
+ // map back to Unicode first.
+ size_t glyphCount = len / 2;
+ SkAutoTMalloc<SkUnichar> unichars(glyphCount);
+ srcPaint.glyphsToUnichars(
+ (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]);
+ transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding);
+ device->drawText(d, &unichars[0],
+ glyphCount * sizeof(SkUnichar),
+ x, y, transparent);
+ break;
+ }
+ case SkPaint::kUTF8_TextEncoding:
+ case SkPaint::kUTF16_TextEncoding:
+ case SkPaint::kUTF32_TextEncoding:
+ transparent.setTextEncoding(srcPaint.getTextEncoding());
+ device->drawText(d, text, len, x, y, transparent);
+ break;
+ default:
+ SkFAIL("unknown text encoding");
+ }
+}
+
+
void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& srcPaint) {
+ if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) {
+ // http://skbug.com/3866
+ SkPath path;
+ srcPaint.getTextPath(text, len, x, y, &path);
+ this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
+ // Draw text transparently to make it copyable/searchable/accessable.
+ draw_transparent_text(this, d, text, len, x, y, srcPaint);
+ return;
+ }
SkPaint paint = srcPaint;
replace_srcmode_on_opaque_paint(&paint);
@@ -1285,6 +1334,29 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
const SkScalar pos[], int scalarsPerPos,
const SkPoint& offset, const SkPaint& srcPaint) {
+ if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) {
+ const SkPoint* positions = reinterpret_cast<const SkPoint*>(pos);
+ SkAutoTMalloc<SkPoint> positionsBuffer;
+ if (2 != scalarsPerPos) {
+ int glyphCount = srcPaint.textToGlyphs(text, len, NULL);
+ positionsBuffer.reset(glyphCount);
+ for (int i = 0; i < glyphCount; ++i) {
+ positionsBuffer[i].set(pos[i], 0.0f);
+ }
+ positions = &positionsBuffer[0];
+ }
+ SkPath path;
+ srcPaint.getPosTextPath(text, len, positions, &path);
+ SkMatrix matrix;
+ matrix.setTranslate(offset);
+ this->drawPath(d, path, srcPaint, &matrix, true);
+ // Draw text transparently to make it copyable/searchable/accessable.
+ draw_transparent_text(
+ this, d, text, len, offset.x() + positions[0].x(),
+ offset.y() + positions[0].y(), srcPaint);
+ return;
+ }
+
SkPaint paint = srcPaint;
replace_srcmode_on_opaque_paint(&paint);
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 75447f9be2..742e45ca5c 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -189,9 +189,7 @@ public:
return *(fFontGlyphUsage.get());
}
-#ifdef SK_DEBUG
SkPDFCanon* getCanon() const { return fCanon; }
-#endif // SK_DEBUG
protected:
const SkBitmap& onAccessBitmap() override {
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 8df59b77f1..9cbada8364 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -1051,10 +1051,7 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
this->insertObjRef("FontDescriptor", descriptor.detach());
return false;
}
- if (!canEmbed()) {
- this->insertObjRef("FontDescriptor", descriptor.detach());
- return true;
- }
+ SkASSERT(this->canEmbed());
switch (getType()) {
case SkAdvancedTypefaceMetrics::kTrueType_Font: {
@@ -1222,13 +1219,12 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
if (fontData.get() == nullptr) {
return false;
}
- if (canEmbed()) {
- SkAutoTUnref<SkPDFStream> fontStream(new SkPDFStream(fontData.get()));
- fontStream->insertInt("Length1", header);
- fontStream->insertInt("Length2", data);
- fontStream->insertInt("Length3", trailer);
- descriptor->insertObjRef("FontFile", fontStream.detach());
- }
+ SkASSERT(this->canEmbed());
+ SkAutoTUnref<SkPDFStream> fontStream(new SkPDFStream(fontData.get()));
+ fontStream->insertInt("Length1", header);
+ fontStream->insertInt("Length2", data);
+ fontStream->insertInt("Length3", trailer);
+ descriptor->insertObjRef("FontFile", fontStream.detach());
this->insertObjRef("FontDescriptor", descriptor.detach());
@@ -1418,3 +1414,22 @@ SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont,
return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match
: SkPDFFont::kRelated_Match;
}
+
+// Since getAdvancedTypefaceMetrics is expensive, cache the result.
+bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
+ SkAutoResolveDefaultTypeface face(typeface);
+ uint32_t id = face->uniqueID();
+ if (bool* value = canon->fCanEmbedTypeface.find(id)) {
+ return *value;
+ }
+ bool canEmbed = true;
+ SkAutoTUnref<const SkAdvancedTypefaceMetrics> fontMetrics(
+ face->getAdvancedTypefaceMetrics(
+ SkTypeface::kNo_PerGlyphInfo, nullptr, 0));
+ if (fontMetrics) {
+ canEmbed = !SkToBool(
+ fontMetrics->fFlags &
+ SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
+ }
+ return *canon->fCanEmbedTypeface.set(id, canEmbed);
+}
diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h
index 404e8b7621..ca0a51fca4 100644
--- a/src/pdf/SkPDFFont.h
+++ b/src/pdf/SkPDFFont.h
@@ -149,6 +149,12 @@ public:
uint32_t searchFontID,
uint16_t searchGlyphID);
+ /**
+ * Return false iff the typeface has its NotEmbeddable flag set.
+ * If typeface is NULL, the default typeface is checked.
+ */
+ static bool CanEmbedTypeface(SkTypeface*, SkPDFCanon*);
+
protected:
// Common constructor to handle common members.
SkPDFFont(const SkAdvancedTypefaceMetrics* fontInfo,