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

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

Issue 2241683005: SkPDF: unify drawText and drawPosText (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: compile on win Created 4 years, 4 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 // Stolen from measure_text in SkDraw.cpp and then tweaked.
80 static void align_text(const SkPaint& paint,
81 const uint16_t* glyphs, size_t len,
82 SkScalar* x, SkScalar* y) {
83 if (paint.getTextAlign() == SkPaint::kLeft_Align) {
84 return;
85 }
86 SkScalar advance = paint.measureText(glyphs, len * sizeof(uint16_t));
87 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
88 advance *= 0.5f;
89 }
90 if (paint.isVerticalText()) {
91 *y -= advance;
92 } else {
93 *x -= advance;
94 }
95 }
96
97 static int max_glyphid_for_typeface(SkTypeface* typeface) {
98 SkAutoResolveDefaultTypeface autoResolve(typeface);
99 typeface = autoResolve.get();
100 return typeface->countGlyphs() - 1;
101 }
102
103 typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage;
104
105 static int force_glyph_encoding(const SkPaint& paint, const void* text,
106 size_t len, SkGlyphStorage* storage,
107 const uint16_t** glyphIDs) {
108 // Make sure we have a glyph id encoding.
109 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
110 int numGlyphs = paint.textToGlyphs(text, len, nullptr);
111 storage->reset(numGlyphs);
112 paint.textToGlyphs(text, len, storage->get());
113 *glyphIDs = storage->get();
114 return numGlyphs;
115 }
116
117 // For user supplied glyph ids we need to validate them.
118 SkASSERT((len & 1) == 0);
119 int numGlyphs = SkToInt(len / 2);
120 const uint16_t* input = static_cast<const uint16_t*>(text);
121
122 int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface());
123 int validated;
124 for (validated = 0; validated < numGlyphs; ++validated) {
125 if (input[validated] > maxGlyphID) {
126 break;
127 }
128 }
129 if (validated >= numGlyphs) {
130 *glyphIDs = static_cast<const uint16_t*>(text);
131 return numGlyphs;
132 }
133
134 // Silently drop anything out of range.
135 storage->reset(numGlyphs);
136 if (validated > 0) {
137 memcpy(storage->get(), input, validated * sizeof(uint16_t));
138 }
139
140 for (int i = validated; i < numGlyphs; ++i) {
141 storage->get()[i] = input[i];
142 if (input[i] > maxGlyphID) {
143 storage->get()[i] = 0;
144 }
145 }
146 *glyphIDs = storage->get();
147 return numGlyphs;
148 }
149
150 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, 79 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
151 SkWStream* content) { 80 SkWStream* content) {
152 // Flip the text about the x-axis to account for origin swap and include 81 // Flip the text about the x-axis to account for origin swap and include
153 // the passed parameters. 82 // the passed parameters.
154 content->writeText("1 0 "); 83 content->writeText("1 0 ");
155 SkPDFUtils::AppendScalar(0 - textSkewX, content); 84 SkPDFUtils::AppendScalar(0 - textSkewX, content);
156 content->writeText(" -1 "); 85 content->writeText(" -1 ");
157 SkPDFUtils::AppendScalar(x, content); 86 SkPDFUtils::AppendScalar(x, content);
158 content->writeText(" "); 87 content->writeText(" ");
159 SkPDFUtils::AppendScalar(y, content); 88 SkPDFUtils::AppendScalar(y, content);
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 949
1021 void SkPDFDevice::drawImageRect(const SkDraw& draw, 950 void SkPDFDevice::drawImageRect(const SkDraw& draw,
1022 const SkImage* image, 951 const SkImage* image,
1023 const SkRect* src, 952 const SkRect* src,
1024 const SkRect& dst, 953 const SkRect& dst,
1025 const SkPaint& srcPaint, 954 const SkPaint& srcPaint,
1026 SkCanvas::SrcRectConstraint constraint) { 955 SkCanvas::SrcRectConstraint constraint) {
1027 SkASSERT(false); 956 SkASSERT(false);
1028 } 957 }
1029 958
1030 // Create a PDF string. Maximum length (in bytes) is 65,535.
1031 // @param input A string value.
1032 // @param len The length of the input array.
1033 // @param wideChars True iff the upper byte in each uint16_t is
1034 // significant and should be encoded and not
1035 // discarded. If true, the upper byte is encoded
1036 // first. Otherwise, we assert the upper byte is
1037 // zero.
1038 static void write_wide_string(SkDynamicMemoryWStream* wStream,
1039 const uint16_t* input,
1040 size_t len,
1041 bool wideChars) {
1042 if (wideChars) {
1043 SkASSERT(2 * len < 65535);
1044 wStream->writeText("<");
1045 for (size_t i = 0; i < len; i++) {
1046 SkPDFUtils::WriteUInt16BE(wStream, input[i]);
1047 }
1048 wStream->writeText(">");
1049 } else {
1050 SkASSERT(len <= 65535);
1051 SkAutoMalloc buffer(len); // Remove every other byte.
1052 uint8_t* ptr = (uint8_t*)buffer.get();
1053 for (size_t i = 0; i < len; i++) {
1054 SkASSERT(0 == input[i] >> 8);
1055 ptr[i] = static_cast<uint8_t>(input[i]);
1056 }
1057 SkPDFUtils::WriteString(wStream, (char*)buffer.get(), len);
1058 }
1059 }
1060
1061 namespace { 959 namespace {
1062 class GlyphPositioner { 960 class GlyphPositioner {
1063 public: 961 public:
1064 GlyphPositioner(SkDynamicMemoryWStream* content, 962 GlyphPositioner(SkDynamicMemoryWStream* content,
1065 SkScalar textSkewX, 963 SkScalar textSkewX,
1066 bool wideChars) 964 bool wideChars,
965 bool defaultPositioning,
966 SkPoint origin)
1067 : fContent(content) 967 : fContent(content)
1068 , fCurrentMatrixX(0.0f) 968 , fCurrentMatrixX(0.0f)
1069 , fCurrentMatrixY(0.0f) 969 , fCurrentMatrixY(0.0f)
1070 , fXAdvance(0.0f) 970 , fXAdvance(0.0f)
1071 , fWideChars(wideChars) 971 , fWideChars(wideChars)
1072 , fInText(false) { 972 , fInText(false)
1073 set_text_transform(0.0f, 0.0f, textSkewX, fContent); 973 , fDefaultPositioning(defaultPositioning) {
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent);
1074 } 975 }
1075 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } 976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ }
1076 void flush() { 977 void flush() {
1077 if (fInText) { 978 if (fInText) {
1078 fContent->writeText("> Tj\n"); 979 fContent->writeText("> Tj\n");
1079 fInText = false; 980 fInText = false;
1080 } 981 }
1081 } 982 }
1082 void setWideChars(bool wideChars) { 983 void setWideChars(bool wideChars) {
1083 if (fWideChars != wideChars) { 984 if (fWideChars != wideChars) {
1084 SkASSERT(!fInText); 985 SkASSERT(!fInText);
986 SkASSERT(fWideChars == wideChars);
1085 fWideChars = wideChars; 987 fWideChars = wideChars;
1086 } 988 }
1087 } 989 }
1088 void writeGlyph(SkScalar x, 990 void writeGlyph(SkScalar x,
1089 SkScalar y, 991 SkScalar y,
1090 SkScalar advanceWidth, 992 SkScalar advanceWidth,
1091 uint16_t glyph) { 993 uint16_t glyph) {
1092 SkScalar xPosition = x - fCurrentMatrixX; 994 if (!fDefaultPositioning) {
1093 SkScalar yPosition = y - fCurrentMatrixY; 995 SkScalar xPosition = x - fCurrentMatrixX;
1094 if (xPosition != fXAdvance || yPosition != 0) { 996 SkScalar yPosition = y - fCurrentMatrixY;
1095 this->flush(); 997 if (xPosition != fXAdvance || yPosition != 0) {
1096 SkPDFUtils::AppendScalar(xPosition, fContent); 998 this->flush();
1097 fContent->writeText(" "); 999 SkPDFUtils::AppendScalar(xPosition, fContent);
1098 SkPDFUtils::AppendScalar(-yPosition, fContent); 1000 fContent->writeText(" ");
1099 fContent->writeText(" Td "); 1001 SkPDFUtils::AppendScalar(-yPosition, fContent);
1100 fCurrentMatrixX = x; 1002 fContent->writeText(" Td ");
1101 fCurrentMatrixY = y; 1003 fCurrentMatrixX = x;
1102 fXAdvance = 0; 1004 fCurrentMatrixY = y;
1005 fXAdvance = 0;
1006 }
1007 fXAdvance += advanceWidth;
1103 } 1008 }
1104 if (!fInText) { 1009 if (!fInText) {
1105 fContent->writeText("<"); 1010 fContent->writeText("<");
1106 fInText = true; 1011 fInText = true;
1107 } 1012 }
1108 if (fWideChars) { 1013 if (fWideChars) {
1109 SkPDFUtils::WriteUInt16BE(fContent, glyph); 1014 SkPDFUtils::WriteUInt16BE(fContent, glyph);
1110 } else { 1015 } else {
1111 SkASSERT(0 == glyph >> 8); 1016 SkASSERT(0 == glyph >> 8);
1112 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); 1017 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph));
1113 } 1018 }
1114 fXAdvance += advanceWidth;
1115 } 1019 }
1116 1020
1117 private: 1021 private:
1118 SkDynamicMemoryWStream* fContent; 1022 SkDynamicMemoryWStream* fContent;
1119 SkScalar fCurrentMatrixX; 1023 SkScalar fCurrentMatrixX;
1120 SkScalar fCurrentMatrixY; 1024 SkScalar fCurrentMatrixY;
1121 SkScalar fXAdvance; 1025 SkScalar fXAdvance;
1122 bool fWideChars; 1026 bool fWideChars;
1123 bool fInText; 1027 bool fInText;
1028 const bool fDefaultPositioning;
1124 }; 1029 };
1125 } // namespace 1030 } // namespace
1126 1031
1127 static void draw_transparent_text(SkPDFDevice* device, 1032 static void draw_transparent_text(SkPDFDevice* device,
1128 const SkDraw& d, 1033 const SkDraw& d,
1129 const void* text, size_t len, 1034 const void* text, size_t len,
1130 SkScalar x, SkScalar y, 1035 SkScalar x, SkScalar y,
1131 const SkPaint& srcPaint) { 1036 const SkPaint& srcPaint) {
1132 1037
1133 SkPaint transparent; 1038 SkPaint transparent;
1134 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), 1039 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(),
1135 device->getCanon())) { 1040 device->getCanon())) {
1136 SkDEBUGFAIL("default typeface should be embeddable"); 1041 SkDEBUGFAIL("default typeface should be embeddable");
1137 return; // Avoid infinite loop in release. 1042 return; // Avoid infinite loop in release.
1138 } 1043 }
1139 transparent.setTextSize(srcPaint.getTextSize()); 1044 transparent.setTextSize(srcPaint.getTextSize());
1140 transparent.setColor(SK_ColorTRANSPARENT); 1045 transparent.setColor(SK_ColorTRANSPARENT);
1141 switch (srcPaint.getTextEncoding()) { 1046 switch (srcPaint.getTextEncoding()) {
1142 case SkPaint::kGlyphID_TextEncoding: { 1047 case SkPaint::kGlyphID_TextEncoding: {
1143 // Since a glyphId<->Unicode mapping is typeface-specific, 1048 // Since a glyphId<->Unicode mapping is typeface-specific,
1144 // map back to Unicode first. 1049 // map back to Unicode first.
1145 size_t glyphCount = len / 2; 1050 size_t glyphCount = len / 2;
1146 SkAutoTMalloc<SkUnichar> unichars(glyphCount); 1051 SkAutoTMalloc<SkUnichar> unichars(glyphCount);
1147 srcPaint.glyphsToUnichars( 1052 srcPaint.glyphsToUnichars(
1148 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); 1053 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]);
1149 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); 1054 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding);
1055 // TODO(halcanary): deal with case where default typeface
1056 // does not have glyphs for these unicode code points.
1150 device->drawText(d, &unichars[0], 1057 device->drawText(d, &unichars[0],
1151 glyphCount * sizeof(SkUnichar), 1058 glyphCount * sizeof(SkUnichar),
1152 x, y, transparent); 1059 x, y, transparent);
1153 break; 1060 break;
1154 } 1061 }
1155 case SkPaint::kUTF8_TextEncoding: 1062 case SkPaint::kUTF8_TextEncoding:
1156 case SkPaint::kUTF16_TextEncoding: 1063 case SkPaint::kUTF16_TextEncoding:
1157 case SkPaint::kUTF32_TextEncoding: 1064 case SkPaint::kUTF32_TextEncoding:
1158 transparent.setTextEncoding(srcPaint.getTextEncoding()); 1065 transparent.setTextEncoding(srcPaint.getTextEncoding());
1159 device->drawText(d, text, len, x, y, transparent); 1066 device->drawText(d, text, len, x, y, transparent);
1160 break; 1067 break;
1161 default: 1068 default:
1162 SkFAIL("unknown text encoding"); 1069 SkFAIL("unknown text encoding");
1163 } 1070 }
1164 } 1071 }
1165 1072
1166 1073 void SkPDFDevice::drawTextInternal(
1167 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1074 const SkDraw& d, const void* sourceText, size_t sourceByteCount,
1168 SkScalar x, SkScalar y, const SkPaint& srcPaint) { 1075 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
1169 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fDocument->canon()) ) { 1076 SkPoint offset, const SkPaint& srcPaint) {
1170 // https://bug.skia.org/3866 1077 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false);
1171 SkPath path; 1078 if (srcPaint.getMaskFilter() != nullptr) {
1172 srcPaint.getTextPath(text, len, x, y, &path);
1173 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
1174 // Draw text transparently to make it copyable/searchable/accessable.
1175 draw_transparent_text(this, d, text, len, x, y, srcPaint);
1176 return;
1177 }
1178 SkPaint paint = srcPaint;
1179 replace_srcmode_on_opaque_paint(&paint);
1180
1181 NOT_IMPLEMENTED(paint.getMaskFilter() != nullptr, false);
1182 if (paint.getMaskFilter() != nullptr) {
1183 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1079 // Don't pretend we support drawing MaskFilters, it makes for artifacts
1184 // making text unreadable (e.g. same text twice when using CSS shadows). 1080 // making text unreadable (e.g. same text twice when using CSS shadows).
1185 return; 1081 return;
1186 } 1082 }
1187 SkPaint textPaint = calculate_text_paint(paint); 1083 SkPaint paint = calculate_text_paint(srcPaint);
1188 ScopedContentEntry content(this, d, textPaint, true); 1084 replace_srcmode_on_opaque_paint(&paint);
1085 if (!paint.getTypeface()) {
1086 paint.setTypeface(SkTypeface::MakeDefault());
1087 }
1088 SkTypeface* typeface = paint.getTypeface();
1089 SkASSERT(typeface);
1090 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) {
1091 SkPath path; // https://bug.skia.org/3866
1092 paint.getTextPath(sourceText, sourceByteCount,
1093 offset.x(), offset.y(), &path);
1094 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
1095 // Draw text transparently to make it copyable/searchable/accessable.
1096 draw_transparent_text(this, d, sourceText, sourceByteCount,
1097 offset.x(), offset.y(), paint);
1098 return;
1099 }
1100 // Always make a copy (1) to validate user-input glyphs and
1101 // (2) because we may modify the glyphs in place (for
1102 // single-byte-glyph-id PDF fonts).
1103 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
1104 if (glyphCount <= 0) { return; }
1105 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount));
1106 SkGlyphID* glyphs = glyphStorage.get();
1107 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs);
1108 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
1109 // Validate user-input glyphs.
1110 SkGlyphID maxGlyphID = SkToU16(typeface->countGlyphs() - 1);
1111 for (int i = 0; i < glyphCount; ++i) {
1112 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]);
1113 }
1114 } else {
1115 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
1116 }
1117
1118 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
1119 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr);
1120
1121 SkPaint::Align alignment = paint.getTextAlign();
1122 bool verticalText = paint.isVerticalText();
1123 if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
1124 SkScalar advance{0};
1125 for (int i = 0; i < glyphCount; ++i) {
1126 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
1127 }
1128 SkScalar m = alignment == SkPaint::kCenter_Align
1129 ? 0.5f * advance : advance;
1130 offset -= verticalText ? SkPoint{0, m} : SkPoint{m, 0};
1131 }
1132 ScopedContentEntry content(this, d, paint, true);
1189 if (!content.entry()) { 1133 if (!content.entry()) {
1190 return; 1134 return;
1191 } 1135 }
1136 SkDynamicMemoryWStream* out = &content.entry()->fContent;
1137 out->writeText("BT\n");
1138 if (!this->updateFont(paint, glyphs[0], content.entry())) {
1139 SkDebugf("SkPDF: Font error.");
1140 out->writeText("ET\n%SkPDF: Font error.\n");
1141 return;
1142 }
1143 SkPDFFont* font = content.entry()->fState.fFont;
1144 int scalarsPerPos = (int)positioning;
1145 SkASSERT(scalarsPerPos >= 0 && scalarsPerPos <= 2);
1146 GlyphPositioner glyphPositioner(out,
1147 paint.getTextSkewX(),
1148 font->multiByteGlyphs(),
1149 defaultPositioning,
1150 offset);
1151 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage();
1152 const SkGlyphID* const glyphsEnd = glyphs + glyphCount;
1192 1153
1193 SkGlyphStorage storage(0); 1154 while (glyphs < glyphsEnd) {
1194 const uint16_t* glyphIDs = nullptr; 1155 font = content.entry()->fState.fFont;
1195 int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); 1156 int stretch = font->multiByteGlyphs()
1196 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1157 ? SkToInt(glyphsEnd - glyphs)
1158 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly phs));
1159 SkASSERT(glyphs + stretch <= glyphsEnd);
1160 if (stretch < 1) {
1161 SkASSERT(!font->multiByteGlyphs());
1162 // The current pdf font cannot encode the next glyph.
1163 // Try to get a pdf font which can encode the next glyph.
1164 glyphPositioner.flush();
1165 if (!this->updateFont(paint, *glyphs, content.entry())) {
1166 SkDebugf("SkPDF: Font error.");
1167 out->writeText("ET\n%SkPDF: Font error.\n");
1168 return;
1169 }
1170 font = content.entry()->fState.fFont;
1171 glyphPositioner.setWideChars(font->multiByteGlyphs());
1172 // try again
1173 stretch = font->glyphsToPDFFontEncodingCount(glyphs,
1174 SkToInt(glyphsEnd - gly phs));
1175 if (stretch < 1) {
1176 SkDEBUGFAIL("PDF could not encode glyph.");
1177 glyphPositioner.flush();
1178 out->writeText("ET\n%SkPDF: Font encoding error.\n");
1179 return;
1180 }
1181 }
1182 fontGlyphUsage->noteGlyphUsage(font, glyphs, stretch);
1183 if (defaultPositioning) {
1184 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp hs));
1185 while (stretch-- > 0) {
1186 glyphPositioner.writeGlyph(0, 0, 0, *glyphs);
1187 ++glyphs;
1188 }
1189 } else {
1190 while (stretch-- > 0) {
1191 SkScalar advance = glyphCache->getGlyphIDAdvance(*glyphs).fAdvan ceX;
1192 SkScalar x = *pos++; // evaluate x and y in order!
1193 SkScalar y = 2 == scalarsPerPos ? *pos++ : 0;
bungeman-skia 2016/08/15 17:03:37 This is apparently the only place this 'scalarsPer
hal.canary 2016/08/15 18:14:22 Done. I was using it for direct indexing into the
1194 SkPoint xy{x, y};
1195 if (alignment != SkPaint::kLeft_Align) {
1196 SkScalar m = alignment == SkPaint::kCenter_Align
1197 ? 0.5f * advance : advance;
1198 xy -= verticalText ? SkPoint{0, m} : SkPoint{m, 0};
1199 }
1200 (void)font->glyphsToPDFFontEncoding(glyphs, 1);
1201 glyphPositioner.writeGlyph(xy.x(), xy.y(), advance, *glyphs);
1202 ++glyphs;
1203 }
1204 }
1205 }
1206 glyphPositioner.flush();
1207 out->writeText("ET\n");
1208 }
1197 1209
1198 align_text(textPaint, glyphIDs, numGlyphs, &x, &y); 1210 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
1199 content.entry()->fContent.writeText("BT\n"); 1211 SkScalar x, SkScalar y, const SkPaint& paint) {
1200 set_text_transform(x, y, textPaint.getTextSkewX(), 1212 this->drawTextInternal(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng,
1201 &content.entry()->fContent); 1213 SkPoint{x, y}, paint);
1202 int consumedGlyphCount = 0;
1203
1204 SkTDArray<uint16_t> glyphIDsCopy(glyphIDs, numGlyphs);
1205
1206 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage();
1207
1208 while (numGlyphs > consumedGlyphCount) {
1209 if (!this->updateFont(textPaint, glyphIDs[consumedGlyphCount], content.e ntry())) {
1210 SkDebugf("SkPDF: Font error.");
1211 content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n");
1212 return;
1213 }
1214 SkPDFFont* font = content.entry()->fState.fFont;
1215
1216 int availableGlyphs = font->glyphsToPDFFontEncoding(
1217 glyphIDsCopy.begin() + consumedGlyphCount,
1218 numGlyphs - consumedGlyphCount);
1219 fontGlyphUsage->noteGlyphUsage(
1220 font, glyphIDsCopy.begin() + consumedGlyphCount,
1221 availableGlyphs);
1222 write_wide_string(&content.entry()->fContent,
1223 glyphIDsCopy.begin() + consumedGlyphCount,
1224 availableGlyphs, font->multiByteGlyphs());
1225 consumedGlyphCount += availableGlyphs;
1226 content.entry()->fContent.writeText(" Tj\n");
1227 }
1228 content.entry()->fContent.writeText("ET\n");
1229 } 1214 }
1230 1215
1231 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1216 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
1232 const SkScalar pos[], int scalarsPerPos, 1217 const SkScalar pos[], int scalarsPerPos,
1233 const SkPoint& offset, const SkPaint& srcPaint) { 1218 const SkPoint& offset, const SkPaint& paint) {
1234 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fDocument->canon()) ) { 1219 this->drawTextInternal(d, text, len, pos, (SkTextBlob::GlyphPositioning)scal arsPerPos,
bungeman-skia 2016/08/15 17:03:37 ugly cast, and then 'uncast' in the callee.
hal.canary 2016/08/15 18:14:22 I agree. But this will work nicely with SkDevice:
1235 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pos); 1220 offset, paint);
1236 SkAutoTMalloc<SkPoint> positionsBuffer;
1237 if (2 != scalarsPerPos) {
1238 int glyphCount = srcPaint.textToGlyphs(text, len, NULL);
1239 positionsBuffer.reset(glyphCount);
1240 for (int i = 0; i < glyphCount; ++i) {
1241 positionsBuffer[i].set(pos[i], 0.0f);
1242 }
1243 positions = &positionsBuffer[0];
1244 }
1245 SkPath path;
1246 srcPaint.getPosTextPath(text, len, positions, &path);
1247 SkMatrix matrix;
1248 matrix.setTranslate(offset);
1249 this->drawPath(d, path, srcPaint, &matrix, true);
1250 // Draw text transparently to make it copyable/searchable/accessable.
1251 draw_transparent_text(
1252 this, d, text, len, offset.x() + positions[0].x(),
1253 offset.y() + positions[0].y(), srcPaint);
1254 return;
1255 }
1256
1257 SkPaint paint = srcPaint;
1258 replace_srcmode_on_opaque_paint(&paint);
1259
1260 NOT_IMPLEMENTED(paint.getMaskFilter() != nullptr, false);
1261 if (paint.getMaskFilter() != nullptr) {
1262 // Don't pretend we support drawing MaskFilters, it makes for artifacts
1263 // making text unreadable (e.g. same text twice when using CSS shadows).
1264 return;
1265 }
1266 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
1267 SkPaint textPaint = calculate_text_paint(paint);
1268 ScopedContentEntry content(this, d, textPaint, true);
1269 if (!content.entry()) {
1270 return;
1271 }
1272
1273 SkGlyphStorage storage(0);
1274 const uint16_t* glyphIDs = nullptr;
1275 size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphID s);
1276 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
1277 SkAutoGlyphCache autoGlyphCache(textPaint, nullptr, nullptr);
1278
1279 content.entry()->fContent.writeText("BT\n");
1280 if (!this->updateFont(textPaint, glyphIDs[0], content.entry())) {
1281 SkDebugf("SkPDF: Font error.");
1282 content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n");
1283 return;
1284 }
1285 GlyphPositioner glyphPositioner(&content.entry()->fContent,
1286 textPaint.getTextSkewX(),
1287 content.entry()->fState.fFont->multiByteGlyp hs());
1288 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage();
1289 for (size_t i = 0; i < numGlyphs; i++) {
1290 SkPDFFont* font = content.entry()->fState.fFont;
1291 uint16_t encodedValue = glyphIDs[i];
1292 SkScalar advanceWidth = autoGlyphCache->getGlyphIDAdvance(encodedValue). fAdvanceX;
1293 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
1294 // The current pdf font cannot encode the current glyph.
1295 // Try to get a pdf font which can encode the current glyph.
1296 glyphPositioner.flush();
1297 if (!this->updateFont(textPaint, glyphIDs[i], content.entry())) {
1298 SkDebugf("SkPDF: Font error.");
1299 content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n") ;
1300 return;
1301 }
1302 font = content.entry()->fState.fFont;
1303 glyphPositioner.setWideChars(font->multiByteGlyphs());
1304 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
1305 SkDEBUGFAIL("PDF could not encode glyph.");
1306 continue;
1307 }
1308 }
1309 fontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1);
1310 SkScalar x = offset.x() + pos[i * scalarsPerPos];
1311 SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos + 1] : 0);
1312 align_text(textPaint, glyphIDs + i, 1, &x, &y);
1313
1314 glyphPositioner.writeGlyph(x, y, advanceWidth, encodedValue);
1315 }
1316 glyphPositioner.flush(); // Must flush before ending text object.
1317 content.entry()->fContent.writeText("ET\n");
1318 } 1221 }
1319 1222
1320 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, 1223 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
1321 int vertexCount, const SkPoint verts[], 1224 int vertexCount, const SkPoint verts[],
1322 const SkPoint texs[], const SkColor colors[], 1225 const SkPoint texs[], const SkColor colors[],
1323 SkXfermode* xmode, const uint16_t indices[], 1226 SkXfermode* xmode, const uint16_t indices[],
1324 int indexCount, const SkPaint& paint) { 1227 int indexCount, const SkPaint& paint) {
1325 if (d.fRC->isEmpty()) { 1228 if (d.fRC->isEmpty()) {
1326 return; 1229 return;
1327 } 1230 }
(...skipping 923 matching lines...) Expand 10 before | Expand all | Expand 10 after
2251 } 2154 }
2252 2155
2253 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { 2156 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
2254 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), 2157 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()),
2255 image->makeNonTextureImage()); 2158 image->makeNonTextureImage());
2256 } 2159 }
2257 2160
2258 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { 2161 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
2259 return nullptr; 2162 return nullptr;
2260 } 2163 }
OLDNEW
« src/pdf/SkPDFDevice.h ('K') | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698