From a76a10b730ae3fb2abb7c06839ca9c5d14df5ca7 Mon Sep 17 00:00:00 2001 From: halcanary Date: Thu, 7 Jul 2016 12:31:55 -0700 Subject: [PATCH] SkPDF: Fix encoding of unichr outside of basic plane In ToUnicode table, write unicode codepoints as one or two UTF16BE values, rather than a single hex, as the standard requires. Factor out uint16 -> big-endian hex code. SkUtils is now a namespace. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2120533002 Review-Url: https://codereview.chromium.org/2120533002 --- src/pdf/SkPDFDevice.cpp | 8 +--- src/pdf/SkPDFFont.cpp | 20 +++++++--- src/pdf/SkPDFUtils.h | 81 +++++++++++++++++++++++------------------ 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 12698dc00b..7c366cdae7 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -1063,15 +1063,9 @@ static void write_wide_string(SkDynamicMemoryWStream* wStream, bool wideChars) { if (wideChars) { SkASSERT(2 * len < 65535); - static const char gHex[] = "0123456789ABCDEF"; wStream->writeText("<"); for (size_t i = 0; i < len; i++) { - char result[4]; // Big-endian - result[0] = gHex[(input[i] >> 12) & 0xF]; - result[1] = gHex[(input[i] >> 8) & 0xF]; - result[2] = gHex[(input[i] >> 4) & 0xF]; - result[3] = gHex[(input[i]) & 0xF]; - wStream->write(result, 4); + SkPDFUtils::WriteUInt16BE(wStream, input[i]); } wStream->writeText(">"); } else { diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index 99b633508f..0fce0b98d6 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -421,6 +421,16 @@ struct BFRange { SkUnichar fUnicode; }; +static void write_utf16be(SkDynamicMemoryWStream* wStream, SkUnichar utf32) { + uint16_t utf16[2] = {0, 0}; + size_t len = SkUTF16_FromUnichar(utf32, utf16); + SkASSERT(len == 1 || len == 2); + SkPDFUtils::WriteUInt16BE(wStream, utf16[0]); + if (len == 2) { + SkPDFUtils::WriteUInt16BE(wStream, utf16[1]); + } +} + static void append_bfchar_section(const SkTDArray& bfchar, SkDynamicMemoryWStream* cmap) { // PDF spec defines that every bf* list can have at most 100 entries. @@ -431,9 +441,9 @@ static void append_bfchar_section(const SkTDArray& bfchar, cmap->writeText(" beginbfchar\n"); for (int j = 0; j < count; ++j) { cmap->writeText("<"); - cmap->writeHexAsText(bfchar[i + j].fGlyphId, 4); + SkPDFUtils::WriteUInt16BE(cmap, bfchar[i + j].fGlyphId); cmap->writeText("> <"); - cmap->writeHexAsText(bfchar[i + j].fUnicode, 4); + write_utf16be(cmap, bfchar[i + j].fUnicode); cmap->writeText(">\n"); } cmap->writeText("endbfchar\n"); @@ -450,11 +460,11 @@ static void append_bfrange_section(const SkTDArray& bfrange, cmap->writeText(" beginbfrange\n"); for (int j = 0; j < count; ++j) { cmap->writeText("<"); - cmap->writeHexAsText(bfrange[i + j].fStart, 4); + SkPDFUtils::WriteUInt16BE(cmap, bfrange[i + j].fStart); cmap->writeText("> <"); - cmap->writeHexAsText(bfrange[i + j].fEnd, 4); + SkPDFUtils::WriteUInt16BE(cmap, bfrange[i + j].fEnd); cmap->writeText("> <"); - cmap->writeHexAsText(bfrange[i + j].fUnicode, 4); + write_utf16be(cmap, bfrange[i + j].fUnicode); cmap->writeText(">\n"); } cmap->writeText("endbfrange\n"); diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h index cb6e29fe41..124e199614 100644 --- a/src/pdf/SkPDFUtils.h +++ b/src/pdf/SkPDFUtils.h @@ -11,11 +11,11 @@ #include "SkPaint.h" #include "SkPath.h" +#include "SkStream.h" class SkMatrix; class SkPDFArray; struct SkRect; -class SkWStream; #if 0 #define PRINT_NOT_IMPL(str) fprintf(stderr, str) @@ -31,41 +31,52 @@ class SkWStream; } \ } while (0) -class SkPDFUtils { -public: - static sk_sp RectToArray(const SkRect& rect); - static sk_sp MatrixToArray(const SkMatrix& matrix); - static void AppendTransform(const SkMatrix& matrix, SkWStream* content); +namespace SkPDFUtils { - static void MoveTo(SkScalar x, SkScalar y, SkWStream* content); - static void AppendLine(SkScalar x, SkScalar y, SkWStream* content); - static void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, - SkScalar ctl2X, SkScalar ctl2Y, - SkScalar dstX, SkScalar dstY, SkWStream* content); - static void AppendRectangle(const SkRect& rect, SkWStream* content); - static void EmitPath(const SkPath& path, SkPaint::Style paintStyle, - bool doConsumeDegerates, SkWStream* content); - static void EmitPath(const SkPath& path, SkPaint::Style paintStyle, - SkWStream* content) { - SkPDFUtils::EmitPath(path, paintStyle, true, content); - } - static void ClosePath(SkWStream* content); - static void PaintPath(SkPaint::Style style, SkPath::FillType fill, - SkWStream* content); - static void StrokePath(SkWStream* content); - static void DrawFormXObject(int objectIndex, SkWStream* content); - static void ApplyGraphicState(int objectIndex, SkWStream* content); - static void ApplyPattern(int objectIndex, SkWStream* content); +sk_sp RectToArray(const SkRect& rect); +sk_sp MatrixToArray(const SkMatrix& matrix); +void AppendTransform(const SkMatrix& matrix, SkWStream* content); - // 3 = '-', '.', and '\0' characters. - // 9 = number of significant digits - // abs(FLT_MIN_10_EXP) = number of zeros in FLT_MIN - static const size_t kMaximumFloatDecimalLength = 3 + 9 - FLT_MIN_10_EXP; - // FloatToDecimal is exposed for unit tests. - static size_t FloatToDecimal(float value, - char output[kMaximumFloatDecimalLength]); - static void AppendScalar(SkScalar value, SkWStream* stream); - static void WriteString(SkWStream* wStream, const char* input, size_t len); -}; +void MoveTo(SkScalar x, SkScalar y, SkWStream* content); +void AppendLine(SkScalar x, SkScalar y, SkWStream* content); +void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, + SkScalar ctl2X, SkScalar ctl2Y, + SkScalar dstX, SkScalar dstY, SkWStream* content); +void AppendRectangle(const SkRect& rect, SkWStream* content); +void EmitPath(const SkPath& path, SkPaint::Style paintStyle, + bool doConsumeDegerates, SkWStream* content); +inline void EmitPath(const SkPath& path, SkPaint::Style paintStyle, + SkWStream* content) { + SkPDFUtils::EmitPath(path, paintStyle, true, content); +} +void ClosePath(SkWStream* content); +void PaintPath(SkPaint::Style style, SkPath::FillType fill, + SkWStream* content); +void StrokePath(SkWStream* content); +void DrawFormXObject(int objectIndex, SkWStream* content); +void ApplyGraphicState(int objectIndex, SkWStream* content); +void ApplyPattern(int objectIndex, SkWStream* content); + +// 3 = '-', '.', and '\0' characters. +// 9 = number of significant digits +// abs(FLT_MIN_10_EXP) = number of zeros in FLT_MIN +const size_t kMaximumFloatDecimalLength = 3 + 9 - FLT_MIN_10_EXP; +// FloatToDecimal is exposed for unit tests. +size_t FloatToDecimal(float value, + char output[kMaximumFloatDecimalLength]); +void AppendScalar(SkScalar value, SkWStream* stream); +void WriteString(SkWStream* wStream, const char* input, size_t len); + +inline void WriteUInt16BE(SkDynamicMemoryWStream* wStream, uint16_t value) { + static const char gHex[] = "0123456789ABCDEF"; + char result[4]; + result[0] = gHex[ value >> 12 ]; + result[1] = gHex[0xF & (value >> 8 )]; + result[2] = gHex[0xF & (value >> 4 )]; + result[3] = gHex[0xF & (value )]; + wStream->write(result, 4); +} + +} // namespace SkPDFUtils #endif -- 2.34.1