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

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 comment 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 10 matching lines...) Expand all
21 #include "SkPDFDocument.h" 21 #include "SkPDFDocument.h"
22 #include "SkPDFFont.h" 22 #include "SkPDFFont.h"
23 #include "SkPDFFormXObject.h" 23 #include "SkPDFFormXObject.h"
24 #include "SkPDFGraphicState.h" 24 #include "SkPDFGraphicState.h"
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 "SkScopeExit.h"
31 #include "SkString.h" 32 #include "SkString.h"
32 #include "SkSurface.h" 33 #include "SkSurface.h"
33 #include "SkTextFormatParams.h" 34 #include "SkTextFormatParams.h"
34 #include "SkTemplates.h" 35 #include "SkTemplates.h"
35 #include "SkTypefacePriv.h"
36 #include "SkXfermodeInterpretation.h" 36 #include "SkXfermodeInterpretation.h"
37 37
38 #define DPI_FOR_RASTER_SCALE_ONE 72 38 #define DPI_FOR_RASTER_SCALE_ONE 72
39 39
40 // Utility functions 40 // Utility functions
41 41
42 // If the paint will definitely draw opaquely, replace kSrc_Mode with 42 // If the paint will definitely draw opaquely, replace kSrc_Mode with
43 // kSrcOver_Mode. http://crbug.com/473572 43 // kSrcOver_Mode. http://crbug.com/473572
44 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { 44 static void replace_srcmode_on_opaque_paint(SkPaint* paint) {
45 if (kSrcOver_SkXfermodeInterpretation 45 if (kSrcOver_SkXfermodeInterpretation
(...skipping 23 matching lines...) Expand all
69 if (result.getStyle() == SkPaint::kFill_Style) { 69 if (result.getStyle() == SkPaint::kFill_Style) {
70 result.setStyle(SkPaint::kStrokeAndFill_Style); 70 result.setStyle(SkPaint::kStrokeAndFill_Style);
71 } else { 71 } else {
72 width += result.getStrokeWidth(); 72 width += result.getStrokeWidth();
73 } 73 }
74 result.setStrokeWidth(width); 74 result.setStrokeWidth(width);
75 } 75 }
76 return result; 76 return result;
77 } 77 }
78 78
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() 79 SkPDFDevice::GraphicStateEntry::GraphicStateEntry()
93 : fColor(SK_ColorBLACK) 80 : fColor(SK_ColorBLACK)
94 , fTextScaleX(SK_Scalar1) 81 , fTextScaleX(SK_Scalar1)
95 , fTextFill(SkPaint::kFill_Style) 82 , fTextFill(SkPaint::kFill_Style)
96 , fShaderIndex(-1) 83 , fShaderIndex(-1)
97 , fGraphicStateIndex(-1) 84 , fGraphicStateIndex(-1)
98 , fFont(nullptr) 85 , fFont(nullptr)
99 , fTextSize(SK_ScalarNaN) { 86 , fTextSize(SK_ScalarNaN) {
100 fMatrix.reset(); 87 fMatrix.reset();
101 } 88 }
(...skipping 856 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 945
959 namespace { 946 namespace {
960 class GlyphPositioner { 947 class GlyphPositioner {
961 public: 948 public:
962 GlyphPositioner(SkDynamicMemoryWStream* content, 949 GlyphPositioner(SkDynamicMemoryWStream* content,
963 SkScalar textSkewX, 950 SkScalar textSkewX,
964 bool wideChars, 951 bool wideChars,
965 bool defaultPositioning, 952 bool defaultPositioning,
966 SkPoint origin) 953 SkPoint origin)
967 : fContent(content) 954 : fContent(content)
968 , fCurrentMatrixX(0.0f) 955 , fCurrentMatrixOrigin{0.0f, 0.0f}
969 , fCurrentMatrixY(0.0f)
970 , fXAdvance(0.0f) 956 , fXAdvance(0.0f)
971 , fWideChars(wideChars) 957 , fWideChars(wideChars)
972 , fInText(false) 958 , fInText(false)
973 , fDefaultPositioning(defaultPositioning) { 959 , fDefaultPositioning(defaultPositioning) {
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); 960 // Flip the text about the x-axis to account for origin swap and include
961 // the passed parameters.
962 fContent->writeText("1 0 ");
963 SkPDFUtils::AppendScalar(0 - textSkewX, fContent);
964 fContent->writeText(" -1 ");
965 SkPDFUtils::AppendScalar(origin.x(), fContent);
966 fContent->writeText(" ");
967 SkPDFUtils::AppendScalar(origin.y(), fContent);
968 fContent->writeText(" Tm\n");
975 } 969 }
976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } 970 ~GlyphPositioner() { this->flush(); }
977 void flush() { 971 void flush() {
978 if (fInText) { 972 if (fInText) {
979 fContent->writeText("> Tj\n"); 973 fContent->writeText("> Tj\n");
980 fInText = false; 974 fInText = false;
981 } 975 }
982 } 976 }
983 void setWideChars(bool wideChars) { 977 void setWideChars(bool wideChars) {
984 if (fWideChars != wideChars) { 978 if (fWideChars != wideChars) {
985 SkASSERT(!fInText); 979 SkASSERT(!fInText);
986 SkASSERT(fWideChars == wideChars); 980 SkASSERT(fWideChars == wideChars);
987 fWideChars = wideChars; 981 fWideChars = wideChars;
988 } 982 }
989 } 983 }
990 void writeGlyph(SkScalar x, 984 void writeGlyph(SkPoint xy,
991 SkScalar y,
992 SkScalar advanceWidth, 985 SkScalar advanceWidth,
993 uint16_t glyph) { 986 uint16_t glyph) {
994 if (!fDefaultPositioning) { 987 if (!fDefaultPositioning) {
995 SkScalar xPosition = x - fCurrentMatrixX; 988 SkPoint position = xy - fCurrentMatrixOrigin;
996 SkScalar yPosition = y - fCurrentMatrixY; 989 if (position != SkPoint{fXAdvance, 0}) {
997 if (xPosition != fXAdvance || yPosition != 0) {
998 this->flush(); 990 this->flush();
999 SkPDFUtils::AppendScalar(xPosition, fContent); 991 SkPDFUtils::AppendScalar(position.x(), fContent);
1000 fContent->writeText(" "); 992 fContent->writeText(" ");
1001 SkPDFUtils::AppendScalar(-yPosition, fContent); 993 SkPDFUtils::AppendScalar(-position.y(), fContent);
1002 fContent->writeText(" Td "); 994 fContent->writeText(" Td ");
1003 fCurrentMatrixX = x; 995 fCurrentMatrixOrigin = xy;
1004 fCurrentMatrixY = y;
1005 fXAdvance = 0; 996 fXAdvance = 0;
1006 } 997 }
1007 fXAdvance += advanceWidth; 998 fXAdvance += advanceWidth;
1008 } 999 }
1009 if (!fInText) { 1000 if (!fInText) {
1010 fContent->writeText("<"); 1001 fContent->writeText("<");
1011 fInText = true; 1002 fInText = true;
1012 } 1003 }
1013 if (fWideChars) { 1004 if (fWideChars) {
1014 SkPDFUtils::WriteUInt16BE(fContent, glyph); 1005 SkPDFUtils::WriteUInt16BE(fContent, glyph);
1015 } else { 1006 } else {
1016 SkASSERT(0 == glyph >> 8); 1007 SkASSERT(0 == glyph >> 8);
1017 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); 1008 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph));
1018 } 1009 }
1019 } 1010 }
1020 1011
1021 private: 1012 private:
1022 SkDynamicMemoryWStream* fContent; 1013 SkDynamicMemoryWStream* fContent;
1023 SkScalar fCurrentMatrixX; 1014 SkPoint fCurrentMatrixOrigin;
1024 SkScalar fCurrentMatrixY;
1025 SkScalar fXAdvance; 1015 SkScalar fXAdvance;
1026 bool fWideChars; 1016 bool fWideChars;
1027 bool fInText; 1017 bool fInText;
1028 const bool fDefaultPositioning; 1018 const bool fDefaultPositioning;
1029 }; 1019 };
1030 } // namespace 1020 } // namespace
1031 1021
1032 static void draw_transparent_text(SkPDFDevice* device, 1022 static void draw_transparent_text(SkPDFDevice* device,
1033 const SkDraw& d, 1023 const SkDraw& d,
1034 const void* text, size_t len, 1024 const void* text, size_t len,
1035 SkScalar x, SkScalar y, 1025 SkScalar x, SkScalar y,
1036 const SkPaint& srcPaint) { 1026 const SkPaint& srcPaint) {
1037 SkPaint transparent; 1027 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault();
1038 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), 1028 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) {
1039 device->getCanon())) {
1040 SkDebugf("SkPDF: default typeface should be embeddable"); 1029 SkDebugf("SkPDF: default typeface should be embeddable");
1041 return; // Avoid infinite loop in release. 1030 return; // Avoid infinite loop in release.
1042 } 1031 }
1032 SkPaint transparent;
1033 transparent.setTypeface(std::move(defaultFace));
1043 transparent.setTextSize(srcPaint.getTextSize()); 1034 transparent.setTextSize(srcPaint.getTextSize());
1044 transparent.setColor(SK_ColorTRANSPARENT); 1035 transparent.setColor(SK_ColorTRANSPARENT);
1045 switch (srcPaint.getTextEncoding()) { 1036 switch (srcPaint.getTextEncoding()) {
1046 case SkPaint::kGlyphID_TextEncoding: { 1037 case SkPaint::kGlyphID_TextEncoding: {
1047 // Since a glyphId<->Unicode mapping is typeface-specific, 1038 // Since a glyphId<->Unicode mapping is typeface-specific,
1048 // map back to Unicode first. 1039 // map back to Unicode first.
1049 size_t glyphCount = len / 2; 1040 size_t glyphCount = len / 2;
1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); 1041 SkAutoTMalloc<SkUnichar> unichars(glyphCount);
1051 srcPaint.glyphsToUnichars( 1042 srcPaint.glyphsToUnichars(
1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); 1043 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1090 SkPaint paint = calculate_text_paint(srcPaint); 1081 SkPaint paint = calculate_text_paint(srcPaint);
1091 replace_srcmode_on_opaque_paint(&paint); 1082 replace_srcmode_on_opaque_paint(&paint);
1092 if (!paint.getTypeface()) { 1083 if (!paint.getTypeface()) {
1093 paint.setTypeface(SkTypeface::MakeDefault()); 1084 paint.setTypeface(SkTypeface::MakeDefault());
1094 } 1085 }
1095 SkTypeface* typeface = paint.getTypeface(); 1086 SkTypeface* typeface = paint.getTypeface();
1096 if (!typeface) { 1087 if (!typeface) {
1097 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); 1088 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
1098 return; 1089 return;
1099 } 1090 }
1100 int typefaceGlyphCount = typeface->countGlyphs(); 1091
1101 if (typefaceGlyphCount < 1) { 1092 const SkAdvancedTypefaceMetrics* metrics =
1102 SkDebugf("SkPDF: SkTypeface has no glyphs.\n"); 1093 SkPDFFont::GetMetrics(typeface, fDocument->canon());
1094 if (!metrics) {
1103 return; 1095 return;
1104 } 1096 }
1097 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping.
1098 const SkGlyphID maxGlyphID = metrics->fLastGlyphID;
1105 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { 1099 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) {
1106 SkPath path; // https://bug.skia.org/3866 1100 SkPath path; // https://bug.skia.org/3866
1107 paint.getTextPath(sourceText, sourceByteCount, 1101 paint.getTextPath(sourceText, sourceByteCount,
1108 offset.x(), offset.y(), &path); 1102 offset.x(), offset.y(), &path);
1109 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); 1103 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
1110 // Draw text transparently to make it copyable/searchable/accessable. 1104 // Draw text transparently to make it copyable/searchable/accessable.
1111 draw_transparent_text(this, d, sourceText, sourceByteCount, 1105 draw_transparent_text(this, d, sourceText, sourceByteCount,
1112 offset.x(), offset.y(), paint); 1106 offset.x(), offset.y(), paint);
1113 return; 1107 return;
1114 } 1108 }
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); 1109 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
1119 if (glyphCount <= 0) { return; } 1110 if (glyphCount <= 0) {
1120 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount)); 1111 return;
1121 SkGlyphID* glyphs = glyphStorage.get(); 1112 }
1122 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs); 1113 SkAutoSTMalloc<128, SkGlyphID> glyphStorage;
1114 const SkGlyphID* glyphs = nullptr;
1123 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { 1115 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
1124 // Validate user-input glyphs. 1116 glyphs = (const SkGlyphID*)sourceText;
1125 SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1); 1117 // validate input later.
1126 for (int i = 0; i < glyphCount; ++i) {
1127 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]);
1128 }
1129 } else { 1118 } else {
1119 glyphStorage.reset(SkToSizeT(glyphCount));
1120 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get() );
1121 glyphs = glyphStorage.get();
1130 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1122 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
1131 } 1123 }
1132 1124
1133 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); 1125 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
1134 paint.setHinting(SkPaint::kNo_Hinting); 1126 paint.setHinting(SkPaint::kNo_Hinting);
1135 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); 1127 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr);
1136 1128
1137 SkPaint::Align alignment = paint.getTextAlign(); 1129 SkPaint::Align alignment = paint.getTextAlign();
1130 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f :
1131 SkPaint::kCenter_Align == alignment ? -0.5f :
1132 /* SkPaint::kRight_Align */ -1.0f;
1138 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { 1133 if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
1139 SkScalar advance{0}; 1134 SkScalar advance = 0;
1140 for (int i = 0; i < glyphCount; ++i) { 1135 for (int i = 0; i < glyphCount; ++i) {
1141 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; 1136 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
1142 } 1137 }
1143 SkScalar m = alignment == SkPaint::kCenter_Align 1138 offset.offset(alignmentFactor * advance, 0);
1144 ? 0.5f * advance : advance;
1145 offset -= SkPoint{m, 0};
1146 } 1139 }
1147 ScopedContentEntry content(this, d, paint, true); 1140 ScopedContentEntry content(this, d, paint, true);
1148 if (!content.entry()) { 1141 if (!content.entry()) {
1149 return; 1142 return;
1150 } 1143 }
1151 SkDynamicMemoryWStream* out = &content.entry()->fContent; 1144 SkDynamicMemoryWStream* out = &content.entry()->fContent;
1145 SkScalar textSize = paint.getTextSize();
1146
1147 int index = 0;
1148 while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font.
1149 ++index; // Skip this glyphID
1150 if (index == glyphCount) {
1151 return; // all glyphIDs were bad.
1152 }
1153 }
1154
1152 out->writeText("BT\n"); 1155 out->writeText("BT\n");
1153 if (!this->updateFont(paint, glyphs[0], content.entry())) { 1156 SK_AT_SCOPE_EXIT(out->writeText("ET\n"));
1154 SkDebugf("SkPDF: Font error."); 1157
1155 out->writeText("ET\n%SkPDF: Font error.\n"); 1158 SkPDFFont* font = this->updateFont(
1156 return; 1159 typeface, textSize, glyphs[index], content.entry());
1157 } 1160 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met .
1158 SkPDFFont* font = content.entry()->fState.fFont; 1161 if (!font) { return; }
1162
1159 GlyphPositioner glyphPositioner(out, 1163 GlyphPositioner glyphPositioner(out,
1160 paint.getTextSkewX(), 1164 paint.getTextSkewX(),
1161 font->multiByteGlyphs(), 1165 font->multiByteGlyphs(),
1162 defaultPositioning, 1166 defaultPositioning,
1163 offset); 1167 offset);
1164 const SkGlyphID* const glyphsEnd = glyphs + glyphCount;
1165 1168
1166 while (glyphs < glyphsEnd) { 1169 while (index < glyphCount) {
1167 font = content.entry()->fState.fFont; 1170 int stretch = font->countStretch(&glyphs[index], glyphCount - index, max GlyphID);
1168 int stretch = font->multiByteGlyphs() 1171 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) { 1172 if (stretch < 1) {
1173 SkASSERT(!font->multiByteGlyphs());
1174 // The current pdf font cannot encode the next glyph. 1173 // The current pdf font cannot encode the next glyph.
1175 // Try to get a pdf font which can encode the next glyph. 1174 // Try to get a pdf font which can encode the next glyph.
1176 glyphPositioner.flush(); 1175 glyphPositioner.flush();
1177 if (!this->updateFont(paint, *glyphs, content.entry())) { 1176 // first, validate the next glyph
1178 SkDebugf("SkPDF: Font error."); 1177 while (glyphs[index] > maxGlyphID) {
1179 out->writeText("ET\n%SkPDF: Font error.\n"); 1178 ++index; // Skip this glyphID
1180 return; 1179 if (index == glyphCount) {
1180 return; // all remainng glyphIDs were bad.
1181 }
1181 } 1182 }
1182 font = content.entry()->fState.fFont; 1183 SkASSERT(index < glyphCount);
1184 font = this->updateFont(typeface, textSize, glyphs[index], content.e ntry());
1185 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met .
1186 if (!font) { return; }
1183 glyphPositioner.setWideChars(font->multiByteGlyphs()); 1187 glyphPositioner.setWideChars(font->multiByteGlyphs());
1184 // try again 1188 // Get stretch for this new font.
1185 stretch = font->glyphsToPDFFontEncodingCount(glyphs, 1189 stretch = font->countStretch(&glyphs[index], glyphCount - index, max GlyphID);
1186 SkToInt(glyphsEnd - gly phs));
1187 if (stretch < 1) { 1190 if (stretch < 1) {
1188 SkDEBUGFAIL("PDF could not encode glyph."); 1191 SkDEBUGFAIL("PDF could not encode glyph.");
1189 glyphPositioner.flush();
1190 out->writeText("ET\n%SkPDF: Font encoding error.\n");
1191 return; 1192 return;
1192 } 1193 }
1193 } 1194 }
1194 font->noteGlyphUsage(glyphs, stretch); 1195 while (stretch-- > 0) {
1195 if (defaultPositioning) { 1196 SkGlyphID gid = glyphs[index];
1196 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp hs)); 1197 if (gid <= maxGlyphID) {
1197 while (stretch-- > 0) { 1198 font->noteGlyphUsage(gid);
1198 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); 1199 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid);
1199 ++glyphs; 1200 if (defaultPositioning) {
1201 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph);
1202 } else {
1203 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvan ceX;
1204 SkPoint xy = SkTextBlob::kFull_Positioning == positioning
1205 ? SkPoint{pos[2 * index], pos[2 * index + 1]}
1206 : SkPoint{pos[index], 0};
1207 if (alignment != SkPaint::kLeft_Align) {
1208 xy.offset(alignmentFactor * advance, 0);
1209 }
1210 glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
1211 }
1200 } 1212 }
1201 } else { 1213 ++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 } 1214 }
1218 } 1215 }
1219 glyphPositioner.flush();
1220 out->writeText("ET\n");
1221 } 1216 }
1222 1217
1223 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1218 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
1224 SkScalar x, SkScalar y, const SkPaint& paint) { 1219 SkScalar x, SkScalar y, const SkPaint& paint) {
1225 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, 1220 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng,
1226 SkPoint{x, y}, paint); 1221 SkPoint{x, y}, paint);
1227 } 1222 }
1228 1223
1229 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1224 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
1230 const SkScalar pos[], int scalarsPerPos, 1225 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 1891 // Assumes that xobject has been canonicalized (so we can directly compare
1897 // pointers). 1892 // pointers).
1898 int result = fXObjectResources.find(xObject); 1893 int result = fXObjectResources.find(xObject);
1899 if (result < 0) { 1894 if (result < 0) {
1900 result = fXObjectResources.count(); 1895 result = fXObjectResources.count();
1901 fXObjectResources.push(SkRef(xObject)); 1896 fXObjectResources.push(SkRef(xObject));
1902 } 1897 }
1903 return result; 1898 return result;
1904 } 1899 }
1905 1900
1906 bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 1901 SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface,
1907 SkPDFDevice::ContentEntry* contentEntry) { 1902 SkScalar textSize,
1908 SkTypeface* typeface = paint.getTypeface(); 1903 uint16_t glyphID,
1904 SkPDFDevice::ContentEntry* contentEntry) {
1909 if (contentEntry->fState.fFont == nullptr || 1905 if (contentEntry->fState.fFont == nullptr ||
1910 contentEntry->fState.fTextSize != paint.getTextSize() || 1906 contentEntry->fState.fTextSize != textSize ||
1911 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 1907 !contentEntry->fState.fFont->hasGlyph(glyphID)) {
1912 int fontIndex = getFontResourceIndex(typeface, glyphID); 1908 int fontIndex = getFontResourceIndex(typeface, glyphID);
1913 if (fontIndex < 0) { 1909 if (fontIndex < 0) {
1914 return false; 1910 SkDebugf("SkPDF: Font error.");
1911 return nullptr;
1915 } 1912 }
1916 contentEntry->fContent.writeText("/"); 1913 contentEntry->fContent.writeText("/");
1917 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 1914 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
1918 SkPDFResourceDict::kFont_ResourceType, 1915 SkPDFResourceDict::kFont_ResourceType,
1919 fontIndex).c_str()); 1916 fontIndex).c_str());
1920 contentEntry->fContent.writeText(" "); 1917 contentEntry->fContent.writeText(" ");
1921 SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent); 1918 SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent);
1922 contentEntry->fContent.writeText(" Tf\n"); 1919 contentEntry->fContent.writeText(" Tf\n");
1923 contentEntry->fState.fFont = fFontResources[fontIndex]; 1920 contentEntry->fState.fFont = fFontResources[fontIndex];
1924 } 1921 }
1925 return true; 1922 return contentEntry->fState.fFont;
1926 } 1923 }
1927 1924
1928 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 1925 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
1929 sk_sp<SkPDFFont> newFont( 1926 sk_sp<SkPDFFont> newFont(
1930 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); 1927 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID));
1931 if (!newFont) { 1928 if (!newFont) {
1932 return -1; 1929 return -1;
1933 } 1930 }
1934 int resourceIndex = fFontResources.find(newFont.get()); 1931 int resourceIndex = fFontResources.find(newFont.get());
1935 if (resourceIndex < 0) { 1932 if (resourceIndex < 0) {
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
2145 } 2142 }
2146 2143
2147 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { 2144 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
2148 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), 2145 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()),
2149 image->makeNonTextureImage()); 2146 image->makeNonTextureImage());
2150 } 2147 }
2151 2148
2152 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { 2149 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
2153 return nullptr; 2150 return nullptr;
2154 } 2151 }
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