OLD | NEW |
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 Loading... |
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 Loading... |
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 | |
1133 SkPaint transparent; | 1037 SkPaint transparent; |
1134 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), | 1038 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), |
1135 device->getCanon())) { | 1039 device->getCanon())) { |
1136 SkDEBUGFAIL("default typeface should be embeddable"); | 1040 SkDebugf("SkPDF: default typeface should be embeddable"); |
1137 return; // Avoid infinite loop in release. | 1041 return; // Avoid infinite loop in release. |
1138 } | 1042 } |
1139 transparent.setTextSize(srcPaint.getTextSize()); | 1043 transparent.setTextSize(srcPaint.getTextSize()); |
1140 transparent.setColor(SK_ColorTRANSPARENT); | 1044 transparent.setColor(SK_ColorTRANSPARENT); |
1141 switch (srcPaint.getTextEncoding()) { | 1045 switch (srcPaint.getTextEncoding()) { |
1142 case SkPaint::kGlyphID_TextEncoding: { | 1046 case SkPaint::kGlyphID_TextEncoding: { |
1143 // Since a glyphId<->Unicode mapping is typeface-specific, | 1047 // Since a glyphId<->Unicode mapping is typeface-specific, |
1144 // map back to Unicode first. | 1048 // map back to Unicode first. |
1145 size_t glyphCount = len / 2; | 1049 size_t glyphCount = len / 2; |
1146 SkAutoTMalloc<SkUnichar> unichars(glyphCount); | 1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); |
1147 srcPaint.glyphsToUnichars( | 1051 srcPaint.glyphsToUnichars( |
1148 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); | 1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); |
1149 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); | 1053 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
| 1054 // TODO(halcanary): deal with case where default typeface |
| 1055 // does not have glyphs for these unicode code points. |
1150 device->drawText(d, &unichars[0], | 1056 device->drawText(d, &unichars[0], |
1151 glyphCount * sizeof(SkUnichar), | 1057 glyphCount * sizeof(SkUnichar), |
1152 x, y, transparent); | 1058 x, y, transparent); |
1153 break; | 1059 break; |
1154 } | 1060 } |
1155 case SkPaint::kUTF8_TextEncoding: | 1061 case SkPaint::kUTF8_TextEncoding: |
1156 case SkPaint::kUTF16_TextEncoding: | 1062 case SkPaint::kUTF16_TextEncoding: |
1157 case SkPaint::kUTF32_TextEncoding: | 1063 case SkPaint::kUTF32_TextEncoding: |
1158 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 1064 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
1159 device->drawText(d, text, len, x, y, transparent); | 1065 device->drawText(d, text, len, x, y, transparent); |
1160 break; | 1066 break; |
1161 default: | 1067 default: |
1162 SkFAIL("unknown text encoding"); | 1068 SkFAIL("unknown text encoding"); |
1163 } | 1069 } |
1164 } | 1070 } |
1165 | 1071 |
1166 | 1072 void SkPDFDevice::internalDrawText( |
1167 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1073 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
1168 SkScalar x, SkScalar y, const SkPaint& srcPaint) { | 1074 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
1169 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fDocument->canon())
) { | 1075 SkPoint offset, const SkPaint& srcPaint) { |
1170 // https://bug.skia.org/3866 | 1076 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
1171 SkPath path; | 1077 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 | 1078 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
1184 // 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). |
1185 return; | 1080 return; |
1186 } | 1081 } |
1187 SkPaint textPaint = calculate_text_paint(paint); | 1082 SkPaint paint = calculate_text_paint(srcPaint); |
1188 ScopedContentEntry content(this, d, textPaint, true); | 1083 replace_srcmode_on_opaque_paint(&paint); |
| 1084 if (!paint.getTypeface()) { |
| 1085 paint.setTypeface(SkTypeface::MakeDefault()); |
| 1086 } |
| 1087 SkTypeface* typeface = paint.getTypeface(); |
| 1088 if (!typeface) { |
| 1089 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
| 1090 return; |
| 1091 } |
| 1092 int typefaceGlyphCount = typeface->countGlyphs(); |
| 1093 if (typefaceGlyphCount < 1) { |
| 1094 SkDebugf("SkPDF: SkTypeface has no glyphs.\n"); |
| 1095 return; |
| 1096 } |
| 1097 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
| 1098 SkPath path; // https://bug.skia.org/3866 |
| 1099 paint.getTextPath(sourceText, sourceByteCount, |
| 1100 offset.x(), offset.y(), &path); |
| 1101 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
| 1102 // Draw text transparently to make it copyable/searchable/accessable. |
| 1103 draw_transparent_text(this, d, sourceText, sourceByteCount, |
| 1104 offset.x(), offset.y(), paint); |
| 1105 return; |
| 1106 } |
| 1107 // Always make a copy (1) to validate user-input glyphs and |
| 1108 // (2) because we may modify the glyphs in place (for |
| 1109 // single-byte-glyph-id PDF fonts). |
| 1110 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); |
| 1111 if (glyphCount <= 0) { return; } |
| 1112 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount)); |
| 1113 SkGlyphID* glyphs = glyphStorage.get(); |
| 1114 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs); |
| 1115 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { |
| 1116 // Validate user-input glyphs. |
| 1117 SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1); |
| 1118 for (int i = 0; i < glyphCount; ++i) { |
| 1119 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]); |
| 1120 } |
| 1121 } else { |
| 1122 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 1123 } |
| 1124 |
| 1125 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
| 1126 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
| 1127 |
| 1128 SkPaint::Align alignment = paint.getTextAlign(); |
| 1129 bool verticalText = paint.isVerticalText(); |
| 1130 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
| 1131 SkScalar advance{0}; |
| 1132 for (int i = 0; i < glyphCount; ++i) { |
| 1133 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
| 1134 } |
| 1135 SkScalar m = alignment == SkPaint::kCenter_Align |
| 1136 ? 0.5f * advance : advance; |
| 1137 offset -= verticalText ? SkPoint{0, m} : SkPoint{m, 0}; |
| 1138 } |
| 1139 ScopedContentEntry content(this, d, paint, true); |
1189 if (!content.entry()) { | 1140 if (!content.entry()) { |
1190 return; | 1141 return; |
1191 } | 1142 } |
| 1143 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
| 1144 out->writeText("BT\n"); |
| 1145 if (!this->updateFont(paint, glyphs[0], content.entry())) { |
| 1146 SkDebugf("SkPDF: Font error."); |
| 1147 out->writeText("ET\n%SkPDF: Font error.\n"); |
| 1148 return; |
| 1149 } |
| 1150 SkPDFFont* font = content.entry()->fState.fFont; |
| 1151 GlyphPositioner glyphPositioner(out, |
| 1152 paint.getTextSkewX(), |
| 1153 font->multiByteGlyphs(), |
| 1154 defaultPositioning, |
| 1155 offset); |
| 1156 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage(); |
| 1157 const SkGlyphID* const glyphsEnd = glyphs + glyphCount; |
1192 | 1158 |
1193 SkGlyphStorage storage(0); | 1159 while (glyphs < glyphsEnd) { |
1194 const uint16_t* glyphIDs = nullptr; | 1160 font = content.entry()->fState.fFont; |
1195 int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); | 1161 int stretch = font->multiByteGlyphs() |
1196 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 1162 ? SkToInt(glyphsEnd - glyphs) |
| 1163 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly
phs)); |
| 1164 SkASSERT(glyphs + stretch <= glyphsEnd); |
| 1165 if (stretch < 1) { |
| 1166 SkASSERT(!font->multiByteGlyphs()); |
| 1167 // The current pdf font cannot encode the next glyph. |
| 1168 // Try to get a pdf font which can encode the next glyph. |
| 1169 glyphPositioner.flush(); |
| 1170 if (!this->updateFont(paint, *glyphs, content.entry())) { |
| 1171 SkDebugf("SkPDF: Font error."); |
| 1172 out->writeText("ET\n%SkPDF: Font error.\n"); |
| 1173 return; |
| 1174 } |
| 1175 font = content.entry()->fState.fFont; |
| 1176 glyphPositioner.setWideChars(font->multiByteGlyphs()); |
| 1177 // try again |
| 1178 stretch = font->glyphsToPDFFontEncodingCount(glyphs, |
| 1179 SkToInt(glyphsEnd - gly
phs)); |
| 1180 if (stretch < 1) { |
| 1181 SkDEBUGFAIL("PDF could not encode glyph."); |
| 1182 glyphPositioner.flush(); |
| 1183 out->writeText("ET\n%SkPDF: Font encoding error.\n"); |
| 1184 return; |
| 1185 } |
| 1186 } |
| 1187 fontGlyphUsage->noteGlyphUsage(font, glyphs, stretch); |
| 1188 if (defaultPositioning) { |
| 1189 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp
hs)); |
| 1190 while (stretch-- > 0) { |
| 1191 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); |
| 1192 ++glyphs; |
| 1193 } |
| 1194 } else { |
| 1195 while (stretch-- > 0) { |
| 1196 SkScalar advance = glyphCache->getGlyphIDAdvance(*glyphs).fAdvan
ceX; |
| 1197 SkScalar x = *pos++; |
| 1198 // evaluate x and y in order! |
| 1199 SkScalar y = SkTextBlob::kFull_Positioning == positioning ? *pos
++ : 0; |
| 1200 SkPoint xy{x, y}; |
| 1201 if (alignment != SkPaint::kLeft_Align) { |
| 1202 SkScalar m = alignment == SkPaint::kCenter_Align |
| 1203 ? 0.5f * advance : advance; |
| 1204 xy -= verticalText ? SkPoint{0, m} : SkPoint{m, 0}; |
| 1205 } |
| 1206 (void)font->glyphsToPDFFontEncoding(glyphs, 1); |
| 1207 glyphPositioner.writeGlyph(xy.x(), xy.y(), advance, *glyphs); |
| 1208 ++glyphs; |
| 1209 } |
| 1210 } |
| 1211 } |
| 1212 glyphPositioner.flush(); |
| 1213 out->writeText("ET\n"); |
| 1214 } |
1197 | 1215 |
1198 align_text(textPaint, glyphIDs, numGlyphs, &x, &y); | 1216 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1199 content.entry()->fContent.writeText("BT\n"); | 1217 SkScalar x, SkScalar y, const SkPaint& paint) { |
1200 set_text_transform(x, y, textPaint.getTextSkewX(), | 1218 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, |
1201 &content.entry()->fContent); | 1219 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 } | 1220 } |
1230 | 1221 |
1231 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1222 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
1232 const SkScalar pos[], int scalarsPerPos, | 1223 const SkScalar pos[], int scalarsPerPos, |
1233 const SkPoint& offset, const SkPaint& srcPaint) { | 1224 const SkPoint& offset, const SkPaint& paint) { |
1234 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fDocument->canon())
) { | 1225 this->internalDrawText(d, text, len, pos, (SkTextBlob::GlyphPositioning)scal
arsPerPos, |
1235 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pos); | 1226 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 } | 1227 } |
1319 | 1228 |
1320 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, | 1229 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, |
1321 int vertexCount, const SkPoint verts[], | 1230 int vertexCount, const SkPoint verts[], |
1322 const SkPoint texs[], const SkColor colors[], | 1231 const SkPoint texs[], const SkColor colors[], |
1323 SkXfermode* xmode, const uint16_t indices[], | 1232 SkXfermode* xmode, const uint16_t indices[], |
1324 int indexCount, const SkPaint& paint) { | 1233 int indexCount, const SkPaint& paint) { |
1325 if (d.fRC->isEmpty()) { | 1234 if (d.fRC->isEmpty()) { |
1326 return; | 1235 return; |
1327 } | 1236 } |
(...skipping 923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2251 } | 2160 } |
2252 | 2161 |
2253 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2162 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2254 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2163 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
2255 image->makeNonTextureImage()); | 2164 image->makeNonTextureImage()); |
2256 } | 2165 } |
2257 | 2166 |
2258 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2167 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2259 return nullptr; | 2168 return nullptr; |
2260 } | 2169 } |
OLD | NEW |