Chromium Code Reviews| 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, |