Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(608)

Unified Diff: src/pdf/SkPDFDevice.cpp

Issue 24364008: Update PDF backend to support fallback fonts on Android. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/pdf/SkPDFDevice.cpp
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index d13d30cbfb46efbbbe29f6bc3f22522190af75de..c4a35854b7b1616cbd38cbfb0b963cfd93367a6e 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -33,6 +33,15 @@
#include "SkTypefacePriv.h"
#include "SkTSet.h"
+#ifdef SK_BUILD_FOR_ANDROID
+#include "SkTypeface_android.h"
+
+struct TypefaceData {
+ int lowerBounds;
+ int upperBounds;
+};
+#endif
+
// Utility functions
static void emit_pdf_color(SkColor color, SkWStream* result) {
@@ -1115,6 +1124,128 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
return;
}
+#ifdef SK_BUILD_FOR_ANDROID
+ /*
+ * In the case that we have enabled fallback fonts on Android we need to
+ * take the following steps to ensure that the PDF draws all characters,
+ * regardless of their underlying font file, correctly.
+ *
+ * 1. Convert input into GlyphID encoding if it currently is not
+ * 2. Iterate over the glyphIDs and identify the actual typeface that each
+ * glyph resolves to
+ * 3. Iterate over those typefaces and recursively call this function with
+ * only the glyphs (and their positions) that the typeface is capable of
+ * resolving.
+ */
+ if (paint.getPaintOptionsAndroid().isUsingFontFallbacks()) {
+ uint16_t* glyphIDs = NULL;
reed1 2013/09/24 20:10:19 can this guy be const?
+ SkGlyphStorage tmpStorage(0);
+ size_t numGlyphs = 0;
+
+ // convert to glyphIDs
+ if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
+ numGlyphs = paint.textToGlyphs(text, len, NULL);
+ tmpStorage.reset(numGlyphs);
+ paint.textToGlyphs(text, len, tmpStorage.get());
+ glyphIDs = tmpStorage.get();
+ } else {
+ numGlyphs = len / 2;
+ glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text)));
reed1 2013/09/24 20:10:19 nit: that's a lot (of) ((parens))
+ }
+
+ // if no typeface is provided in the paint get the default
+ SkAutoTUnref<SkTypeface> origFace(SkSafeRef(paint.getTypeface()));
+ if (!origFace.get()) {
+ origFace.reset(SkTypeface::RefDefault());
+ }
+ const uint16_t origGlyphCount = origFace->countGlyphs();
+
+ // keep a list of the already visited typefaces and some data about them
+ SkTDArray<SkTypeface*> visitedTypefaces;
+ SkTDArray<TypefaceData> typefaceData;
reed1 2013/09/24 20:10:19 Can these two arrays be folded into a single one,
+
+ // find all the typefaces needed to resolve this run of text
+ bool usesOriginalTypeface = false;
+ for (uint16_t x = 0; x < numGlyphs; ++x) {
+ // optimization that checks to see if original typeface can resolve the glyph
+ if (glyphIDs[x] < origGlyphCount) {
+ usesOriginalTypeface = true;
+ continue;
+ }
+
+ // find the fallback typeface that supports this glyph
+ int lBounds, uBounds;
+ SkTypeface* fallbackTypeface = SkGetTypefaceForGlyphID(glyphIDs[x],
+ origFace.get(),
+ paint.getPaintOptionsAndroid(),
+ &lBounds, &uBounds);
+ // if there is no valid typeface then we just skip the glyph
+ if (!fallbackTypeface) {
+ continue;
+ }
+
+ // check if we have already used this typeface
+ if (visitedTypefaces.contains(fallbackTypeface)) {
+ continue;
+ }
+
+ // add the typeface and its data if we don't have it
+ visitedTypefaces.push(fallbackTypeface);
+ TypefaceData* data = typefaceData.push();
+ data->lowerBounds = lBounds;
+ data->upperBounds = uBounds;
+ }
+
+ // if the original font was used then add it to the list as well
+ if (usesOriginalTypeface) {
reed1 2013/09/24 20:10:19 In this case, can't we just call through to the or
djsollen 2013/09/24 20:44:17 We need to make the copy for the case when we have
+ visitedTypefaces.push(SkSafeRef(origFace.get()));
reed1 2013/09/24 20:10:19 why do we need to ref() the typefaces?
+ TypefaceData* data = typefaceData.push();
+ data->lowerBounds = 0;
+ data->upperBounds = origGlyphCount;
+ }
+
+ // keep a scratch glyph and pos storage
+ SkAutoTMalloc<SkScalar> posStorage(len * scalarsPerPos);
+ SkScalar* tmpPos = posStorage.get();
+ SkGlyphStorage glyphStorage(numGlyphs);
+ uint16_t* tmpGlyphIDs = glyphStorage.get();
+
+ // loop through all the valid typefaces, trim the glyphs to only those
+ // resolved by the typeface, and then draw that run of glyphs
+ for (int x = 0; x < visitedTypefaces.count(); ++x) {
+ SkTypeface* typeface = visitedTypefaces[x];
+ const TypefaceData& data = typefaceData[x];
+
+ int tmpGlyphCount = 0;
+ for (uint16_t y = 0; y < numGlyphs; ++y) {
+ if (glyphIDs[y] >= data.lowerBounds && glyphIDs[y] < data.upperBounds) {
+ tmpGlyphIDs[tmpGlyphCount] = glyphIDs[y] - data.lowerBounds;
+ memcpy(&(tmpPos[tmpGlyphCount * scalarsPerPos]),
+ &(pos[y * scalarsPerPos]),
+ scalarsPerPos * sizeof(SkScalar));
+ tmpGlyphCount++;
+ }
+ }
+
+ // recursively call this function with the right typeface
+ SkPaint tmpPaint = paint;
+ tmpPaint.setTypeface(typeface);
+ tmpPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ // turn off fallback chaining
+ SkPaintOptionsAndroid paintOpts = tmpPaint.getPaintOptionsAndroid();
+ paintOpts.setUseFontFallbacks(false);
+ tmpPaint.setPaintOptionsAndroid(paintOpts);
+
+ this->drawPosText(d, tmpGlyphIDs, tmpGlyphCount * 2, tmpPos, constY,
+ scalarsPerPos, tmpPaint);
+ }
+
+ visitedTypefaces.safeUnrefAll();
+ return;
+ }
+#endif
+
SkGlyphStorage storage(0);
uint16_t* glyphIDs = NULL;
size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage,

Powered by Google App Engine
This is Rietveld 408576698