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