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

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: major refactor 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
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 920 matching lines...) Expand 10 before | Expand all | Expand 10 after
966 SkPoint origin) 965 SkPoint origin)
967 : fContent(content) 966 : fContent(content)
968 , fCurrentMatrixX(0.0f) 967 , fCurrentMatrixX(0.0f)
969 , fCurrentMatrixY(0.0f) 968 , fCurrentMatrixY(0.0f)
970 , fXAdvance(0.0f) 969 , fXAdvance(0.0f)
971 , fWideChars(wideChars) 970 , fWideChars(wideChars)
972 , fInText(false) 971 , fInText(false)
973 , fDefaultPositioning(defaultPositioning) { 972 , fDefaultPositioning(defaultPositioning) {
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); 973 set_text_transform(origin.x(), origin.y(), textSkewX, fContent);
975 } 974 }
976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } 975 ~GlyphPositioner() {this->flush(); }
bungeman-skia 2016/08/25 19:28:43 nit: probably want a space between '{' and 'this'.
hal.canary 2016/08/26 15:27:03 Done. And removed the extra space before '}'
977 void flush() { 976 void flush() {
978 if (fInText) { 977 if (fInText) {
979 fContent->writeText("> Tj\n"); 978 fContent->writeText("> Tj\n");
980 fInText = false; 979 fInText = false;
981 } 980 }
982 } 981 }
983 void setWideChars(bool wideChars) { 982 void setWideChars(bool wideChars) {
984 if (fWideChars != wideChars) { 983 if (fWideChars != wideChars) {
985 SkASSERT(!fInText); 984 SkASSERT(!fInText);
986 SkASSERT(fWideChars == wideChars); 985 SkASSERT(fWideChars == wideChars);
987 fWideChars = wideChars; 986 fWideChars = wideChars;
988 } 987 }
989 } 988 }
990 void writeGlyph(SkScalar x, 989 void writeGlyph(SkPoint xy,
991 SkScalar y,
992 SkScalar advanceWidth, 990 SkScalar advanceWidth,
993 uint16_t glyph) { 991 uint16_t glyph) {
994 if (!fDefaultPositioning) { 992 if (!fDefaultPositioning) {
995 SkScalar xPosition = x - fCurrentMatrixX; 993 SkScalar xPosition = xy.x() - fCurrentMatrixX;
996 SkScalar yPosition = y - fCurrentMatrixY; 994 SkScalar yPosition = xy.y() - fCurrentMatrixY;
bungeman-skia 2016/08/25 19:28:43 This handling seems almost painful to read. Is the
hal.canary 2016/08/26 15:27:03 Excellent point. Done. I also used SkPoint::oper
997 if (xPosition != fXAdvance || yPosition != 0) { 995 if (xPosition != fXAdvance || yPosition != 0) {
998 this->flush(); 996 this->flush();
999 SkPDFUtils::AppendScalar(xPosition, fContent); 997 SkPDFUtils::AppendScalar(xPosition, fContent);
1000 fContent->writeText(" "); 998 fContent->writeText(" ");
1001 SkPDFUtils::AppendScalar(-yPosition, fContent); 999 SkPDFUtils::AppendScalar(-yPosition, fContent);
1002 fContent->writeText(" Td "); 1000 fContent->writeText(" Td ");
1003 fCurrentMatrixX = x; 1001 fCurrentMatrixX = xy.x();
1004 fCurrentMatrixY = y; 1002 fCurrentMatrixY = xy.y();
1005 fXAdvance = 0; 1003 fXAdvance = 0;
1006 } 1004 }
1007 fXAdvance += advanceWidth; 1005 fXAdvance += advanceWidth;
1008 } 1006 }
1009 if (!fInText) { 1007 if (!fInText) {
1010 fContent->writeText("<"); 1008 fContent->writeText("<");
1011 fInText = true; 1009 fInText = true;
1012 } 1010 }
1013 if (fWideChars) { 1011 if (fWideChars) {
1014 SkPDFUtils::WriteUInt16BE(fContent, glyph); 1012 SkPDFUtils::WriteUInt16BE(fContent, glyph);
(...skipping 12 matching lines...) Expand all
1027 bool fInText; 1025 bool fInText;
1028 const bool fDefaultPositioning; 1026 const bool fDefaultPositioning;
1029 }; 1027 };
1030 } // namespace 1028 } // namespace
1031 1029
1032 static void draw_transparent_text(SkPDFDevice* device, 1030 static void draw_transparent_text(SkPDFDevice* device,
1033 const SkDraw& d, 1031 const SkDraw& d,
1034 const void* text, size_t len, 1032 const void* text, size_t len,
1035 SkScalar x, SkScalar y, 1033 SkScalar x, SkScalar y,
1036 const SkPaint& srcPaint) { 1034 const SkPaint& srcPaint) {
1037 SkPaint transparent; 1035 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault();
1038 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), 1036 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(),
1039 device->getCanon())) { 1037 device->getCanon())) {
bungeman-skia 2016/08/25 19:28:43 nit: Since you're touching this line anyway, will
hal.canary 2016/08/26 15:27:03 Done.
1040 SkDebugf("SkPDF: default typeface should be embeddable"); 1038 SkDebugf("SkPDF: default typeface should be embeddable");
1041 return; // Avoid infinite loop in release. 1039 return; // Avoid infinite loop in release.
1042 } 1040 }
1041 SkPaint transparent;
1042 transparent.setTypeface(std::move(defaultFace));
1043 transparent.setTextSize(srcPaint.getTextSize()); 1043 transparent.setTextSize(srcPaint.getTextSize());
1044 transparent.setColor(SK_ColorTRANSPARENT); 1044 transparent.setColor(SK_ColorTRANSPARENT);
1045 switch (srcPaint.getTextEncoding()) { 1045 switch (srcPaint.getTextEncoding()) {
1046 case SkPaint::kGlyphID_TextEncoding: { 1046 case SkPaint::kGlyphID_TextEncoding: {
1047 // Since a glyphId<->Unicode mapping is typeface-specific, 1047 // Since a glyphId<->Unicode mapping is typeface-specific,
1048 // map back to Unicode first. 1048 // map back to Unicode first.
1049 size_t glyphCount = len / 2; 1049 size_t glyphCount = len / 2;
1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); 1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount);
1051 srcPaint.glyphsToUnichars( 1051 srcPaint.glyphsToUnichars(
1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); 1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]);
1053 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); 1053 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding);
1054 // TODO(halcanary): deal with case where default typeface 1054 // TODO(halcanary): deal with case where default typeface
1055 // does not have glyphs for these unicode code points. 1055 // does not have glyphs for these unicode code points.
1056 device->drawText(d, &unichars[0], 1056 device->drawText(d, &unichars[0],
1057 glyphCount * sizeof(SkUnichar), 1057 glyphCount * sizeof(SkUnichar),
1058 x, y, transparent); 1058 x, y, transparent);
1059 break; 1059 break;
1060 } 1060 }
1061 case SkPaint::kUTF8_TextEncoding: 1061 case SkPaint::kUTF8_TextEncoding:
1062 case SkPaint::kUTF16_TextEncoding: 1062 case SkPaint::kUTF16_TextEncoding:
1063 case SkPaint::kUTF32_TextEncoding: 1063 case SkPaint::kUTF32_TextEncoding:
1064 transparent.setTextEncoding(srcPaint.getTextEncoding()); 1064 transparent.setTextEncoding(srcPaint.getTextEncoding());
1065 device->drawText(d, text, len, x, y, transparent); 1065 device->drawText(d, text, len, x, y, transparent);
1066 break; 1066 break;
1067 default: 1067 default:
1068 SkFAIL("unknown text encoding"); 1068 SkFAIL("unknown text encoding");
1069 } 1069 }
1070 } 1070 }
1071 1071
1072 namespace {
1073 struct TextObject {
1074 SkDynamicMemoryWStream* fOut;
1075 TextObject(SkDynamicMemoryWStream* out) : fOut(out) { fOut->writeText("BT\n" ); }
1076 ~TextObject() { fOut->writeText("ET\n"); }
1077 };
1078 } // namespace
bungeman-skia 2016/08/25 19:28:43 It seems that this struct is only used by internal
hal.canary 2016/08/26 15:27:03 Done.
1079
1080 static int get_stretch(SkPDFFont* font, const SkGlyphID* glyphs, int index,
1081 int glyphCount, SkGlyphID maxGlyphID, bool multiByte) {
1082 SkASSERT(font);
1083 return multiByte ? glyphCount - index
1084 : font->countStretch(&glyphs[index], glyphCount - index , maxGlyphID);
1085 }
1086
1072 void SkPDFDevice::internalDrawText( 1087 void SkPDFDevice::internalDrawText(
1073 const SkDraw& d, const void* sourceText, size_t sourceByteCount, 1088 const SkDraw& d, const void* sourceText, size_t sourceByteCount,
1074 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, 1089 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
1075 SkPoint offset, const SkPaint& srcPaint) { 1090 SkPoint offset, const SkPaint& srcPaint) {
1076 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); 1091 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false);
1077 if (srcPaint.getMaskFilter() != nullptr) { 1092 if (srcPaint.getMaskFilter() != nullptr) {
1078 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1093 // Don't pretend we support drawing MaskFilters, it makes for artifacts
1079 // making text unreadable (e.g. same text twice when using CSS shadows). 1094 // making text unreadable (e.g. same text twice when using CSS shadows).
1080 return; 1095 return;
1081 } 1096 }
1082 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); 1097 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false);
1083 if (srcPaint.isVerticalText()) { 1098 if (srcPaint.isVerticalText()) {
1084 // Don't pretend we support drawing vertical text. It is not 1099 // Don't pretend we support drawing vertical text. It is not
1085 // clear to me how to switch to "vertical writing" mode in PDF. 1100 // clear to me how to switch to "vertical writing" mode in PDF.
1086 // Currently neither Chromium or Android set this flag. 1101 // Currently neither Chromium or Android set this flag.
1087 // https://bug.skia.org/5665 1102 // https://bug.skia.org/5665
1088 return; 1103 return;
1089 } 1104 }
1090 SkPaint paint = calculate_text_paint(srcPaint); 1105 SkPaint paint = calculate_text_paint(srcPaint);
1091 replace_srcmode_on_opaque_paint(&paint); 1106 replace_srcmode_on_opaque_paint(&paint);
1092 if (!paint.getTypeface()) { 1107 if (!paint.getTypeface()) {
1093 paint.setTypeface(SkTypeface::MakeDefault()); 1108 paint.setTypeface(SkTypeface::MakeDefault());
1094 } 1109 }
1095 SkTypeface* typeface = paint.getTypeface(); 1110 SkTypeface* typeface = paint.getTypeface();
1096 if (!typeface) { 1111 if (!typeface) {
1097 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); 1112 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
1098 return; 1113 return;
1099 } 1114 }
1100 int typefaceGlyphCount = typeface->countGlyphs(); 1115 SkPDFFont::TypefaceInfo faceInfo = SkPDFFont::GetTypefaceInfo(typeface);
1101 if (typefaceGlyphCount < 1) { 1116 if (!faceInfo.fGood) {
1102 SkDebugf("SkPDF: SkTypeface has no glyphs.\n");
1103 return; 1117 return;
1104 } 1118 }
1119 const SkGlyphID maxGlyphID = faceInfo.fMaxGlyphID;
1105 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { 1120 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) {
1106 SkPath path; // https://bug.skia.org/3866 1121 SkPath path; // https://bug.skia.org/3866
1107 paint.getTextPath(sourceText, sourceByteCount, 1122 paint.getTextPath(sourceText, sourceByteCount,
1108 offset.x(), offset.y(), &path); 1123 offset.x(), offset.y(), &path);
1109 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); 1124 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
1110 // Draw text transparently to make it copyable/searchable/accessable. 1125 // Draw text transparently to make it copyable/searchable/accessable.
1111 draw_transparent_text(this, d, sourceText, sourceByteCount, 1126 draw_transparent_text(this, d, sourceText, sourceByteCount,
1112 offset.x(), offset.y(), paint); 1127 offset.x(), offset.y(), paint);
1113 return; 1128 return;
1114 } 1129 }
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); 1130 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
1119 if (glyphCount <= 0) { return; } 1131 if (glyphCount <= 0) {
1120 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount)); 1132 return;
1121 SkGlyphID* glyphs = glyphStorage.get(); 1133 }
1122 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs); 1134 SkAutoSTMalloc<128, SkGlyphID> glyphStorage;
1135 const SkGlyphID* glyphs = nullptr;
1123 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { 1136 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
1124 // Validate user-input glyphs. 1137 glyphs = (const SkGlyphID*)sourceText;
1125 SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1); 1138 // validate input later.
1126 for (int i = 0; i < glyphCount; ++i) {
1127 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]);
1128 }
1129 } else { 1139 } else {
1140 glyphStorage.reset(SkToSizeT(glyphCount));
1141 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get() );
1142 glyphs = glyphStorage.get();
1130 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1143 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
1131 } 1144 }
1132 1145
1133 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); 1146 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
1134 paint.setHinting(SkPaint::kNo_Hinting); 1147 paint.setHinting(SkPaint::kNo_Hinting);
1135 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); 1148 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr);
1136 1149
1137 SkPaint::Align alignment = paint.getTextAlign(); 1150 SkPaint::Align alignment = paint.getTextAlign();
1151 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f :
1152 SkPaint::kCenter_Align == alignment ? -0.5f :
1153 /* SkPaint::kRight_Align */ -1.0f;
1138 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { 1154 if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
1139 SkScalar advance{0}; 1155 SkScalar advance = 0;
1140 for (int i = 0; i < glyphCount; ++i) { 1156 for (int i = 0; i < glyphCount; ++i) {
1141 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; 1157 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
1142 } 1158 }
1143 SkScalar m = alignment == SkPaint::kCenter_Align 1159 offset.offset(alignmentFactor * advance, 0);
1144 ? 0.5f * advance : advance;
1145 offset -= SkPoint{m, 0};
1146 } 1160 }
1147 ScopedContentEntry content(this, d, paint, true); 1161 ScopedContentEntry content(this, d, paint, true);
1148 if (!content.entry()) { 1162 if (!content.entry()) {
1149 return; 1163 return;
1150 } 1164 }
1151 SkDynamicMemoryWStream* out = &content.entry()->fContent; 1165 SkDynamicMemoryWStream* out = &content.entry()->fContent;
1152 out->writeText("BT\n"); 1166 SkScalar textSize = paint.getTextSize();
1153 if (!this->updateFont(paint, glyphs[0], content.entry())) { 1167 TextObject textObject(out); // Must be in scope for this->updateFont().
bungeman-skia 2016/08/25 19:28:43 I'm not sure this name clearly conveys the side ef
hal.canary 2016/08/26 15:27:03 Done.
1154 SkDebugf("SkPDF: Font error."); 1168 int index = 0;
1155 out->writeText("ET\n%SkPDF: Font error.\n"); 1169 while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font.
1156 return; 1170 ++index; // Skip this glyphID
1171 if (index == glyphCount) {
1172 return; // all glyphIDs were bad.
1173 }
1157 } 1174 }
1158 SkPDFFont* font = content.entry()->fState.fFont; 1175 SkPDFFont* font = this->updateFont(
1176 typeface, textSize, glyphs[index], content.entry());
1177 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met .
1178 if (!font) { return; }
1179
1159 GlyphPositioner glyphPositioner(out, 1180 GlyphPositioner glyphPositioner(out,
1160 paint.getTextSkewX(), 1181 paint.getTextSkewX(),
1161 font->multiByteGlyphs(), 1182 font->multiByteGlyphs(),
1162 defaultPositioning, 1183 defaultPositioning,
1163 offset); 1184 offset);
1164 const SkGlyphID* const glyphsEnd = glyphs + glyphCount;
1165 1185
1166 while (glyphs < glyphsEnd) { 1186 while (index < glyphCount) {
1167 font = content.entry()->fState.fFont; 1187 bool multiByte = font->multiByteGlyphs();
1168 int stretch = font->multiByteGlyphs() 1188 int stretch = get_stretch(font, glyphs, index, glyphCount, maxGlyphID, m ultiByte);
1169 ? SkToInt(glyphsEnd - glyphs) 1189 SkASSERT(index + stretch <= glyphCount);
1170 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly phs));
1171 SkASSERT(glyphs + stretch <= glyphsEnd);
1172 if (stretch < 1) { 1190 if (stretch < 1) {
1173 SkASSERT(!font->multiByteGlyphs()); 1191 SkASSERT(!multiByte);
1174 // The current pdf font cannot encode the next glyph. 1192 // The current pdf font cannot encode the next glyph.
1175 // Try to get a pdf font which can encode the next glyph. 1193 // Try to get a pdf font which can encode the next glyph.
1176 glyphPositioner.flush(); 1194 glyphPositioner.flush();
1177 if (!this->updateFont(paint, *glyphs, content.entry())) { 1195 // first, validate the next glyph
1178 SkDebugf("SkPDF: Font error."); 1196 while (glyphs[index] > maxGlyphID) {
1179 out->writeText("ET\n%SkPDF: Font error.\n"); 1197 ++index; // Skip this glyphID
1180 return; 1198 if (index == glyphCount) {
1199 return; // all remainng glyphIDs were bad.
1200 }
1181 } 1201 }
1182 font = content.entry()->fState.fFont; 1202 SkASSERT(index < glyphCount);
1203 font = this->updateFont(typeface, textSize, glyphs[index], content.e ntry());
1204 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met .
1205 if (!font) { return; }
1183 glyphPositioner.setWideChars(font->multiByteGlyphs()); 1206 glyphPositioner.setWideChars(font->multiByteGlyphs());
1184 // try again 1207 // Get stretch for this new font.
1185 stretch = font->glyphsToPDFFontEncodingCount(glyphs, 1208 stretch = get_stretch(font, glyphs, index, glyphCount, maxGlyphID, f alse);
1186 SkToInt(glyphsEnd - gly phs));
1187 if (stretch < 1) { 1209 if (stretch < 1) {
1188 SkDEBUGFAIL("PDF could not encode glyph."); 1210 SkDEBUGFAIL("PDF could not encode glyph.");
1189 glyphPositioner.flush();
1190 out->writeText("ET\n%SkPDF: Font encoding error.\n");
1191 return; 1211 return;
1192 } 1212 }
1193 } 1213 }
1194 font->noteGlyphUsage(glyphs, stretch); 1214 while (stretch-- > 0) {
1195 if (defaultPositioning) { 1215 SkGlyphID gid = glyphs[index];
1196 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp hs)); 1216 if (gid <= maxGlyphID) {
1197 while (stretch-- > 0) { 1217 font->noteGlyphUsage(gid);
1198 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); 1218 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid);
1199 ++glyphs; 1219 if (defaultPositioning) {
1220 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph);
1221 } else {
1222 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvan ceX;
1223 SkPoint xy = SkTextBlob::kFull_Positioning == positioning
1224 ? SkPoint{pos[2 * index], pos[2 * index + 1]}
1225 : SkPoint{pos[index], 0};
1226 if (alignment != SkPaint::kLeft_Align) {
1227 xy.offset(alignmentFactor * advance, 0);
1228 }
1229 glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
1230 }
1200 } 1231 }
1201 } else { 1232 ++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 } 1233 }
1218 } 1234 }
1219 glyphPositioner.flush();
1220 out->writeText("ET\n");
1221 } 1235 }
1222 1236
1223 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1237 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
1224 SkScalar x, SkScalar y, const SkPaint& paint) { 1238 SkScalar x, SkScalar y, const SkPaint& paint) {
1225 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, 1239 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng,
1226 SkPoint{x, y}, paint); 1240 SkPoint{x, y}, paint);
1227 } 1241 }
1228 1242
1229 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1243 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
1230 const SkScalar pos[], int scalarsPerPos, 1244 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 1910 // Assumes that xobject has been canonicalized (so we can directly compare
1897 // pointers). 1911 // pointers).
1898 int result = fXObjectResources.find(xObject); 1912 int result = fXObjectResources.find(xObject);
1899 if (result < 0) { 1913 if (result < 0) {
1900 result = fXObjectResources.count(); 1914 result = fXObjectResources.count();
1901 fXObjectResources.push(SkRef(xObject)); 1915 fXObjectResources.push(SkRef(xObject));
1902 } 1916 }
1903 return result; 1917 return result;
1904 } 1918 }
1905 1919
1906 bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 1920 SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface,
1907 SkPDFDevice::ContentEntry* contentEntry) { 1921 SkScalar textSize,
1908 SkTypeface* typeface = paint.getTypeface(); 1922 uint16_t glyphID,
1923 SkPDFDevice::ContentEntry* contentEntry) {
1909 if (contentEntry->fState.fFont == nullptr || 1924 if (contentEntry->fState.fFont == nullptr ||
1910 contentEntry->fState.fTextSize != paint.getTextSize() || 1925 contentEntry->fState.fTextSize != textSize ||
1911 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 1926 !contentEntry->fState.fFont->hasGlyph(glyphID)) {
1912 int fontIndex = getFontResourceIndex(typeface, glyphID); 1927 int fontIndex = getFontResourceIndex(typeface, glyphID);
1913 if (fontIndex < 0) { 1928 if (fontIndex < 0) {
1914 return false; 1929 SkDebugf("SkPDF: Font error.");
1930 return nullptr;
1915 } 1931 }
1916 contentEntry->fContent.writeText("/"); 1932 contentEntry->fContent.writeText("/");
1917 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 1933 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
1918 SkPDFResourceDict::kFont_ResourceType, 1934 SkPDFResourceDict::kFont_ResourceType,
1919 fontIndex).c_str()); 1935 fontIndex).c_str());
1920 contentEntry->fContent.writeText(" "); 1936 contentEntry->fContent.writeText(" ");
1921 SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent); 1937 SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent);
1922 contentEntry->fContent.writeText(" Tf\n"); 1938 contentEntry->fContent.writeText(" Tf\n");
1923 contentEntry->fState.fFont = fFontResources[fontIndex]; 1939 contentEntry->fState.fFont = fFontResources[fontIndex];
1924 } 1940 }
1925 return true; 1941 return contentEntry->fState.fFont;
1926 } 1942 }
1927 1943
1928 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 1944 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
1929 sk_sp<SkPDFFont> newFont( 1945 sk_sp<SkPDFFont> newFont(
1930 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); 1946 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID));
1931 if (!newFont) { 1947 if (!newFont) {
1932 return -1; 1948 return -1;
1933 } 1949 }
1934 int resourceIndex = fFontResources.find(newFont.get()); 1950 int resourceIndex = fFontResources.find(newFont.get());
1935 if (resourceIndex < 0) { 1951 if (resourceIndex < 0) {
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
2145 } 2161 }
2146 2162
2147 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { 2163 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
2148 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), 2164 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()),
2149 image->makeNonTextureImage()); 2165 image->makeNonTextureImage());
2150 } 2166 }
2151 2167
2152 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { 2168 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
2153 return nullptr; 2169 return nullptr;
2154 } 2170 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | src/pdf/SkPDFFont.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698