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 10 matching lines...) Expand all Loading... |
21 #include "SkPDFDocument.h" | 21 #include "SkPDFDocument.h" |
22 #include "SkPDFFont.h" | 22 #include "SkPDFFont.h" |
23 #include "SkPDFFormXObject.h" | 23 #include "SkPDFFormXObject.h" |
24 #include "SkPDFGraphicState.h" | 24 #include "SkPDFGraphicState.h" |
25 #include "SkPDFResourceDict.h" | 25 #include "SkPDFResourceDict.h" |
26 #include "SkPDFShader.h" | 26 #include "SkPDFShader.h" |
27 #include "SkPDFTypes.h" | 27 #include "SkPDFTypes.h" |
28 #include "SkPDFUtils.h" | 28 #include "SkPDFUtils.h" |
29 #include "SkRasterClip.h" | 29 #include "SkRasterClip.h" |
30 #include "SkRRect.h" | 30 #include "SkRRect.h" |
| 31 #include "SkScopeExit.h" |
31 #include "SkString.h" | 32 #include "SkString.h" |
32 #include "SkSurface.h" | 33 #include "SkSurface.h" |
33 #include "SkTextFormatParams.h" | 34 #include "SkTextFormatParams.h" |
34 #include "SkTemplates.h" | 35 #include "SkTemplates.h" |
35 #include "SkTypefacePriv.h" | |
36 #include "SkXfermodeInterpretation.h" | 36 #include "SkXfermodeInterpretation.h" |
37 | 37 |
38 #define DPI_FOR_RASTER_SCALE_ONE 72 | 38 #define DPI_FOR_RASTER_SCALE_ONE 72 |
39 | 39 |
40 // Utility functions | 40 // Utility functions |
41 | 41 |
42 // If the paint will definitely draw opaquely, replace kSrc_Mode with | 42 // If the paint will definitely draw opaquely, replace kSrc_Mode with |
43 // kSrcOver_Mode. http://crbug.com/473572 | 43 // kSrcOver_Mode. http://crbug.com/473572 |
44 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { | 44 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { |
45 if (kSrcOver_SkXfermodeInterpretation | 45 if (kSrcOver_SkXfermodeInterpretation |
(...skipping 23 matching lines...) Expand all 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 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, | |
80 SkWStream* content) { | |
81 // Flip the text about the x-axis to account for origin swap and include | |
82 // the passed parameters. | |
83 content->writeText("1 0 "); | |
84 SkPDFUtils::AppendScalar(0 - textSkewX, content); | |
85 content->writeText(" -1 "); | |
86 SkPDFUtils::AppendScalar(x, content); | |
87 content->writeText(" "); | |
88 SkPDFUtils::AppendScalar(y, content); | |
89 content->writeText(" Tm\n"); | |
90 } | |
91 | |
92 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() | 79 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() |
93 : fColor(SK_ColorBLACK) | 80 : fColor(SK_ColorBLACK) |
94 , fTextScaleX(SK_Scalar1) | 81 , fTextScaleX(SK_Scalar1) |
95 , fTextFill(SkPaint::kFill_Style) | 82 , fTextFill(SkPaint::kFill_Style) |
96 , fShaderIndex(-1) | 83 , fShaderIndex(-1) |
97 , fGraphicStateIndex(-1) | 84 , fGraphicStateIndex(-1) |
98 , fFont(nullptr) | 85 , fFont(nullptr) |
99 , fTextSize(SK_ScalarNaN) { | 86 , fTextSize(SK_ScalarNaN) { |
100 fMatrix.reset(); | 87 fMatrix.reset(); |
101 } | 88 } |
(...skipping 856 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 | 945 |
959 namespace { | 946 namespace { |
960 class GlyphPositioner { | 947 class GlyphPositioner { |
961 public: | 948 public: |
962 GlyphPositioner(SkDynamicMemoryWStream* content, | 949 GlyphPositioner(SkDynamicMemoryWStream* content, |
963 SkScalar textSkewX, | 950 SkScalar textSkewX, |
964 bool wideChars, | 951 bool wideChars, |
965 bool defaultPositioning, | 952 bool defaultPositioning, |
966 SkPoint origin) | 953 SkPoint origin) |
967 : fContent(content) | 954 : fContent(content) |
968 , fCurrentMatrixX(0.0f) | 955 , fCurrentMatrixOrigin{0.0f, 0.0f} |
969 , fCurrentMatrixY(0.0f) | |
970 , fXAdvance(0.0f) | 956 , fXAdvance(0.0f) |
971 , fWideChars(wideChars) | 957 , fWideChars(wideChars) |
972 , fInText(false) | 958 , fInText(false) |
973 , fDefaultPositioning(defaultPositioning) { | 959 , fDefaultPositioning(defaultPositioning) { |
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); | 960 // Flip the text about the x-axis to account for origin swap and include |
| 961 // the passed parameters. |
| 962 fContent->writeText("1 0 "); |
| 963 SkPDFUtils::AppendScalar(0 - textSkewX, fContent); |
| 964 fContent->writeText(" -1 "); |
| 965 SkPDFUtils::AppendScalar(origin.x(), fContent); |
| 966 fContent->writeText(" "); |
| 967 SkPDFUtils::AppendScalar(origin.y(), fContent); |
| 968 fContent->writeText(" Tm\n"); |
975 } | 969 } |
976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } | 970 ~GlyphPositioner() { this->flush(); } |
977 void flush() { | 971 void flush() { |
978 if (fInText) { | 972 if (fInText) { |
979 fContent->writeText("> Tj\n"); | 973 fContent->writeText("> Tj\n"); |
980 fInText = false; | 974 fInText = false; |
981 } | 975 } |
982 } | 976 } |
983 void setWideChars(bool wideChars) { | 977 void setWideChars(bool wideChars) { |
984 if (fWideChars != wideChars) { | 978 if (fWideChars != wideChars) { |
985 SkASSERT(!fInText); | 979 SkASSERT(!fInText); |
986 SkASSERT(fWideChars == wideChars); | 980 SkASSERT(fWideChars == wideChars); |
987 fWideChars = wideChars; | 981 fWideChars = wideChars; |
988 } | 982 } |
989 } | 983 } |
990 void writeGlyph(SkScalar x, | 984 void writeGlyph(SkPoint xy, |
991 SkScalar y, | |
992 SkScalar advanceWidth, | 985 SkScalar advanceWidth, |
993 uint16_t glyph) { | 986 uint16_t glyph) { |
994 if (!fDefaultPositioning) { | 987 if (!fDefaultPositioning) { |
995 SkScalar xPosition = x - fCurrentMatrixX; | 988 SkPoint position = xy - fCurrentMatrixOrigin; |
996 SkScalar yPosition = y - fCurrentMatrixY; | 989 if (position != SkPoint{fXAdvance, 0}) { |
997 if (xPosition != fXAdvance || yPosition != 0) { | |
998 this->flush(); | 990 this->flush(); |
999 SkPDFUtils::AppendScalar(xPosition, fContent); | 991 SkPDFUtils::AppendScalar(position.x(), fContent); |
1000 fContent->writeText(" "); | 992 fContent->writeText(" "); |
1001 SkPDFUtils::AppendScalar(-yPosition, fContent); | 993 SkPDFUtils::AppendScalar(-position.y(), fContent); |
1002 fContent->writeText(" Td "); | 994 fContent->writeText(" Td "); |
1003 fCurrentMatrixX = x; | 995 fCurrentMatrixOrigin = xy; |
1004 fCurrentMatrixY = y; | |
1005 fXAdvance = 0; | 996 fXAdvance = 0; |
1006 } | 997 } |
1007 fXAdvance += advanceWidth; | 998 fXAdvance += advanceWidth; |
1008 } | 999 } |
1009 if (!fInText) { | 1000 if (!fInText) { |
1010 fContent->writeText("<"); | 1001 fContent->writeText("<"); |
1011 fInText = true; | 1002 fInText = true; |
1012 } | 1003 } |
1013 if (fWideChars) { | 1004 if (fWideChars) { |
1014 SkPDFUtils::WriteUInt16BE(fContent, glyph); | 1005 SkPDFUtils::WriteUInt16BE(fContent, glyph); |
1015 } else { | 1006 } else { |
1016 SkASSERT(0 == glyph >> 8); | 1007 SkASSERT(0 == glyph >> 8); |
1017 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); | 1008 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); |
1018 } | 1009 } |
1019 } | 1010 } |
1020 | 1011 |
1021 private: | 1012 private: |
1022 SkDynamicMemoryWStream* fContent; | 1013 SkDynamicMemoryWStream* fContent; |
1023 SkScalar fCurrentMatrixX; | 1014 SkPoint fCurrentMatrixOrigin; |
1024 SkScalar fCurrentMatrixY; | |
1025 SkScalar fXAdvance; | 1015 SkScalar fXAdvance; |
1026 bool fWideChars; | 1016 bool fWideChars; |
1027 bool fInText; | 1017 bool fInText; |
1028 const bool fDefaultPositioning; | 1018 const bool fDefaultPositioning; |
1029 }; | 1019 }; |
1030 } // namespace | 1020 } // namespace |
1031 | 1021 |
1032 static void draw_transparent_text(SkPDFDevice* device, | 1022 static void draw_transparent_text(SkPDFDevice* device, |
1033 const SkDraw& d, | 1023 const SkDraw& d, |
1034 const void* text, size_t len, | 1024 const void* text, size_t len, |
1035 SkScalar x, SkScalar y, | 1025 SkScalar x, SkScalar y, |
1036 const SkPaint& srcPaint) { | 1026 const SkPaint& srcPaint) { |
1037 SkPaint transparent; | 1027 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); |
1038 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), | 1028 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { |
1039 device->getCanon())) { | |
1040 SkDebugf("SkPDF: default typeface should be embeddable"); | 1029 SkDebugf("SkPDF: default typeface should be embeddable"); |
1041 return; // Avoid infinite loop in release. | 1030 return; // Avoid infinite loop in release. |
1042 } | 1031 } |
| 1032 SkPaint transparent; |
| 1033 transparent.setTypeface(std::move(defaultFace)); |
1043 transparent.setTextSize(srcPaint.getTextSize()); | 1034 transparent.setTextSize(srcPaint.getTextSize()); |
1044 transparent.setColor(SK_ColorTRANSPARENT); | 1035 transparent.setColor(SK_ColorTRANSPARENT); |
1045 switch (srcPaint.getTextEncoding()) { | 1036 switch (srcPaint.getTextEncoding()) { |
1046 case SkPaint::kGlyphID_TextEncoding: { | 1037 case SkPaint::kGlyphID_TextEncoding: { |
1047 // Since a glyphId<->Unicode mapping is typeface-specific, | 1038 // Since a glyphId<->Unicode mapping is typeface-specific, |
1048 // map back to Unicode first. | 1039 // map back to Unicode first. |
1049 size_t glyphCount = len / 2; | 1040 size_t glyphCount = len / 2; |
1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); | 1041 SkAutoTMalloc<SkUnichar> unichars(glyphCount); |
1051 srcPaint.glyphsToUnichars( | 1042 srcPaint.glyphsToUnichars( |
1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); | 1043 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1090 SkPaint paint = calculate_text_paint(srcPaint); | 1081 SkPaint paint = calculate_text_paint(srcPaint); |
1091 replace_srcmode_on_opaque_paint(&paint); | 1082 replace_srcmode_on_opaque_paint(&paint); |
1092 if (!paint.getTypeface()) { | 1083 if (!paint.getTypeface()) { |
1093 paint.setTypeface(SkTypeface::MakeDefault()); | 1084 paint.setTypeface(SkTypeface::MakeDefault()); |
1094 } | 1085 } |
1095 SkTypeface* typeface = paint.getTypeface(); | 1086 SkTypeface* typeface = paint.getTypeface(); |
1096 if (!typeface) { | 1087 if (!typeface) { |
1097 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); | 1088 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
1098 return; | 1089 return; |
1099 } | 1090 } |
1100 int typefaceGlyphCount = typeface->countGlyphs(); | 1091 |
1101 if (typefaceGlyphCount < 1) { | 1092 const SkAdvancedTypefaceMetrics* metrics = |
1102 SkDebugf("SkPDF: SkTypeface has no glyphs.\n"); | 1093 SkPDFFont::GetMetrics(typeface, fDocument->canon()); |
| 1094 if (!metrics) { |
1103 return; | 1095 return; |
1104 } | 1096 } |
| 1097 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. |
| 1098 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; |
1105 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { | 1099 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
1106 SkPath path; // https://bug.skia.org/3866 | 1100 SkPath path; // https://bug.skia.org/3866 |
1107 paint.getTextPath(sourceText, sourceByteCount, | 1101 paint.getTextPath(sourceText, sourceByteCount, |
1108 offset.x(), offset.y(), &path); | 1102 offset.x(), offset.y(), &path); |
1109 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1103 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
1110 // Draw text transparently to make it copyable/searchable/accessable. | 1104 // Draw text transparently to make it copyable/searchable/accessable. |
1111 draw_transparent_text(this, d, sourceText, sourceByteCount, | 1105 draw_transparent_text(this, d, sourceText, sourceByteCount, |
1112 offset.x(), offset.y(), paint); | 1106 offset.x(), offset.y(), paint); |
1113 return; | 1107 return; |
1114 } | 1108 } |
1115 // Always make a copy (1) to validate user-input glyphs and | |
1116 // (2) because we may modify the glyphs in place (for | |
1117 // single-byte-glyph-id PDF fonts). | |
1118 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); | 1109 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); |
1119 if (glyphCount <= 0) { return; } | 1110 if (glyphCount <= 0) { |
1120 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount)); | 1111 return; |
1121 SkGlyphID* glyphs = glyphStorage.get(); | 1112 } |
1122 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs); | 1113 SkAutoSTMalloc<128, SkGlyphID> glyphStorage; |
| 1114 const SkGlyphID* glyphs = nullptr; |
1123 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { | 1115 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { |
1124 // Validate user-input glyphs. | 1116 glyphs = (const SkGlyphID*)sourceText; |
1125 SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1); | 1117 // validate input later. |
1126 for (int i = 0; i < glyphCount; ++i) { | |
1127 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]); | |
1128 } | |
1129 } else { | 1118 } else { |
| 1119 glyphStorage.reset(SkToSizeT(glyphCount)); |
| 1120 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get()
); |
| 1121 glyphs = glyphStorage.get(); |
1130 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 1122 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
1131 } | 1123 } |
1132 | 1124 |
1133 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); | 1125 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
1134 paint.setHinting(SkPaint::kNo_Hinting); | 1126 paint.setHinting(SkPaint::kNo_Hinting); |
1135 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); | 1127 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
1136 | 1128 |
1137 SkPaint::Align alignment = paint.getTextAlign(); | 1129 SkPaint::Align alignment = paint.getTextAlign(); |
| 1130 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : |
| 1131 SkPaint::kCenter_Align == alignment ? -0.5f : |
| 1132 /* SkPaint::kRight_Align */ -1.0f; |
1138 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { | 1133 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
1139 SkScalar advance{0}; | 1134 SkScalar advance = 0; |
1140 for (int i = 0; i < glyphCount; ++i) { | 1135 for (int i = 0; i < glyphCount; ++i) { |
1141 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; | 1136 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
1142 } | 1137 } |
1143 SkScalar m = alignment == SkPaint::kCenter_Align | 1138 offset.offset(alignmentFactor * advance, 0); |
1144 ? 0.5f * advance : advance; | |
1145 offset -= SkPoint{m, 0}; | |
1146 } | 1139 } |
1147 ScopedContentEntry content(this, d, paint, true); | 1140 ScopedContentEntry content(this, d, paint, true); |
1148 if (!content.entry()) { | 1141 if (!content.entry()) { |
1149 return; | 1142 return; |
1150 } | 1143 } |
1151 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1144 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
| 1145 SkScalar textSize = paint.getTextSize(); |
| 1146 |
| 1147 int index = 0; |
| 1148 while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font. |
| 1149 ++index; // Skip this glyphID |
| 1150 if (index == glyphCount) { |
| 1151 return; // all glyphIDs were bad. |
| 1152 } |
| 1153 } |
| 1154 |
1152 out->writeText("BT\n"); | 1155 out->writeText("BT\n"); |
1153 if (!this->updateFont(paint, glyphs[0], content.entry())) { | 1156 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); |
1154 SkDebugf("SkPDF: Font error."); | 1157 |
1155 out->writeText("ET\n%SkPDF: Font error.\n"); | 1158 SkPDFFont* font = this->updateFont( |
1156 return; | 1159 typeface, textSize, glyphs[index], content.entry()); |
1157 } | 1160 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met
. |
1158 SkPDFFont* font = content.entry()->fState.fFont; | 1161 if (!font) { return; } |
| 1162 |
1159 GlyphPositioner glyphPositioner(out, | 1163 GlyphPositioner glyphPositioner(out, |
1160 paint.getTextSkewX(), | 1164 paint.getTextSkewX(), |
1161 font->multiByteGlyphs(), | 1165 font->multiByteGlyphs(), |
1162 defaultPositioning, | 1166 defaultPositioning, |
1163 offset); | 1167 offset); |
1164 const SkGlyphID* const glyphsEnd = glyphs + glyphCount; | |
1165 | 1168 |
1166 while (glyphs < glyphsEnd) { | 1169 while (index < glyphCount) { |
1167 font = content.entry()->fState.fFont; | 1170 int stretch = font->countStretch(&glyphs[index], glyphCount - index, max
GlyphID); |
1168 int stretch = font->multiByteGlyphs() | 1171 SkASSERT(index + stretch <= glyphCount); |
1169 ? SkToInt(glyphsEnd - glyphs) | |
1170 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly
phs)); | |
1171 SkASSERT(glyphs + stretch <= glyphsEnd); | |
1172 if (stretch < 1) { | 1172 if (stretch < 1) { |
1173 SkASSERT(!font->multiByteGlyphs()); | |
1174 // The current pdf font cannot encode the next glyph. | 1173 // The current pdf font cannot encode the next glyph. |
1175 // Try to get a pdf font which can encode the next glyph. | 1174 // Try to get a pdf font which can encode the next glyph. |
1176 glyphPositioner.flush(); | 1175 glyphPositioner.flush(); |
1177 if (!this->updateFont(paint, *glyphs, content.entry())) { | 1176 // first, validate the next glyph |
1178 SkDebugf("SkPDF: Font error."); | 1177 while (glyphs[index] > maxGlyphID) { |
1179 out->writeText("ET\n%SkPDF: Font error.\n"); | 1178 ++index; // Skip this glyphID |
1180 return; | 1179 if (index == glyphCount) { |
| 1180 return; // all remainng glyphIDs were bad. |
| 1181 } |
1181 } | 1182 } |
1182 font = content.entry()->fState.fFont; | 1183 SkASSERT(index < glyphCount); |
| 1184 font = this->updateFont(typeface, textSize, glyphs[index], content.e
ntry()); |
| 1185 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met
. |
| 1186 if (!font) { return; } |
1183 glyphPositioner.setWideChars(font->multiByteGlyphs()); | 1187 glyphPositioner.setWideChars(font->multiByteGlyphs()); |
1184 // try again | 1188 // Get stretch for this new font. |
1185 stretch = font->glyphsToPDFFontEncodingCount(glyphs, | 1189 stretch = font->countStretch(&glyphs[index], glyphCount - index, max
GlyphID); |
1186 SkToInt(glyphsEnd - gly
phs)); | |
1187 if (stretch < 1) { | 1190 if (stretch < 1) { |
1188 SkDEBUGFAIL("PDF could not encode glyph."); | 1191 SkDEBUGFAIL("PDF could not encode glyph."); |
1189 glyphPositioner.flush(); | |
1190 out->writeText("ET\n%SkPDF: Font encoding error.\n"); | |
1191 return; | 1192 return; |
1192 } | 1193 } |
1193 } | 1194 } |
1194 font->noteGlyphUsage(glyphs, stretch); | 1195 while (stretch-- > 0) { |
1195 if (defaultPositioning) { | 1196 SkGlyphID gid = glyphs[index]; |
1196 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp
hs)); | 1197 if (gid <= maxGlyphID) { |
1197 while (stretch-- > 0) { | 1198 font->noteGlyphUsage(gid); |
1198 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); | 1199 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid); |
1199 ++glyphs; | 1200 if (defaultPositioning) { |
| 1201 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph); |
| 1202 } else { |
| 1203 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvan
ceX; |
| 1204 SkPoint xy = SkTextBlob::kFull_Positioning == positioning |
| 1205 ? SkPoint{pos[2 * index], pos[2 * index + 1]} |
| 1206 : SkPoint{pos[index], 0}; |
| 1207 if (alignment != SkPaint::kLeft_Align) { |
| 1208 xy.offset(alignmentFactor * advance, 0); |
| 1209 } |
| 1210 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); |
| 1211 } |
1200 } | 1212 } |
1201 } else { | 1213 ++index; |
1202 while (stretch-- > 0) { | |
1203 SkScalar advance = glyphCache->getGlyphIDAdvance(*glyphs).fAdvan
ceX; | |
1204 SkScalar x = *pos++; | |
1205 // evaluate x and y in order! | |
1206 SkScalar y = SkTextBlob::kFull_Positioning == positioning ? *pos
++ : 0; | |
1207 SkPoint xy{x, y}; | |
1208 if (alignment != SkPaint::kLeft_Align) { | |
1209 SkScalar m = alignment == SkPaint::kCenter_Align | |
1210 ? 0.5f * advance : advance; | |
1211 xy -= SkPoint{m, 0}; | |
1212 } | |
1213 (void)font->glyphsToPDFFontEncoding(glyphs, 1); | |
1214 glyphPositioner.writeGlyph(xy.x(), xy.y(), advance, *glyphs); | |
1215 ++glyphs; | |
1216 } | |
1217 } | 1214 } |
1218 } | 1215 } |
1219 glyphPositioner.flush(); | |
1220 out->writeText("ET\n"); | |
1221 } | 1216 } |
1222 | 1217 |
1223 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1218 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1224 SkScalar x, SkScalar y, const SkPaint& paint) { | 1219 SkScalar x, SkScalar y, const SkPaint& paint) { |
1225 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, | 1220 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, |
1226 SkPoint{x, y}, paint); | 1221 SkPoint{x, y}, paint); |
1227 } | 1222 } |
1228 | 1223 |
1229 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1224 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
1230 const SkScalar pos[], int scalarsPerPos, | 1225 const SkScalar pos[], int scalarsPerPos, |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1896 // Assumes that xobject has been canonicalized (so we can directly compare | 1891 // Assumes that xobject has been canonicalized (so we can directly compare |
1897 // pointers). | 1892 // pointers). |
1898 int result = fXObjectResources.find(xObject); | 1893 int result = fXObjectResources.find(xObject); |
1899 if (result < 0) { | 1894 if (result < 0) { |
1900 result = fXObjectResources.count(); | 1895 result = fXObjectResources.count(); |
1901 fXObjectResources.push(SkRef(xObject)); | 1896 fXObjectResources.push(SkRef(xObject)); |
1902 } | 1897 } |
1903 return result; | 1898 return result; |
1904 } | 1899 } |
1905 | 1900 |
1906 bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, | 1901 SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface, |
1907 SkPDFDevice::ContentEntry* contentEntry) { | 1902 SkScalar textSize, |
1908 SkTypeface* typeface = paint.getTypeface(); | 1903 uint16_t glyphID, |
| 1904 SkPDFDevice::ContentEntry* contentEntry) { |
1909 if (contentEntry->fState.fFont == nullptr || | 1905 if (contentEntry->fState.fFont == nullptr || |
1910 contentEntry->fState.fTextSize != paint.getTextSize() || | 1906 contentEntry->fState.fTextSize != textSize || |
1911 !contentEntry->fState.fFont->hasGlyph(glyphID)) { | 1907 !contentEntry->fState.fFont->hasGlyph(glyphID)) { |
1912 int fontIndex = getFontResourceIndex(typeface, glyphID); | 1908 int fontIndex = getFontResourceIndex(typeface, glyphID); |
1913 if (fontIndex < 0) { | 1909 if (fontIndex < 0) { |
1914 return false; | 1910 SkDebugf("SkPDF: Font error."); |
| 1911 return nullptr; |
1915 } | 1912 } |
1916 contentEntry->fContent.writeText("/"); | 1913 contentEntry->fContent.writeText("/"); |
1917 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( | 1914 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( |
1918 SkPDFResourceDict::kFont_ResourceType, | 1915 SkPDFResourceDict::kFont_ResourceType, |
1919 fontIndex).c_str()); | 1916 fontIndex).c_str()); |
1920 contentEntry->fContent.writeText(" "); | 1917 contentEntry->fContent.writeText(" "); |
1921 SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent); | 1918 SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent); |
1922 contentEntry->fContent.writeText(" Tf\n"); | 1919 contentEntry->fContent.writeText(" Tf\n"); |
1923 contentEntry->fState.fFont = fFontResources[fontIndex]; | 1920 contentEntry->fState.fFont = fFontResources[fontIndex]; |
1924 } | 1921 } |
1925 return true; | 1922 return contentEntry->fState.fFont; |
1926 } | 1923 } |
1927 | 1924 |
1928 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { | 1925 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { |
1929 sk_sp<SkPDFFont> newFont( | 1926 sk_sp<SkPDFFont> newFont( |
1930 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); | 1927 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); |
1931 if (!newFont) { | 1928 if (!newFont) { |
1932 return -1; | 1929 return -1; |
1933 } | 1930 } |
1934 int resourceIndex = fFontResources.find(newFont.get()); | 1931 int resourceIndex = fFontResources.find(newFont.get()); |
1935 if (resourceIndex < 0) { | 1932 if (resourceIndex < 0) { |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2145 } | 2142 } |
2146 | 2143 |
2147 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2144 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2148 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2145 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
2149 image->makeNonTextureImage()); | 2146 image->makeNonTextureImage()); |
2150 } | 2147 } |
2151 | 2148 |
2152 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2149 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2153 return nullptr; | 2150 return nullptr; |
2154 } | 2151 } |
OLD | NEW |