| 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 |