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 |
79 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, | 150 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, |
80 SkWStream* content) { | 151 SkWStream* content) { |
81 // Flip the text about the x-axis to account for origin swap and include | 152 // Flip the text about the x-axis to account for origin swap and include |
82 // the passed parameters. | 153 // the passed parameters. |
83 content->writeText("1 0 "); | 154 content->writeText("1 0 "); |
84 SkPDFUtils::AppendScalar(0 - textSkewX, content); | 155 SkPDFUtils::AppendScalar(0 - textSkewX, content); |
85 content->writeText(" -1 "); | 156 content->writeText(" -1 "); |
86 SkPDFUtils::AppendScalar(x, content); | 157 SkPDFUtils::AppendScalar(x, content); |
87 content->writeText(" "); | 158 content->writeText(" "); |
88 SkPDFUtils::AppendScalar(y, content); | 159 SkPDFUtils::AppendScalar(y, content); |
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 | 1020 |
950 void SkPDFDevice::drawImageRect(const SkDraw& draw, | 1021 void SkPDFDevice::drawImageRect(const SkDraw& draw, |
951 const SkImage* image, | 1022 const SkImage* image, |
952 const SkRect* src, | 1023 const SkRect* src, |
953 const SkRect& dst, | 1024 const SkRect& dst, |
954 const SkPaint& srcPaint, | 1025 const SkPaint& srcPaint, |
955 SkCanvas::SrcRectConstraint constraint) { | 1026 SkCanvas::SrcRectConstraint constraint) { |
956 SkASSERT(false); | 1027 SkASSERT(false); |
957 } | 1028 } |
958 | 1029 |
| 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 |
959 namespace { | 1061 namespace { |
960 class GlyphPositioner { | 1062 class GlyphPositioner { |
961 public: | 1063 public: |
962 GlyphPositioner(SkDynamicMemoryWStream* content, | 1064 GlyphPositioner(SkDynamicMemoryWStream* content, |
963 SkScalar textSkewX, | 1065 SkScalar textSkewX, |
964 bool wideChars, | 1066 bool wideChars) |
965 bool defaultPositioning, | |
966 SkPoint origin) | |
967 : fContent(content) | 1067 : fContent(content) |
968 , fCurrentMatrixX(0.0f) | 1068 , fCurrentMatrixX(0.0f) |
969 , fCurrentMatrixY(0.0f) | 1069 , fCurrentMatrixY(0.0f) |
970 , fXAdvance(0.0f) | 1070 , fXAdvance(0.0f) |
971 , fWideChars(wideChars) | 1071 , fWideChars(wideChars) |
972 , fInText(false) | 1072 , fInText(false) { |
973 , fDefaultPositioning(defaultPositioning) { | 1073 set_text_transform(0.0f, 0.0f, textSkewX, fContent); |
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); | |
975 } | 1074 } |
976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } | 1075 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } |
977 void flush() { | 1076 void flush() { |
978 if (fInText) { | 1077 if (fInText) { |
979 fContent->writeText("> Tj\n"); | 1078 fContent->writeText("> Tj\n"); |
980 fInText = false; | 1079 fInText = false; |
981 } | 1080 } |
982 } | 1081 } |
983 void setWideChars(bool wideChars) { | 1082 void setWideChars(bool wideChars) { |
984 if (fWideChars != wideChars) { | 1083 if (fWideChars != wideChars) { |
985 SkASSERT(!fInText); | 1084 SkASSERT(!fInText); |
986 SkASSERT(fWideChars == wideChars); | |
987 fWideChars = wideChars; | 1085 fWideChars = wideChars; |
988 } | 1086 } |
989 } | 1087 } |
990 void writeGlyph(SkScalar x, | 1088 void writeGlyph(SkScalar x, |
991 SkScalar y, | 1089 SkScalar y, |
992 SkScalar advanceWidth, | 1090 SkScalar advanceWidth, |
993 uint16_t glyph) { | 1091 uint16_t glyph) { |
994 if (!fDefaultPositioning) { | 1092 SkScalar xPosition = x - fCurrentMatrixX; |
995 SkScalar xPosition = x - fCurrentMatrixX; | 1093 SkScalar yPosition = y - fCurrentMatrixY; |
996 SkScalar yPosition = y - fCurrentMatrixY; | 1094 if (xPosition != fXAdvance || yPosition != 0) { |
997 if (xPosition != fXAdvance || yPosition != 0) { | 1095 this->flush(); |
998 this->flush(); | 1096 SkPDFUtils::AppendScalar(xPosition, fContent); |
999 SkPDFUtils::AppendScalar(xPosition, fContent); | 1097 fContent->writeText(" "); |
1000 fContent->writeText(" "); | 1098 SkPDFUtils::AppendScalar(-yPosition, fContent); |
1001 SkPDFUtils::AppendScalar(-yPosition, fContent); | 1099 fContent->writeText(" Td "); |
1002 fContent->writeText(" Td "); | 1100 fCurrentMatrixX = x; |
1003 fCurrentMatrixX = x; | 1101 fCurrentMatrixY = y; |
1004 fCurrentMatrixY = y; | 1102 fXAdvance = 0; |
1005 fXAdvance = 0; | |
1006 } | |
1007 fXAdvance += advanceWidth; | |
1008 } | 1103 } |
1009 if (!fInText) { | 1104 if (!fInText) { |
1010 fContent->writeText("<"); | 1105 fContent->writeText("<"); |
1011 fInText = true; | 1106 fInText = true; |
1012 } | 1107 } |
1013 if (fWideChars) { | 1108 if (fWideChars) { |
1014 SkPDFUtils::WriteUInt16BE(fContent, glyph); | 1109 SkPDFUtils::WriteUInt16BE(fContent, glyph); |
1015 } else { | 1110 } else { |
1016 SkASSERT(0 == glyph >> 8); | 1111 SkASSERT(0 == glyph >> 8); |
1017 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); | 1112 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); |
1018 } | 1113 } |
| 1114 fXAdvance += advanceWidth; |
1019 } | 1115 } |
1020 | 1116 |
1021 private: | 1117 private: |
1022 SkDynamicMemoryWStream* fContent; | 1118 SkDynamicMemoryWStream* fContent; |
1023 SkScalar fCurrentMatrixX; | 1119 SkScalar fCurrentMatrixX; |
1024 SkScalar fCurrentMatrixY; | 1120 SkScalar fCurrentMatrixY; |
1025 SkScalar fXAdvance; | 1121 SkScalar fXAdvance; |
1026 bool fWideChars; | 1122 bool fWideChars; |
1027 bool fInText; | 1123 bool fInText; |
1028 const bool fDefaultPositioning; | |
1029 }; | 1124 }; |
1030 } // namespace | 1125 } // namespace |
1031 | 1126 |
1032 static void draw_transparent_text(SkPDFDevice* device, | 1127 static void draw_transparent_text(SkPDFDevice* device, |
1033 const SkDraw& d, | 1128 const SkDraw& d, |
1034 const void* text, size_t len, | 1129 const void* text, size_t len, |
1035 SkScalar x, SkScalar y, | 1130 SkScalar x, SkScalar y, |
1036 const SkPaint& srcPaint) { | 1131 const SkPaint& srcPaint) { |
1037 | 1132 |
1038 SkPaint transparent; | 1133 SkPaint transparent; |
1039 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), | 1134 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), |
1040 device->getCanon())) { | 1135 device->getCanon())) { |
1041 SkDEBUGFAIL("default typeface should be embeddable"); | 1136 SkDEBUGFAIL("default typeface should be embeddable"); |
1042 return; // Avoid infinite loop in release. | 1137 return; // Avoid infinite loop in release. |
1043 } | 1138 } |
1044 transparent.setTextSize(srcPaint.getTextSize()); | 1139 transparent.setTextSize(srcPaint.getTextSize()); |
1045 transparent.setColor(SK_ColorTRANSPARENT); | 1140 transparent.setColor(SK_ColorTRANSPARENT); |
1046 switch (srcPaint.getTextEncoding()) { | 1141 switch (srcPaint.getTextEncoding()) { |
1047 case SkPaint::kGlyphID_TextEncoding: { | 1142 case SkPaint::kGlyphID_TextEncoding: { |
1048 // Since a glyphId<->Unicode mapping is typeface-specific, | 1143 // Since a glyphId<->Unicode mapping is typeface-specific, |
1049 // map back to Unicode first. | 1144 // map back to Unicode first. |
1050 size_t glyphCount = len / 2; | 1145 size_t glyphCount = len / 2; |
1051 SkAutoTMalloc<SkUnichar> unichars(glyphCount); | 1146 SkAutoTMalloc<SkUnichar> unichars(glyphCount); |
1052 srcPaint.glyphsToUnichars( | 1147 srcPaint.glyphsToUnichars( |
1053 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); | 1148 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); |
1054 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); | 1149 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
1055 // TODO(halcanary): deal with case where default typeface | |
1056 // does not have glyphs for these unicode code points. | |
1057 device->drawText(d, &unichars[0], | 1150 device->drawText(d, &unichars[0], |
1058 glyphCount * sizeof(SkUnichar), | 1151 glyphCount * sizeof(SkUnichar), |
1059 x, y, transparent); | 1152 x, y, transparent); |
1060 break; | 1153 break; |
1061 } | 1154 } |
1062 case SkPaint::kUTF8_TextEncoding: | 1155 case SkPaint::kUTF8_TextEncoding: |
1063 case SkPaint::kUTF16_TextEncoding: | 1156 case SkPaint::kUTF16_TextEncoding: |
1064 case SkPaint::kUTF32_TextEncoding: | 1157 case SkPaint::kUTF32_TextEncoding: |
1065 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 1158 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
1066 device->drawText(d, text, len, x, y, transparent); | 1159 device->drawText(d, text, len, x, y, transparent); |
1067 break; | 1160 break; |
1068 default: | 1161 default: |
1069 SkFAIL("unknown text encoding"); | 1162 SkFAIL("unknown text encoding"); |
1070 } | 1163 } |
1071 } | 1164 } |
1072 | 1165 |
1073 void SkPDFDevice::internalDrawText( | 1166 |
1074 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 1167 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1075 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 1168 SkScalar x, SkScalar y, const SkPaint& srcPaint) { |
1076 SkPoint offset, const SkPaint& srcPaint) { | 1169 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fDocument->canon())
) { |
1077 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 1170 // https://bug.skia.org/3866 |
1078 if (srcPaint.getMaskFilter() != nullptr) { | 1171 SkPath path; |
| 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) { |
1079 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 1183 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
1080 // making text unreadable (e.g. same text twice when using CSS shadows). | 1184 // making text unreadable (e.g. same text twice when using CSS shadows). |
1081 return; | 1185 return; |
1082 } | 1186 } |
1083 SkPaint paint = calculate_text_paint(srcPaint); | 1187 SkPaint textPaint = calculate_text_paint(paint); |
1084 replace_srcmode_on_opaque_paint(&paint); | 1188 ScopedContentEntry content(this, d, textPaint, true); |
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); | |
1133 if (!content.entry()) { | 1189 if (!content.entry()) { |
1134 return; | 1190 return; |
1135 } | 1191 } |
1136 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1192 |
1137 out->writeText("BT\n"); | 1193 SkGlyphStorage storage(0); |
1138 if (!this->updateFont(paint, glyphs[0], content.entry())) { | 1194 const uint16_t* glyphIDs = nullptr; |
1139 SkDebugf("SkPDF: Font error."); | 1195 int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); |
1140 out->writeText("ET\n%SkPDF: Font error.\n"); | 1196 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 1197 |
| 1198 align_text(textPaint, glyphIDs, numGlyphs, &x, &y); |
| 1199 content.entry()->fContent.writeText("BT\n"); |
| 1200 set_text_transform(x, y, textPaint.getTextSkewX(), |
| 1201 &content.entry()->fContent); |
| 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 } |
| 1230 |
| 1231 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
| 1232 const SkScalar pos[], int scalarsPerPos, |
| 1233 const SkPoint& offset, const SkPaint& srcPaint) { |
| 1234 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fDocument->canon())
) { |
| 1235 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pos); |
| 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); |
1141 return; | 1254 return; |
1142 } | 1255 } |
1143 SkPDFFont* font = content.entry()->fState.fFont; | 1256 |
1144 GlyphPositioner glyphPositioner(out, | 1257 SkPaint paint = srcPaint; |
1145 paint.getTextSkewX(), | 1258 replace_srcmode_on_opaque_paint(&paint); |
1146 font->multiByteGlyphs(), | 1259 |
1147 defaultPositioning, | 1260 NOT_IMPLEMENTED(paint.getMaskFilter() != nullptr, false); |
1148 offset); | 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()); |
1149 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage(); | 1288 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage(); |
1150 const SkGlyphID* const glyphsEnd = glyphs + glyphCount; | 1289 for (size_t i = 0; i < numGlyphs; i++) { |
1151 | 1290 SkPDFFont* font = content.entry()->fState.fFont; |
1152 while (glyphs < glyphsEnd) { | 1291 uint16_t encodedValue = glyphIDs[i]; |
1153 font = content.entry()->fState.fFont; | 1292 SkScalar advanceWidth = autoGlyphCache->getGlyphIDAdvance(encodedValue).
fAdvanceX; |
1154 int stretch = font->multiByteGlyphs() | 1293 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { |
1155 ? SkToInt(glyphsEnd - glyphs) | 1294 // The current pdf font cannot encode the current glyph. |
1156 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly
phs)); | 1295 // Try to get a pdf font which can encode the current glyph. |
1157 SkASSERT(glyphs + stretch <= glyphsEnd); | |
1158 if (stretch < 1) { | |
1159 SkASSERT(!font->multiByteGlyphs()); | |
1160 // The current pdf font cannot encode the next glyph. | |
1161 // Try to get a pdf font which can encode the next glyph. | |
1162 glyphPositioner.flush(); | 1296 glyphPositioner.flush(); |
1163 if (!this->updateFont(paint, *glyphs, content.entry())) { | 1297 if (!this->updateFont(textPaint, glyphIDs[i], content.entry())) { |
1164 SkDebugf("SkPDF: Font error."); | 1298 SkDebugf("SkPDF: Font error."); |
1165 out->writeText("ET\n%SkPDF: Font error.\n"); | 1299 content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n")
; |
1166 return; | 1300 return; |
1167 } | 1301 } |
1168 font = content.entry()->fState.fFont; | 1302 font = content.entry()->fState.fFont; |
1169 glyphPositioner.setWideChars(font->multiByteGlyphs()); | 1303 glyphPositioner.setWideChars(font->multiByteGlyphs()); |
1170 // try again | 1304 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { |
1171 stretch = font->glyphsToPDFFontEncodingCount(glyphs, | |
1172 SkToInt(glyphsEnd - gly
phs)); | |
1173 if (stretch < 1) { | |
1174 SkDEBUGFAIL("PDF could not encode glyph."); | 1305 SkDEBUGFAIL("PDF could not encode glyph."); |
1175 glyphPositioner.flush(); | 1306 continue; |
1176 out->writeText("ET\n%SkPDF: Font encoding error.\n"); | |
1177 return; | |
1178 } | 1307 } |
1179 } | 1308 } |
1180 fontGlyphUsage->noteGlyphUsage(font, glyphs, stretch); | 1309 fontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); |
1181 if (defaultPositioning) { | 1310 SkScalar x = offset.x() + pos[i * scalarsPerPos]; |
1182 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp
hs)); | 1311 SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos +
1] : 0); |
1183 while (stretch-- > 0) { | 1312 align_text(textPaint, glyphIDs + i, 1, &x, &y); |
1184 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); | 1313 |
1185 ++glyphs; | 1314 glyphPositioner.writeGlyph(x, y, advanceWidth, encodedValue); |
1186 } | |
1187 } else { | |
1188 while (stretch-- > 0) { | |
1189 SkScalar advance = glyphCache->getGlyphIDAdvance(*glyphs).fAdvan
ceX; | |
1190 SkScalar x = *pos++; | |
1191 // evaluate x and y in order! | |
1192 SkScalar y = SkTextBlob::kFull_Positioning == positioning ? *pos
++ : 0; | |
1193 SkPoint xy{x, y}; | |
1194 if (alignment != SkPaint::kLeft_Align) { | |
1195 SkScalar m = alignment == SkPaint::kCenter_Align | |
1196 ? 0.5f * advance : advance; | |
1197 xy -= verticalText ? SkPoint{0, m} : SkPoint{m, 0}; | |
1198 } | |
1199 (void)font->glyphsToPDFFontEncoding(glyphs, 1); | |
1200 glyphPositioner.writeGlyph(xy.x(), xy.y(), advance, *glyphs); | |
1201 ++glyphs; | |
1202 } | |
1203 } | |
1204 } | 1315 } |
1205 glyphPositioner.flush(); | 1316 glyphPositioner.flush(); // Must flush before ending text object. |
1206 out->writeText("ET\n"); | 1317 content.entry()->fContent.writeText("ET\n"); |
1207 } | |
1208 | |
1209 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | |
1210 SkScalar x, SkScalar y, const SkPaint& paint) { | |
1211 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, | |
1212 SkPoint{x, y}, paint); | |
1213 } | |
1214 | |
1215 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | |
1216 const SkScalar pos[], int scalarsPerPos, | |
1217 const SkPoint& offset, const SkPaint& paint) { | |
1218 this->internalDrawText(d, text, len, pos, (SkTextBlob::GlyphPositioning)scal
arsPerPos, | |
1219 offset, paint); | |
1220 } | 1318 } |
1221 | 1319 |
1222 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, | 1320 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, |
1223 int vertexCount, const SkPoint verts[], | 1321 int vertexCount, const SkPoint verts[], |
1224 const SkPoint texs[], const SkColor colors[], | 1322 const SkPoint texs[], const SkColor colors[], |
1225 SkXfermode* xmode, const uint16_t indices[], | 1323 SkXfermode* xmode, const uint16_t indices[], |
1226 int indexCount, const SkPaint& paint) { | 1324 int indexCount, const SkPaint& paint) { |
1227 if (d.fRC->isEmpty()) { | 1325 if (d.fRC->isEmpty()) { |
1228 return; | 1326 return; |
1229 } | 1327 } |
(...skipping 923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2153 } | 2251 } |
2154 | 2252 |
2155 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2253 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2156 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2254 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
2157 image->makeNonTextureImage()); | 2255 image->makeNonTextureImage()); |
2158 } | 2256 } |
2159 | 2257 |
2160 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2258 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2161 return nullptr; | 2259 return nullptr; |
2162 } | 2260 } |
OLD | NEW |