| Index: src/pdf/SkPDFDevice.cpp
|
| diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
|
| index d13d30cbfb46efbbbe29f6bc3f22522190af75de..e4b07f04fa794bcd27373564411445a039cd4afe 100644
|
| --- a/src/pdf/SkPDFDevice.cpp
|
| +++ b/src/pdf/SkPDFDevice.cpp
|
| @@ -33,6 +33,22 @@
|
| #include "SkTypefacePriv.h"
|
| #include "SkTSet.h"
|
|
|
| +#ifdef SK_BUILD_FOR_ANDROID
|
| +#include "SkTypeface_android.h"
|
| +
|
| +struct TypefaceFallbackData {
|
| + SkTypeface* typeface;
|
| + int lowerBounds;
|
| + int upperBounds;
|
| +
|
| + bool operator==(const TypefaceFallbackData& b) const {
|
| + return typeface == b.typeface &&
|
| + lowerBounds == b.lowerBounds &&
|
| + upperBounds == b.upperBounds;
|
| + }
|
| +};
|
| +#endif
|
| +
|
| // Utility functions
|
|
|
| static void emit_pdf_color(SkColor color, SkWStream* result) {
|
| @@ -1115,6 +1131,112 @@ 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;
|
| + SkGlyphStorage tmpStorage(0);
|
| + size_t numGlyphs = 0;
|
| +
|
| + // convert to glyphIDs
|
| + if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
|
| + numGlyphs = len / 2;
|
| + glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>(text));
|
| + } else {
|
| + numGlyphs = paint.textToGlyphs(text, len, NULL);
|
| + tmpStorage.reset(numGlyphs);
|
| + paint.textToGlyphs(text, len, tmpStorage.get());
|
| + glyphIDs = tmpStorage.get();
|
| + }
|
| +
|
| + // if no typeface is provided in the paint get the default
|
| + SkAutoTUnref<SkTypeface> origFace(SkSafeRef(paint.getTypeface()));
|
| + if (NULL == 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<TypefaceFallbackData> visitedTypefaces;
|
| +
|
| + // 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
|
| + TypefaceFallbackData data;
|
| + data.typeface = SkGetTypefaceForGlyphID(glyphIDs[x], origFace.get(),
|
| + paint.getPaintOptionsAndroid(),
|
| + &data.lowerBounds, &data.upperBounds);
|
| + // add the typeface and its data if we don't have it
|
| + if (data.typeface && !visitedTypefaces.contains(data)) {
|
| + visitedTypefaces.push(data);
|
| + }
|
| + }
|
| +
|
| + // if the original font was used then add it to the list as well
|
| + if (usesOriginalTypeface) {
|
| + TypefaceFallbackData* data = visitedTypefaces.push();
|
| + data->typeface = origFace.get();
|
| + 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) {
|
| + const TypefaceFallbackData& data = visitedTypefaces[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(data.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);
|
| + }
|
| + return;
|
| + }
|
| +#endif
|
| +
|
| SkGlyphStorage storage(0);
|
| uint16_t* glyphIDs = NULL;
|
| size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage,
|
|
|