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