diff options
author | 2013-01-25 19:27:23 +0000 | |
---|---|---|
committer | 2013-01-25 19:27:23 +0000 | |
commit | 4e1cc6ac450903510b96c1b12f6ee6f420044a66 (patch) | |
tree | 8a5160b6762816863800d0ae6ecf32dcba707719 /src/pdf | |
parent | 6d5d08f14f1907d516ee28656dfd9ca063e0f7fc (diff) |
[PDF] Handle invalid glyph IDs on drawText methods.
Review URL: https://codereview.appspot.com/7179053
git-svn-id: http://skia.googlecode.com/svn/trunk@7401 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pdf')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 106 |
1 files changed, 75 insertions, 31 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 63cc8c4ec9..e253a5fc35 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -14,6 +14,7 @@ #include "SkClipStack.h" #include "SkData.h" #include "SkDraw.h" +#include "SkFontHost.h" #include "SkGlyphCache.h" #include "SkPaint.h" #include "SkPath.h" @@ -28,6 +29,7 @@ #include "SkRect.h" #include "SkString.h" #include "SkTextFormatParams.h" +#include "SkTemplates.h" #include "SkTypeface.h" #include "SkTypes.h" @@ -102,6 +104,69 @@ static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint, *y = *y - yAdj; } +static size_t max_glyphid_for_typeface(const SkTypeface* typeface) { + SkAdvancedTypefaceMetrics* metrics; + metrics = SkFontHost::GetAdvancedTypefaceMetrics( + SkTypeface::UniqueID(typeface), + SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo, + NULL, 0); + + int lastGlyphID = 0; + if (metrics) { + lastGlyphID = metrics->fLastGlyphID; + metrics->unref(); + } + return lastGlyphID; +} + +typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage; + +static size_t force_glyph_encoding(const SkPaint& paint, const void* text, + size_t len, SkGlyphStorage* storage, + uint16_t** glyphIDs) { + // Make sure we have a glyph id encoding. + if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { + size_t numGlyphs = paint.textToGlyphs(text, len, NULL); + storage->reset(numGlyphs); + paint.textToGlyphs(text, len, storage->get()); + *glyphIDs = storage->get(); + return numGlyphs; + } + + // For user supplied glyph ids we need to validate them. + SkASSERT((len & 1) == 0); + size_t numGlyphs = len / 2; + const uint16_t* input = + reinterpret_cast<uint16_t*>(const_cast<void*>((text))); + + int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface()); + size_t validated; + for (validated = 0; validated < numGlyphs; ++validated) { + if (input[validated] > maxGlyphID) { + break; + } + } + if (validated >= numGlyphs) { + *glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text))); + return numGlyphs; + } + + // Silently drop anything out of range. + storage->reset(numGlyphs); + if (validated > 0) { + memcpy(storage->get(), input, validated * sizeof(uint16_t)); + } + + for (size_t i = validated; i < numGlyphs; ++i) { + storage->get()[i] = input[i]; + if (input[i] > maxGlyphID) { + storage->get()[i] = 0; + } + } + *glyphIDs = storage->get(); + return numGlyphs; +} + static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, SkWStream* content) { // Flip the text about the x-axis to account for origin swap and include @@ -816,20 +881,11 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, return; } - // We want the text in glyph id encoding and a writable buffer, so we end - // up making a copy either way. - size_t numGlyphs = paint.textToGlyphs(text, len, NULL); - uint16_t* glyphIDs = reinterpret_cast<uint16_t*>( - sk_malloc_flags(numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW)); - SkAutoFree autoFreeGlyphIDs(glyphIDs); - if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { - paint.textToGlyphs(text, len, glyphIDs); - textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - } else { - SkASSERT((len & 1) == 0); - SkASSERT(len / 2 == numGlyphs); - memcpy(glyphIDs, text, len); - } + SkGlyphStorage storage(0); + uint16_t* glyphIDs = NULL; + size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, + &glyphIDs); + textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); @@ -865,22 +921,11 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, return; } - // Make sure we have a glyph id encoding. - SkAutoFree glyphStorage; - uint16_t* glyphIDs; - size_t numGlyphs; - if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { - numGlyphs = paint.textToGlyphs(text, len, NULL); - glyphIDs = reinterpret_cast<uint16_t*>(sk_malloc_flags( - numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW)); - glyphStorage.set(glyphIDs); - paint.textToGlyphs(text, len, glyphIDs); - textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - } else { - SkASSERT((len & 1) == 0); - numGlyphs = len / 2; - glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text))); - } + SkGlyphStorage storage(0); + uint16_t* glyphIDs = NULL; + size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, + &glyphIDs); + textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); content.entry()->fContent.writeText("BT\n"); @@ -1615,4 +1660,3 @@ bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, bool SkPDFDevice::allowImageFilter(SkImageFilter*) { return false; } - |