Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: src/pdf/SkPDFDevice.cpp

Issue 2278703002: SkPDF: Glyph validation change (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix compile Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkPDFDevice.h" 8 #include "SkPDFDevice.h"
9 #include "SkAnnotationKeys.h" 9 #include "SkAnnotationKeys.h"
10 #include "SkBitmapDevice.h" 10 #include "SkBitmapDevice.h"
(...skipping 14 matching lines...) Expand all
25 #include "SkPDFResourceDict.h" 25 #include "SkPDFResourceDict.h"
26 #include "SkPDFShader.h" 26 #include "SkPDFShader.h"
27 #include "SkPDFTypes.h" 27 #include "SkPDFTypes.h"
28 #include "SkPDFUtils.h" 28 #include "SkPDFUtils.h"
29 #include "SkRasterClip.h" 29 #include "SkRasterClip.h"
30 #include "SkRRect.h" 30 #include "SkRRect.h"
31 #include "SkString.h" 31 #include "SkString.h"
32 #include "SkSurface.h" 32 #include "SkSurface.h"
33 #include "SkTextFormatParams.h" 33 #include "SkTextFormatParams.h"
34 #include "SkTemplates.h" 34 #include "SkTemplates.h"
35 #include "SkTypefacePriv.h"
36 #include "SkXfermodeInterpretation.h" 35 #include "SkXfermodeInterpretation.h"
37 36
38 #define DPI_FOR_RASTER_SCALE_ONE 72 37 #define DPI_FOR_RASTER_SCALE_ONE 72
39 38
40 // Utility functions 39 // Utility functions
41 40
42 // If the paint will definitely draw opaquely, replace kSrc_Mode with 41 // If the paint will definitely draw opaquely, replace kSrc_Mode with
43 // kSrcOver_Mode. http://crbug.com/473572 42 // kSrcOver_Mode. http://crbug.com/473572
44 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { 43 static void replace_srcmode_on_opaque_paint(SkPaint* paint) {
45 if (kSrcOver_SkXfermodeInterpretation 44 if (kSrcOver_SkXfermodeInterpretation
(...skipping 23 matching lines...) Expand all
69 if (result.getStyle() == SkPaint::kFill_Style) { 68 if (result.getStyle() == SkPaint::kFill_Style) {
70 result.setStyle(SkPaint::kStrokeAndFill_Style); 69 result.setStyle(SkPaint::kStrokeAndFill_Style);
71 } else { 70 } else {
72 width += result.getStrokeWidth(); 71 width += result.getStrokeWidth();
73 } 72 }
74 result.setStrokeWidth(width); 73 result.setStrokeWidth(width);
75 } 74 }
76 return result; 75 return result;
77 } 76 }
78 77
79 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
80 SkWStream* content) {
81 // Flip the text about the x-axis to account for origin swap and include
82 // the passed parameters.
83 content->writeText("1 0 ");
84 SkPDFUtils::AppendScalar(0 - textSkewX, content);
85 content->writeText(" -1 ");
86 SkPDFUtils::AppendScalar(x, content);
87 content->writeText(" ");
88 SkPDFUtils::AppendScalar(y, content);
89 content->writeText(" Tm\n");
90 }
91
92 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() 78 SkPDFDevice::GraphicStateEntry::GraphicStateEntry()
93 : fColor(SK_ColorBLACK) 79 : fColor(SK_ColorBLACK)
94 , fTextScaleX(SK_Scalar1) 80 , fTextScaleX(SK_Scalar1)
95 , fTextFill(SkPaint::kFill_Style) 81 , fTextFill(SkPaint::kFill_Style)
96 , fShaderIndex(-1) 82 , fShaderIndex(-1)
97 , fGraphicStateIndex(-1) 83 , fGraphicStateIndex(-1)
98 , fFont(nullptr) 84 , fFont(nullptr)
99 , fTextSize(SK_ScalarNaN) { 85 , fTextSize(SK_ScalarNaN) {
100 fMatrix.reset(); 86 fMatrix.reset();
101 } 87 }
(...skipping 856 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 944
959 namespace { 945 namespace {
960 class GlyphPositioner { 946 class GlyphPositioner {
961 public: 947 public:
962 GlyphPositioner(SkDynamicMemoryWStream* content, 948 GlyphPositioner(SkDynamicMemoryWStream* content,
963 SkScalar textSkewX, 949 SkScalar textSkewX,
964 bool wideChars, 950 bool wideChars,
965 bool defaultPositioning, 951 bool defaultPositioning,
966 SkPoint origin) 952 SkPoint origin)
967 : fContent(content) 953 : fContent(content)
968 , fCurrentMatrixX(0.0f) 954 , fCurrentMatrixOrigin{0.0f, 0.0f}
969 , fCurrentMatrixY(0.0f)
970 , fXAdvance(0.0f) 955 , fXAdvance(0.0f)
971 , fWideChars(wideChars) 956 , fWideChars(wideChars)
972 , fInText(false) 957 , fInText(false)
973 , fDefaultPositioning(defaultPositioning) { 958 , fDefaultPositioning(defaultPositioning) {
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); 959 // Flip the text about the x-axis to account for origin swap and include
960 // the passed parameters.
961 fContent->writeText("1 0 ");
962 SkPDFUtils::AppendScalar(0 - textSkewX, fContent);
963 fContent->writeText(" -1 ");
964 SkPDFUtils::AppendScalar(origin.x(), fContent);
965 fContent->writeText(" ");
966 SkPDFUtils::AppendScalar(origin.y(), fContent);
967 fContent->writeText(" Tm\n");
975 } 968 }
976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } 969 ~GlyphPositioner() { this->flush(); }
977 void flush() { 970 void flush() {
978 if (fInText) { 971 if (fInText) {
979 fContent->writeText("> Tj\n"); 972 fContent->writeText("> Tj\n");
980 fInText = false; 973 fInText = false;
981 } 974 }
982 } 975 }
983 void setWideChars(bool wideChars) { 976 void setWideChars(bool wideChars) {
984 if (fWideChars != wideChars) { 977 if (fWideChars != wideChars) {
985 SkASSERT(!fInText); 978 SkASSERT(!fInText);
986 SkASSERT(fWideChars == wideChars); 979 SkASSERT(fWideChars == wideChars);
987 fWideChars = wideChars; 980 fWideChars = wideChars;
988 } 981 }
989 } 982 }
990 void writeGlyph(SkScalar x, 983 void writeGlyph(SkPoint xy,
991 SkScalar y,
992 SkScalar advanceWidth, 984 SkScalar advanceWidth,
993 uint16_t glyph) { 985 uint16_t glyph) {
994 if (!fDefaultPositioning) { 986 if (!fDefaultPositioning) {
995 SkScalar xPosition = x - fCurrentMatrixX; 987 SkPoint position = xy - fCurrentMatrixOrigin;
996 SkScalar yPosition = y - fCurrentMatrixY; 988 if (position != SkPoint{fXAdvance, 0}) {
997 if (xPosition != fXAdvance || yPosition != 0) {
998 this->flush(); 989 this->flush();
999 SkPDFUtils::AppendScalar(xPosition, fContent); 990 SkPDFUtils::AppendScalar(position.x(), fContent);
1000 fContent->writeText(" "); 991 fContent->writeText(" ");
1001 SkPDFUtils::AppendScalar(-yPosition, fContent); 992 SkPDFUtils::AppendScalar(-position.y(), fContent);
1002 fContent->writeText(" Td "); 993 fContent->writeText(" Td ");
1003 fCurrentMatrixX = x; 994 fCurrentMatrixOrigin = xy;
1004 fCurrentMatrixY = y;
1005 fXAdvance = 0; 995 fXAdvance = 0;
1006 } 996 }
1007 fXAdvance += advanceWidth; 997 fXAdvance += advanceWidth;
1008 } 998 }
1009 if (!fInText) { 999 if (!fInText) {
1010 fContent->writeText("<"); 1000 fContent->writeText("<");
1011 fInText = true; 1001 fInText = true;
1012 } 1002 }
1013 if (fWideChars) { 1003 if (fWideChars) {
1014 SkPDFUtils::WriteUInt16BE(fContent, glyph); 1004 SkPDFUtils::WriteUInt16BE(fContent, glyph);
1015 } else { 1005 } else {
1016 SkASSERT(0 == glyph >> 8); 1006 SkASSERT(0 == glyph >> 8);
1017 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); 1007 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph));
1018 } 1008 }
1019 } 1009 }
1020 1010
1021 private: 1011 private:
1022 SkDynamicMemoryWStream* fContent; 1012 SkDynamicMemoryWStream* fContent;
1023 SkScalar fCurrentMatrixX; 1013 SkPoint fCurrentMatrixOrigin;
1024 SkScalar fCurrentMatrixY;
1025 SkScalar fXAdvance; 1014 SkScalar fXAdvance;
1026 bool fWideChars; 1015 bool fWideChars;
1027 bool fInText; 1016 bool fInText;
1028 const bool fDefaultPositioning; 1017 const bool fDefaultPositioning;
1029 }; 1018 };
1030 } // namespace 1019 } // namespace
1031 1020
1032 static void draw_transparent_text(SkPDFDevice* device, 1021 static void draw_transparent_text(SkPDFDevice* device,
1033 const SkDraw& d, 1022 const SkDraw& d,
1034 const void* text, size_t len, 1023 const void* text, size_t len,
1035 SkScalar x, SkScalar y, 1024 SkScalar x, SkScalar y,
1036 const SkPaint& srcPaint) { 1025 const SkPaint& srcPaint) {
1037 SkPaint transparent; 1026 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault();
1038 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), 1027 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) {
1039 device->getCanon())) {
1040 SkDebugf("SkPDF: default typeface should be embeddable"); 1028 SkDebugf("SkPDF: default typeface should be embeddable");
1041 return; // Avoid infinite loop in release. 1029 return; // Avoid infinite loop in release.
1042 } 1030 }
1031 SkPaint transparent;
1032 transparent.setTypeface(std::move(defaultFace));
1043 transparent.setTextSize(srcPaint.getTextSize()); 1033 transparent.setTextSize(srcPaint.getTextSize());
1044 transparent.setColor(SK_ColorTRANSPARENT); 1034 transparent.setColor(SK_ColorTRANSPARENT);
1045 switch (srcPaint.getTextEncoding()) { 1035 switch (srcPaint.getTextEncoding()) {
1046 case SkPaint::kGlyphID_TextEncoding: { 1036 case SkPaint::kGlyphID_TextEncoding: {
1047 // Since a glyphId<->Unicode mapping is typeface-specific, 1037 // Since a glyphId<->Unicode mapping is typeface-specific,
1048 // map back to Unicode first. 1038 // map back to Unicode first.
1049 size_t glyphCount = len / 2; 1039 size_t glyphCount = len / 2;
1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); 1040 SkAutoTMalloc<SkUnichar> unichars(glyphCount);
1051 srcPaint.glyphsToUnichars( 1041 srcPaint.glyphsToUnichars(
1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); 1042 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]);
1053 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); 1043 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding);
1054 // TODO(halcanary): deal with case where default typeface 1044 // TODO(halcanary): deal with case where default typeface
1055 // does not have glyphs for these unicode code points. 1045 // does not have glyphs for these unicode code points.
1056 device->drawText(d, &unichars[0], 1046 device->drawText(d, &unichars[0],
1057 glyphCount * sizeof(SkUnichar), 1047 glyphCount * sizeof(SkUnichar),
1058 x, y, transparent); 1048 x, y, transparent);
1059 break; 1049 break;
1060 } 1050 }
1061 case SkPaint::kUTF8_TextEncoding: 1051 case SkPaint::kUTF8_TextEncoding:
1062 case SkPaint::kUTF16_TextEncoding: 1052 case SkPaint::kUTF16_TextEncoding:
1063 case SkPaint::kUTF32_TextEncoding: 1053 case SkPaint::kUTF32_TextEncoding:
1064 transparent.setTextEncoding(srcPaint.getTextEncoding()); 1054 transparent.setTextEncoding(srcPaint.getTextEncoding());
1065 device->drawText(d, text, len, x, y, transparent); 1055 device->drawText(d, text, len, x, y, transparent);
1066 break; 1056 break;
1067 default: 1057 default:
1068 SkFAIL("unknown text encoding"); 1058 SkFAIL("unknown text encoding");
1069 } 1059 }
1070 } 1060 }
1071 1061
1062 template <typename Fn>
1063 struct SkAtScopeExitImpl {
1064 Fn fFn;
1065 ~SkAtScopeExitImpl() { fFn(); }
1066 };
1067 #define SK_AT_SCOPE_EXIT(...) \
1068 auto fn = [&]() { __VA_ARGS__ }; \
1069 SkAtScopeExitImpl<decltype(fn)> \
1070 SK_MACRO_APPEND_LINE(at_scope_exit_){std::move(fn)}
bungeman-skia 2016/08/26 17:47:36 It would be nice for this to look more like https
hal.canary 2016/08/26 18:11:55 Done.
1071
1072 void SkPDFDevice::internalDrawText( 1072 void SkPDFDevice::internalDrawText(
1073 const SkDraw& d, const void* sourceText, size_t sourceByteCount, 1073 const SkDraw& d, const void* sourceText, size_t sourceByteCount,
1074 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, 1074 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
1075 SkPoint offset, const SkPaint& srcPaint) { 1075 SkPoint offset, const SkPaint& srcPaint) {
1076 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); 1076 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false);
1077 if (srcPaint.getMaskFilter() != nullptr) { 1077 if (srcPaint.getMaskFilter() != nullptr) {
1078 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1078 // Don't pretend we support drawing MaskFilters, it makes for artifacts
1079 // making text unreadable (e.g. same text twice when using CSS shadows). 1079 // making text unreadable (e.g. same text twice when using CSS shadows).
1080 return; 1080 return;
1081 } 1081 }
1082 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); 1082 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false);
1083 if (srcPaint.isVerticalText()) { 1083 if (srcPaint.isVerticalText()) {
1084 // Don't pretend we support drawing vertical text. It is not 1084 // Don't pretend we support drawing vertical text. It is not
1085 // clear to me how to switch to "vertical writing" mode in PDF. 1085 // clear to me how to switch to "vertical writing" mode in PDF.
1086 // Currently neither Chromium or Android set this flag. 1086 // Currently neither Chromium or Android set this flag.
1087 // https://bug.skia.org/5665 1087 // https://bug.skia.org/5665
1088 return; 1088 return;
1089 } 1089 }
1090 SkPaint paint = calculate_text_paint(srcPaint); 1090 SkPaint paint = calculate_text_paint(srcPaint);
1091 replace_srcmode_on_opaque_paint(&paint); 1091 replace_srcmode_on_opaque_paint(&paint);
1092 if (!paint.getTypeface()) { 1092 if (!paint.getTypeface()) {
1093 paint.setTypeface(SkTypeface::MakeDefault()); 1093 paint.setTypeface(SkTypeface::MakeDefault());
1094 } 1094 }
1095 SkTypeface* typeface = paint.getTypeface(); 1095 SkTypeface* typeface = paint.getTypeface();
1096 if (!typeface) { 1096 if (!typeface) {
1097 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); 1097 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
1098 return; 1098 return;
1099 } 1099 }
1100 int typefaceGlyphCount = typeface->countGlyphs(); 1100 SkPDFFont::TypefaceInfo faceInfo = SkPDFFont::GetTypefaceInfo(typeface);
1101 if (typefaceGlyphCount < 1) { 1101 if (!faceInfo.fGood) {
1102 SkDebugf("SkPDF: SkTypeface has no glyphs.\n");
1103 return; 1102 return;
1104 } 1103 }
1104 const SkGlyphID maxGlyphID = faceInfo.fMaxGlyphID;
1105 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { 1105 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) {
1106 SkPath path; // https://bug.skia.org/3866 1106 SkPath path; // https://bug.skia.org/3866
1107 paint.getTextPath(sourceText, sourceByteCount, 1107 paint.getTextPath(sourceText, sourceByteCount,
1108 offset.x(), offset.y(), &path); 1108 offset.x(), offset.y(), &path);
1109 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); 1109 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
1110 // Draw text transparently to make it copyable/searchable/accessable. 1110 // Draw text transparently to make it copyable/searchable/accessable.
1111 draw_transparent_text(this, d, sourceText, sourceByteCount, 1111 draw_transparent_text(this, d, sourceText, sourceByteCount,
1112 offset.x(), offset.y(), paint); 1112 offset.x(), offset.y(), paint);
1113 return; 1113 return;
1114 } 1114 }
1115 // Always make a copy (1) to validate user-input glyphs and
1116 // (2) because we may modify the glyphs in place (for
1117 // single-byte-glyph-id PDF fonts).
1118 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); 1115 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
1119 if (glyphCount <= 0) { return; } 1116 if (glyphCount <= 0) {
1120 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount)); 1117 return;
1121 SkGlyphID* glyphs = glyphStorage.get(); 1118 }
1122 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs); 1119 SkAutoSTMalloc<128, SkGlyphID> glyphStorage;
1120 const SkGlyphID* glyphs = nullptr;
1123 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { 1121 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
1124 // Validate user-input glyphs. 1122 glyphs = (const SkGlyphID*)sourceText;
1125 SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1); 1123 // validate input later.
1126 for (int i = 0; i < glyphCount; ++i) {
1127 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]);
1128 }
1129 } else { 1124 } else {
1125 glyphStorage.reset(SkToSizeT(glyphCount));
1126 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get() );
1127 glyphs = glyphStorage.get();
1130 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1128 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
1131 } 1129 }
1132 1130
1133 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); 1131 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
1134 paint.setHinting(SkPaint::kNo_Hinting); 1132 paint.setHinting(SkPaint::kNo_Hinting);
1135 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); 1133 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr);
1136 1134
1137 SkPaint::Align alignment = paint.getTextAlign(); 1135 SkPaint::Align alignment = paint.getTextAlign();
1136 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f :
1137 SkPaint::kCenter_Align == alignment ? -0.5f :
1138 /* SkPaint::kRight_Align */ -1.0f;
1138 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { 1139 if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
1139 SkScalar advance{0}; 1140 SkScalar advance = 0;
1140 for (int i = 0; i < glyphCount; ++i) { 1141 for (int i = 0; i < glyphCount; ++i) {
1141 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; 1142 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
1142 } 1143 }
1143 SkScalar m = alignment == SkPaint::kCenter_Align 1144 offset.offset(alignmentFactor * advance, 0);
1144 ? 0.5f * advance : advance;
1145 offset -= SkPoint{m, 0};
1146 } 1145 }
1147 ScopedContentEntry content(this, d, paint, true); 1146 ScopedContentEntry content(this, d, paint, true);
1148 if (!content.entry()) { 1147 if (!content.entry()) {
1149 return; 1148 return;
1150 } 1149 }
1151 SkDynamicMemoryWStream* out = &content.entry()->fContent; 1150 SkDynamicMemoryWStream* out = &content.entry()->fContent;
1151 SkScalar textSize = paint.getTextSize();
1152
1152 out->writeText("BT\n"); 1153 out->writeText("BT\n");
1153 if (!this->updateFont(paint, glyphs[0], content.entry())) { 1154 SK_AT_SCOPE_EXIT( out->writeText("ET\n"); );
1154 SkDebugf("SkPDF: Font error."); 1155
1155 out->writeText("ET\n%SkPDF: Font error.\n"); 1156 int index = 0;
1156 return; 1157 while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font.
bungeman-skia 2016/08/26 17:47:36 Should this while loop go before writing out "BT"?
hal.canary 2016/08/26 18:11:55 Done. Good catch.
1158 ++index; // Skip this glyphID
1159 if (index == glyphCount) {
1160 return; // all glyphIDs were bad.
1161 }
1157 } 1162 }
1158 SkPDFFont* font = content.entry()->fState.fFont; 1163 SkPDFFont* font = this->updateFont(
1164 typeface, textSize, glyphs[index], content.entry());
1165 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met .
1166 if (!font) { return; }
1167
1159 GlyphPositioner glyphPositioner(out, 1168 GlyphPositioner glyphPositioner(out,
1160 paint.getTextSkewX(), 1169 paint.getTextSkewX(),
1161 font->multiByteGlyphs(), 1170 font->multiByteGlyphs(),
1162 defaultPositioning, 1171 defaultPositioning,
1163 offset); 1172 offset);
1164 const SkGlyphID* const glyphsEnd = glyphs + glyphCount;
1165 1173
1166 while (glyphs < glyphsEnd) { 1174 while (index < glyphCount) {
1167 font = content.entry()->fState.fFont; 1175 int stretch = font->countStretch(&glyphs[index], glyphCount - index, max GlyphID);
1168 int stretch = font->multiByteGlyphs() 1176 SkASSERT(index + stretch <= glyphCount);
1169 ? SkToInt(glyphsEnd - glyphs)
1170 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly phs));
1171 SkASSERT(glyphs + stretch <= glyphsEnd);
1172 if (stretch < 1) { 1177 if (stretch < 1) {
1173 SkASSERT(!font->multiByteGlyphs());
1174 // The current pdf font cannot encode the next glyph. 1178 // The current pdf font cannot encode the next glyph.
1175 // Try to get a pdf font which can encode the next glyph. 1179 // Try to get a pdf font which can encode the next glyph.
1176 glyphPositioner.flush(); 1180 glyphPositioner.flush();
1177 if (!this->updateFont(paint, *glyphs, content.entry())) { 1181 // first, validate the next glyph
1178 SkDebugf("SkPDF: Font error."); 1182 while (glyphs[index] > maxGlyphID) {
1179 out->writeText("ET\n%SkPDF: Font error.\n"); 1183 ++index; // Skip this glyphID
1180 return; 1184 if (index == glyphCount) {
1185 return; // all remainng glyphIDs were bad.
1186 }
1181 } 1187 }
1182 font = content.entry()->fState.fFont; 1188 SkASSERT(index < glyphCount);
1189 font = this->updateFont(typeface, textSize, glyphs[index], content.e ntry());
1190 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met .
1191 if (!font) { return; }
1183 glyphPositioner.setWideChars(font->multiByteGlyphs()); 1192 glyphPositioner.setWideChars(font->multiByteGlyphs());
1184 // try again 1193 // Get stretch for this new font.
1185 stretch = font->glyphsToPDFFontEncodingCount(glyphs, 1194 stretch = font->countStretch(&glyphs[index], glyphCount - index, max GlyphID);
1186 SkToInt(glyphsEnd - gly phs));
1187 if (stretch < 1) { 1195 if (stretch < 1) {
1188 SkDEBUGFAIL("PDF could not encode glyph."); 1196 SkDEBUGFAIL("PDF could not encode glyph.");
1189 glyphPositioner.flush();
1190 out->writeText("ET\n%SkPDF: Font encoding error.\n");
1191 return; 1197 return;
1192 } 1198 }
1193 } 1199 }
1194 font->noteGlyphUsage(glyphs, stretch); 1200 while (stretch-- > 0) {
1195 if (defaultPositioning) { 1201 SkGlyphID gid = glyphs[index];
1196 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp hs)); 1202 if (gid <= maxGlyphID) {
1197 while (stretch-- > 0) { 1203 font->noteGlyphUsage(gid);
1198 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); 1204 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid);
1199 ++glyphs; 1205 if (defaultPositioning) {
1206 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph);
1207 } else {
1208 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvan ceX;
1209 SkPoint xy = SkTextBlob::kFull_Positioning == positioning
1210 ? SkPoint{pos[2 * index], pos[2 * index + 1]}
1211 : SkPoint{pos[index], 0};
bungeman-skia 2016/08/26 17:47:36 nit: probably the silliest nit ever, but it makes
hal.canary 2016/08/26 18:11:55 Done.
1212 if (alignment != SkPaint::kLeft_Align) {
1213 xy.offset(alignmentFactor * advance, 0);
1214 }
1215 glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
1216 }
1200 } 1217 }
1201 } else { 1218 ++index;
1202 while (stretch-- > 0) {
1203 SkScalar advance = glyphCache->getGlyphIDAdvance(*glyphs).fAdvan ceX;
1204 SkScalar x = *pos++;
1205 // evaluate x and y in order!
1206 SkScalar y = SkTextBlob::kFull_Positioning == positioning ? *pos ++ : 0;
1207 SkPoint xy{x, y};
1208 if (alignment != SkPaint::kLeft_Align) {
1209 SkScalar m = alignment == SkPaint::kCenter_Align
1210 ? 0.5f * advance : advance;
1211 xy -= SkPoint{m, 0};
1212 }
1213 (void)font->glyphsToPDFFontEncoding(glyphs, 1);
1214 glyphPositioner.writeGlyph(xy.x(), xy.y(), advance, *glyphs);
1215 ++glyphs;
1216 }
1217 } 1219 }
1218 } 1220 }
1219 glyphPositioner.flush();
1220 out->writeText("ET\n");
1221 } 1221 }
1222 1222
1223 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1223 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
1224 SkScalar x, SkScalar y, const SkPaint& paint) { 1224 SkScalar x, SkScalar y, const SkPaint& paint) {
1225 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, 1225 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng,
1226 SkPoint{x, y}, paint); 1226 SkPoint{x, y}, paint);
1227 } 1227 }
1228 1228
1229 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1229 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
1230 const SkScalar pos[], int scalarsPerPos, 1230 const SkScalar pos[], int scalarsPerPos,
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after
1896 // Assumes that xobject has been canonicalized (so we can directly compare 1896 // Assumes that xobject has been canonicalized (so we can directly compare
1897 // pointers). 1897 // pointers).
1898 int result = fXObjectResources.find(xObject); 1898 int result = fXObjectResources.find(xObject);
1899 if (result < 0) { 1899 if (result < 0) {
1900 result = fXObjectResources.count(); 1900 result = fXObjectResources.count();
1901 fXObjectResources.push(SkRef(xObject)); 1901 fXObjectResources.push(SkRef(xObject));
1902 } 1902 }
1903 return result; 1903 return result;
1904 } 1904 }
1905 1905
1906 bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 1906 SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface,
1907 SkPDFDevice::ContentEntry* contentEntry) { 1907 SkScalar textSize,
1908 SkTypeface* typeface = paint.getTypeface(); 1908 uint16_t glyphID,
1909 SkPDFDevice::ContentEntry* contentEntry) {
1909 if (contentEntry->fState.fFont == nullptr || 1910 if (contentEntry->fState.fFont == nullptr ||
1910 contentEntry->fState.fTextSize != paint.getTextSize() || 1911 contentEntry->fState.fTextSize != textSize ||
1911 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 1912 !contentEntry->fState.fFont->hasGlyph(glyphID)) {
1912 int fontIndex = getFontResourceIndex(typeface, glyphID); 1913 int fontIndex = getFontResourceIndex(typeface, glyphID);
1913 if (fontIndex < 0) { 1914 if (fontIndex < 0) {
1914 return false; 1915 SkDebugf("SkPDF: Font error.");
1916 return nullptr;
1915 } 1917 }
1916 contentEntry->fContent.writeText("/"); 1918 contentEntry->fContent.writeText("/");
1917 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 1919 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
1918 SkPDFResourceDict::kFont_ResourceType, 1920 SkPDFResourceDict::kFont_ResourceType,
1919 fontIndex).c_str()); 1921 fontIndex).c_str());
1920 contentEntry->fContent.writeText(" "); 1922 contentEntry->fContent.writeText(" ");
1921 SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent); 1923 SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent);
1922 contentEntry->fContent.writeText(" Tf\n"); 1924 contentEntry->fContent.writeText(" Tf\n");
1923 contentEntry->fState.fFont = fFontResources[fontIndex]; 1925 contentEntry->fState.fFont = fFontResources[fontIndex];
1924 } 1926 }
1925 return true; 1927 return contentEntry->fState.fFont;
1926 } 1928 }
1927 1929
1928 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 1930 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
1929 sk_sp<SkPDFFont> newFont( 1931 sk_sp<SkPDFFont> newFont(
1930 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); 1932 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID));
1931 if (!newFont) { 1933 if (!newFont) {
1932 return -1; 1934 return -1;
1933 } 1935 }
1934 int resourceIndex = fFontResources.find(newFont.get()); 1936 int resourceIndex = fFontResources.find(newFont.get());
1935 if (resourceIndex < 0) { 1937 if (resourceIndex < 0) {
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
2145 } 2147 }
2146 2148
2147 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { 2149 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
2148 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), 2150 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()),
2149 image->makeNonTextureImage()); 2151 image->makeNonTextureImage());
2150 } 2152 }
2151 2153
2152 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { 2154 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
2153 return nullptr; 2155 return nullptr;
2154 } 2156 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698