[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
This commit is contained in:
parent
6d5d08f14f
commit
4e1cc6ac45
@ -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;
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,11 @@
|
||||
|
||||
|
||||
#include "Test.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkData.h"
|
||||
#include "SkFlate.h"
|
||||
#include "SkPDFCatalog.h"
|
||||
#include "SkPDFDevice.h"
|
||||
#include "SkPDFStream.h"
|
||||
#include "SkPDFTypes.h"
|
||||
#include "SkScalar.h"
|
||||
@ -217,6 +219,28 @@ static void TestSubstitute(skiatest::Reporter* reporter) {
|
||||
buffer.getOffset()));
|
||||
}
|
||||
|
||||
// This test used to assert without the fix submitted for
|
||||
// http://code.google.com/p/skia/issues/detail?id=1083.
|
||||
// SKP files might have invalid glyph ids. This test ensures they are ignored,
|
||||
// and there is no assert on input data in Debug mode.
|
||||
static void test_issue1083(skiatest::Reporter* reporter) {
|
||||
SkISize pageSize = SkISize::Make(100, 100);
|
||||
SkPDFDevice* dev = new SkPDFDevice(pageSize, pageSize, SkMatrix::I());
|
||||
|
||||
SkCanvas c(dev);
|
||||
SkPaint paint;
|
||||
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
|
||||
uint16_t glyphID = 65000;
|
||||
c.drawText(&glyphID, 2, 0, 0, paint);
|
||||
|
||||
SkPDFDocument doc;
|
||||
doc.appendPage(dev);
|
||||
|
||||
SkDynamicMemoryWStream stream;
|
||||
doc.emitPDF(&stream);
|
||||
}
|
||||
|
||||
static void TestPDFPrimitives(skiatest::Reporter* reporter) {
|
||||
SkAutoTUnref<SkPDFInt> int42(new SkPDFInt(42));
|
||||
SimpleCheckObjectOutput(reporter, int42.get(), "42");
|
||||
@ -298,6 +322,8 @@ static void TestPDFPrimitives(skiatest::Reporter* reporter) {
|
||||
TestObjectRef(reporter);
|
||||
|
||||
TestSubstitute(reporter);
|
||||
|
||||
test_issue1083(reporter);
|
||||
}
|
||||
|
||||
#include "TestClassDef.h"
|
||||
|
Loading…
Reference in New Issue
Block a user