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 920 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
966 SkPoint origin) | 965 SkPoint origin) |
967 : fContent(content) | 966 : fContent(content) |
968 , fCurrentMatrixX(0.0f) | 967 , fCurrentMatrixX(0.0f) |
969 , fCurrentMatrixY(0.0f) | 968 , fCurrentMatrixY(0.0f) |
970 , fXAdvance(0.0f) | 969 , fXAdvance(0.0f) |
971 , fWideChars(wideChars) | 970 , fWideChars(wideChars) |
972 , fInText(false) | 971 , fInText(false) |
973 , fDefaultPositioning(defaultPositioning) { | 972 , fDefaultPositioning(defaultPositioning) { |
974 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); | 973 set_text_transform(origin.x(), origin.y(), textSkewX, fContent); |
975 } | 974 } |
976 ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } | 975 ~GlyphPositioner() {this->flush(); } |
bungeman-skia
2016/08/25 19:28:43
nit: probably want a space between '{' and 'this'.
hal.canary
2016/08/26 15:27:03
Done. And removed the extra space before '}'
| |
977 void flush() { | 976 void flush() { |
978 if (fInText) { | 977 if (fInText) { |
979 fContent->writeText("> Tj\n"); | 978 fContent->writeText("> Tj\n"); |
980 fInText = false; | 979 fInText = false; |
981 } | 980 } |
982 } | 981 } |
983 void setWideChars(bool wideChars) { | 982 void setWideChars(bool wideChars) { |
984 if (fWideChars != wideChars) { | 983 if (fWideChars != wideChars) { |
985 SkASSERT(!fInText); | 984 SkASSERT(!fInText); |
986 SkASSERT(fWideChars == wideChars); | 985 SkASSERT(fWideChars == wideChars); |
987 fWideChars = wideChars; | 986 fWideChars = wideChars; |
988 } | 987 } |
989 } | 988 } |
990 void writeGlyph(SkScalar x, | 989 void writeGlyph(SkPoint xy, |
991 SkScalar y, | |
992 SkScalar advanceWidth, | 990 SkScalar advanceWidth, |
993 uint16_t glyph) { | 991 uint16_t glyph) { |
994 if (!fDefaultPositioning) { | 992 if (!fDefaultPositioning) { |
995 SkScalar xPosition = x - fCurrentMatrixX; | 993 SkScalar xPosition = xy.x() - fCurrentMatrixX; |
996 SkScalar yPosition = y - fCurrentMatrixY; | 994 SkScalar yPosition = xy.y() - fCurrentMatrixY; |
bungeman-skia
2016/08/25 19:28:43
This handling seems almost painful to read. Is the
hal.canary
2016/08/26 15:27:03
Excellent point.
Done.
I also used SkPoint::oper
| |
997 if (xPosition != fXAdvance || yPosition != 0) { | 995 if (xPosition != fXAdvance || yPosition != 0) { |
998 this->flush(); | 996 this->flush(); |
999 SkPDFUtils::AppendScalar(xPosition, fContent); | 997 SkPDFUtils::AppendScalar(xPosition, fContent); |
1000 fContent->writeText(" "); | 998 fContent->writeText(" "); |
1001 SkPDFUtils::AppendScalar(-yPosition, fContent); | 999 SkPDFUtils::AppendScalar(-yPosition, fContent); |
1002 fContent->writeText(" Td "); | 1000 fContent->writeText(" Td "); |
1003 fCurrentMatrixX = x; | 1001 fCurrentMatrixX = xy.x(); |
1004 fCurrentMatrixY = y; | 1002 fCurrentMatrixY = xy.y(); |
1005 fXAdvance = 0; | 1003 fXAdvance = 0; |
1006 } | 1004 } |
1007 fXAdvance += advanceWidth; | 1005 fXAdvance += advanceWidth; |
1008 } | 1006 } |
1009 if (!fInText) { | 1007 if (!fInText) { |
1010 fContent->writeText("<"); | 1008 fContent->writeText("<"); |
1011 fInText = true; | 1009 fInText = true; |
1012 } | 1010 } |
1013 if (fWideChars) { | 1011 if (fWideChars) { |
1014 SkPDFUtils::WriteUInt16BE(fContent, glyph); | 1012 SkPDFUtils::WriteUInt16BE(fContent, glyph); |
(...skipping 12 matching lines...) Expand all Loading... | |
1027 bool fInText; | 1025 bool fInText; |
1028 const bool fDefaultPositioning; | 1026 const bool fDefaultPositioning; |
1029 }; | 1027 }; |
1030 } // namespace | 1028 } // namespace |
1031 | 1029 |
1032 static void draw_transparent_text(SkPDFDevice* device, | 1030 static void draw_transparent_text(SkPDFDevice* device, |
1033 const SkDraw& d, | 1031 const SkDraw& d, |
1034 const void* text, size_t len, | 1032 const void* text, size_t len, |
1035 SkScalar x, SkScalar y, | 1033 SkScalar x, SkScalar y, |
1036 const SkPaint& srcPaint) { | 1034 const SkPaint& srcPaint) { |
1037 SkPaint transparent; | 1035 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); |
1038 if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(), | 1036 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), |
1039 device->getCanon())) { | 1037 device->getCanon())) { |
bungeman-skia
2016/08/25 19:28:43
nit: Since you're touching this line anyway, will
hal.canary
2016/08/26 15:27:03
Done.
| |
1040 SkDebugf("SkPDF: default typeface should be embeddable"); | 1038 SkDebugf("SkPDF: default typeface should be embeddable"); |
1041 return; // Avoid infinite loop in release. | 1039 return; // Avoid infinite loop in release. |
1042 } | 1040 } |
1041 SkPaint transparent; | |
1042 transparent.setTypeface(std::move(defaultFace)); | |
1043 transparent.setTextSize(srcPaint.getTextSize()); | 1043 transparent.setTextSize(srcPaint.getTextSize()); |
1044 transparent.setColor(SK_ColorTRANSPARENT); | 1044 transparent.setColor(SK_ColorTRANSPARENT); |
1045 switch (srcPaint.getTextEncoding()) { | 1045 switch (srcPaint.getTextEncoding()) { |
1046 case SkPaint::kGlyphID_TextEncoding: { | 1046 case SkPaint::kGlyphID_TextEncoding: { |
1047 // Since a glyphId<->Unicode mapping is typeface-specific, | 1047 // Since a glyphId<->Unicode mapping is typeface-specific, |
1048 // map back to Unicode first. | 1048 // map back to Unicode first. |
1049 size_t glyphCount = len / 2; | 1049 size_t glyphCount = len / 2; |
1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); | 1050 SkAutoTMalloc<SkUnichar> unichars(glyphCount); |
1051 srcPaint.glyphsToUnichars( | 1051 srcPaint.glyphsToUnichars( |
1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); | 1052 (const uint16_t*)text, SkToInt(glyphCount), &unichars[0]); |
1053 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); | 1053 transparent.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
1054 // TODO(halcanary): deal with case where default typeface | 1054 // TODO(halcanary): deal with case where default typeface |
1055 // does not have glyphs for these unicode code points. | 1055 // does not have glyphs for these unicode code points. |
1056 device->drawText(d, &unichars[0], | 1056 device->drawText(d, &unichars[0], |
1057 glyphCount * sizeof(SkUnichar), | 1057 glyphCount * sizeof(SkUnichar), |
1058 x, y, transparent); | 1058 x, y, transparent); |
1059 break; | 1059 break; |
1060 } | 1060 } |
1061 case SkPaint::kUTF8_TextEncoding: | 1061 case SkPaint::kUTF8_TextEncoding: |
1062 case SkPaint::kUTF16_TextEncoding: | 1062 case SkPaint::kUTF16_TextEncoding: |
1063 case SkPaint::kUTF32_TextEncoding: | 1063 case SkPaint::kUTF32_TextEncoding: |
1064 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 1064 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
1065 device->drawText(d, text, len, x, y, transparent); | 1065 device->drawText(d, text, len, x, y, transparent); |
1066 break; | 1066 break; |
1067 default: | 1067 default: |
1068 SkFAIL("unknown text encoding"); | 1068 SkFAIL("unknown text encoding"); |
1069 } | 1069 } |
1070 } | 1070 } |
1071 | 1071 |
1072 namespace { | |
1073 struct TextObject { | |
1074 SkDynamicMemoryWStream* fOut; | |
1075 TextObject(SkDynamicMemoryWStream* out) : fOut(out) { fOut->writeText("BT\n" ); } | |
1076 ~TextObject() { fOut->writeText("ET\n"); } | |
1077 }; | |
1078 } // namespace | |
bungeman-skia
2016/08/25 19:28:43
It seems that this struct is only used by internal
hal.canary
2016/08/26 15:27:03
Done.
| |
1079 | |
1080 static int get_stretch(SkPDFFont* font, const SkGlyphID* glyphs, int index, | |
1081 int glyphCount, SkGlyphID maxGlyphID, bool multiByte) { | |
1082 SkASSERT(font); | |
1083 return multiByte ? glyphCount - index | |
1084 : font->countStretch(&glyphs[index], glyphCount - index , maxGlyphID); | |
1085 } | |
1086 | |
1072 void SkPDFDevice::internalDrawText( | 1087 void SkPDFDevice::internalDrawText( |
1073 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 1088 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
1074 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 1089 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
1075 SkPoint offset, const SkPaint& srcPaint) { | 1090 SkPoint offset, const SkPaint& srcPaint) { |
1076 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 1091 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
1077 if (srcPaint.getMaskFilter() != nullptr) { | 1092 if (srcPaint.getMaskFilter() != nullptr) { |
1078 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 1093 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
1079 // making text unreadable (e.g. same text twice when using CSS shadows). | 1094 // making text unreadable (e.g. same text twice when using CSS shadows). |
1080 return; | 1095 return; |
1081 } | 1096 } |
1082 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); | 1097 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); |
1083 if (srcPaint.isVerticalText()) { | 1098 if (srcPaint.isVerticalText()) { |
1084 // Don't pretend we support drawing vertical text. It is not | 1099 // Don't pretend we support drawing vertical text. It is not |
1085 // clear to me how to switch to "vertical writing" mode in PDF. | 1100 // clear to me how to switch to "vertical writing" mode in PDF. |
1086 // Currently neither Chromium or Android set this flag. | 1101 // Currently neither Chromium or Android set this flag. |
1087 // https://bug.skia.org/5665 | 1102 // https://bug.skia.org/5665 |
1088 return; | 1103 return; |
1089 } | 1104 } |
1090 SkPaint paint = calculate_text_paint(srcPaint); | 1105 SkPaint paint = calculate_text_paint(srcPaint); |
1091 replace_srcmode_on_opaque_paint(&paint); | 1106 replace_srcmode_on_opaque_paint(&paint); |
1092 if (!paint.getTypeface()) { | 1107 if (!paint.getTypeface()) { |
1093 paint.setTypeface(SkTypeface::MakeDefault()); | 1108 paint.setTypeface(SkTypeface::MakeDefault()); |
1094 } | 1109 } |
1095 SkTypeface* typeface = paint.getTypeface(); | 1110 SkTypeface* typeface = paint.getTypeface(); |
1096 if (!typeface) { | 1111 if (!typeface) { |
1097 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); | 1112 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
1098 return; | 1113 return; |
1099 } | 1114 } |
1100 int typefaceGlyphCount = typeface->countGlyphs(); | 1115 SkPDFFont::TypefaceInfo faceInfo = SkPDFFont::GetTypefaceInfo(typeface); |
1101 if (typefaceGlyphCount < 1) { | 1116 if (!faceInfo.fGood) { |
1102 SkDebugf("SkPDF: SkTypeface has no glyphs.\n"); | |
1103 return; | 1117 return; |
1104 } | 1118 } |
1119 const SkGlyphID maxGlyphID = faceInfo.fMaxGlyphID; | |
1105 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { | 1120 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
1106 SkPath path; // https://bug.skia.org/3866 | 1121 SkPath path; // https://bug.skia.org/3866 |
1107 paint.getTextPath(sourceText, sourceByteCount, | 1122 paint.getTextPath(sourceText, sourceByteCount, |
1108 offset.x(), offset.y(), &path); | 1123 offset.x(), offset.y(), &path); |
1109 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1124 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
1110 // Draw text transparently to make it copyable/searchable/accessable. | 1125 // Draw text transparently to make it copyable/searchable/accessable. |
1111 draw_transparent_text(this, d, sourceText, sourceByteCount, | 1126 draw_transparent_text(this, d, sourceText, sourceByteCount, |
1112 offset.x(), offset.y(), paint); | 1127 offset.x(), offset.y(), paint); |
1113 return; | 1128 return; |
1114 } | 1129 } |
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); | 1130 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); |
1119 if (glyphCount <= 0) { return; } | 1131 if (glyphCount <= 0) { |
1120 SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount)); | 1132 return; |
1121 SkGlyphID* glyphs = glyphStorage.get(); | 1133 } |
1122 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs); | 1134 SkAutoSTMalloc<128, SkGlyphID> glyphStorage; |
1135 const SkGlyphID* glyphs = nullptr; | |
1123 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { | 1136 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { |
1124 // Validate user-input glyphs. | 1137 glyphs = (const SkGlyphID*)sourceText; |
1125 SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1); | 1138 // validate input later. |
1126 for (int i = 0; i < glyphCount; ++i) { | |
1127 glyphs[i] = SkTMin(maxGlyphID, glyphs[i]); | |
1128 } | |
1129 } else { | 1139 } else { |
1140 glyphStorage.reset(SkToSizeT(glyphCount)); | |
1141 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get() ); | |
1142 glyphs = glyphStorage.get(); | |
1130 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 1143 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
1131 } | 1144 } |
1132 | 1145 |
1133 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); | 1146 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
1134 paint.setHinting(SkPaint::kNo_Hinting); | 1147 paint.setHinting(SkPaint::kNo_Hinting); |
1135 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); | 1148 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
1136 | 1149 |
1137 SkPaint::Align alignment = paint.getTextAlign(); | 1150 SkPaint::Align alignment = paint.getTextAlign(); |
1151 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : | |
1152 SkPaint::kCenter_Align == alignment ? -0.5f : | |
1153 /* SkPaint::kRight_Align */ -1.0f; | |
1138 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { | 1154 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
1139 SkScalar advance{0}; | 1155 SkScalar advance = 0; |
1140 for (int i = 0; i < glyphCount; ++i) { | 1156 for (int i = 0; i < glyphCount; ++i) { |
1141 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; | 1157 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
1142 } | 1158 } |
1143 SkScalar m = alignment == SkPaint::kCenter_Align | 1159 offset.offset(alignmentFactor * advance, 0); |
1144 ? 0.5f * advance : advance; | |
1145 offset -= SkPoint{m, 0}; | |
1146 } | 1160 } |
1147 ScopedContentEntry content(this, d, paint, true); | 1161 ScopedContentEntry content(this, d, paint, true); |
1148 if (!content.entry()) { | 1162 if (!content.entry()) { |
1149 return; | 1163 return; |
1150 } | 1164 } |
1151 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1165 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
1152 out->writeText("BT\n"); | 1166 SkScalar textSize = paint.getTextSize(); |
1153 if (!this->updateFont(paint, glyphs[0], content.entry())) { | 1167 TextObject textObject(out); // Must be in scope for this->updateFont(). |
bungeman-skia
2016/08/25 19:28:43
I'm not sure this name clearly conveys the side ef
hal.canary
2016/08/26 15:27:03
Done.
| |
1154 SkDebugf("SkPDF: Font error."); | 1168 int index = 0; |
1155 out->writeText("ET\n%SkPDF: Font error.\n"); | 1169 while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font. |
1156 return; | 1170 ++index; // Skip this glyphID |
1171 if (index == glyphCount) { | |
1172 return; // all glyphIDs were bad. | |
1173 } | |
1157 } | 1174 } |
1158 SkPDFFont* font = content.entry()->fState.fFont; | 1175 SkPDFFont* font = this->updateFont( |
1176 typeface, textSize, glyphs[index], content.entry()); | |
1177 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met . | |
1178 if (!font) { return; } | |
1179 | |
1159 GlyphPositioner glyphPositioner(out, | 1180 GlyphPositioner glyphPositioner(out, |
1160 paint.getTextSkewX(), | 1181 paint.getTextSkewX(), |
1161 font->multiByteGlyphs(), | 1182 font->multiByteGlyphs(), |
1162 defaultPositioning, | 1183 defaultPositioning, |
1163 offset); | 1184 offset); |
1164 const SkGlyphID* const glyphsEnd = glyphs + glyphCount; | |
1165 | 1185 |
1166 while (glyphs < glyphsEnd) { | 1186 while (index < glyphCount) { |
1167 font = content.entry()->fState.fFont; | 1187 bool multiByte = font->multiByteGlyphs(); |
1168 int stretch = font->multiByteGlyphs() | 1188 int stretch = get_stretch(font, glyphs, index, glyphCount, maxGlyphID, m ultiByte); |
1169 ? SkToInt(glyphsEnd - glyphs) | 1189 SkASSERT(index + stretch <= glyphCount); |
1170 : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - gly phs)); | |
1171 SkASSERT(glyphs + stretch <= glyphsEnd); | |
1172 if (stretch < 1) { | 1190 if (stretch < 1) { |
1173 SkASSERT(!font->multiByteGlyphs()); | 1191 SkASSERT(!multiByte); |
1174 // The current pdf font cannot encode the next glyph. | 1192 // The current pdf font cannot encode the next glyph. |
1175 // Try to get a pdf font which can encode the next glyph. | 1193 // Try to get a pdf font which can encode the next glyph. |
1176 glyphPositioner.flush(); | 1194 glyphPositioner.flush(); |
1177 if (!this->updateFont(paint, *glyphs, content.entry())) { | 1195 // first, validate the next glyph |
1178 SkDebugf("SkPDF: Font error."); | 1196 while (glyphs[index] > maxGlyphID) { |
1179 out->writeText("ET\n%SkPDF: Font error.\n"); | 1197 ++index; // Skip this glyphID |
1180 return; | 1198 if (index == glyphCount) { |
1199 return; // all remainng glyphIDs were bad. | |
1200 } | |
1181 } | 1201 } |
1182 font = content.entry()->fState.fFont; | 1202 SkASSERT(index < glyphCount); |
1203 font = this->updateFont(typeface, textSize, glyphs[index], content.e ntry()); | |
1204 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met . | |
1205 if (!font) { return; } | |
1183 glyphPositioner.setWideChars(font->multiByteGlyphs()); | 1206 glyphPositioner.setWideChars(font->multiByteGlyphs()); |
1184 // try again | 1207 // Get stretch for this new font. |
1185 stretch = font->glyphsToPDFFontEncodingCount(glyphs, | 1208 stretch = get_stretch(font, glyphs, index, glyphCount, maxGlyphID, f alse); |
1186 SkToInt(glyphsEnd - gly phs)); | |
1187 if (stretch < 1) { | 1209 if (stretch < 1) { |
1188 SkDEBUGFAIL("PDF could not encode glyph."); | 1210 SkDEBUGFAIL("PDF could not encode glyph."); |
1189 glyphPositioner.flush(); | |
1190 out->writeText("ET\n%SkPDF: Font encoding error.\n"); | |
1191 return; | 1211 return; |
1192 } | 1212 } |
1193 } | 1213 } |
1194 font->noteGlyphUsage(glyphs, stretch); | 1214 while (stretch-- > 0) { |
1195 if (defaultPositioning) { | 1215 SkGlyphID gid = glyphs[index]; |
1196 (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyp hs)); | 1216 if (gid <= maxGlyphID) { |
1197 while (stretch-- > 0) { | 1217 font->noteGlyphUsage(gid); |
1198 glyphPositioner.writeGlyph(0, 0, 0, *glyphs); | 1218 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid); |
1199 ++glyphs; | 1219 if (defaultPositioning) { |
1220 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph); | |
1221 } else { | |
1222 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvan ceX; | |
1223 SkPoint xy = SkTextBlob::kFull_Positioning == positioning | |
1224 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | |
1225 : SkPoint{pos[index], 0}; | |
1226 if (alignment != SkPaint::kLeft_Align) { | |
1227 xy.offset(alignmentFactor * advance, 0); | |
1228 } | |
1229 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | |
1230 } | |
1200 } | 1231 } |
1201 } else { | 1232 ++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 } | 1233 } |
1218 } | 1234 } |
1219 glyphPositioner.flush(); | |
1220 out->writeText("ET\n"); | |
1221 } | 1235 } |
1222 | 1236 |
1223 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1237 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1224 SkScalar x, SkScalar y, const SkPaint& paint) { | 1238 SkScalar x, SkScalar y, const SkPaint& paint) { |
1225 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, | 1239 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, |
1226 SkPoint{x, y}, paint); | 1240 SkPoint{x, y}, paint); |
1227 } | 1241 } |
1228 | 1242 |
1229 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1243 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
1230 const SkScalar pos[], int scalarsPerPos, | 1244 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 | 1910 // Assumes that xobject has been canonicalized (so we can directly compare |
1897 // pointers). | 1911 // pointers). |
1898 int result = fXObjectResources.find(xObject); | 1912 int result = fXObjectResources.find(xObject); |
1899 if (result < 0) { | 1913 if (result < 0) { |
1900 result = fXObjectResources.count(); | 1914 result = fXObjectResources.count(); |
1901 fXObjectResources.push(SkRef(xObject)); | 1915 fXObjectResources.push(SkRef(xObject)); |
1902 } | 1916 } |
1903 return result; | 1917 return result; |
1904 } | 1918 } |
1905 | 1919 |
1906 bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, | 1920 SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface, |
1907 SkPDFDevice::ContentEntry* contentEntry) { | 1921 SkScalar textSize, |
1908 SkTypeface* typeface = paint.getTypeface(); | 1922 uint16_t glyphID, |
1923 SkPDFDevice::ContentEntry* contentEntry) { | |
1909 if (contentEntry->fState.fFont == nullptr || | 1924 if (contentEntry->fState.fFont == nullptr || |
1910 contentEntry->fState.fTextSize != paint.getTextSize() || | 1925 contentEntry->fState.fTextSize != textSize || |
1911 !contentEntry->fState.fFont->hasGlyph(glyphID)) { | 1926 !contentEntry->fState.fFont->hasGlyph(glyphID)) { |
1912 int fontIndex = getFontResourceIndex(typeface, glyphID); | 1927 int fontIndex = getFontResourceIndex(typeface, glyphID); |
1913 if (fontIndex < 0) { | 1928 if (fontIndex < 0) { |
1914 return false; | 1929 SkDebugf("SkPDF: Font error."); |
1930 return nullptr; | |
1915 } | 1931 } |
1916 contentEntry->fContent.writeText("/"); | 1932 contentEntry->fContent.writeText("/"); |
1917 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( | 1933 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( |
1918 SkPDFResourceDict::kFont_ResourceType, | 1934 SkPDFResourceDict::kFont_ResourceType, |
1919 fontIndex).c_str()); | 1935 fontIndex).c_str()); |
1920 contentEntry->fContent.writeText(" "); | 1936 contentEntry->fContent.writeText(" "); |
1921 SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent); | 1937 SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent); |
1922 contentEntry->fContent.writeText(" Tf\n"); | 1938 contentEntry->fContent.writeText(" Tf\n"); |
1923 contentEntry->fState.fFont = fFontResources[fontIndex]; | 1939 contentEntry->fState.fFont = fFontResources[fontIndex]; |
1924 } | 1940 } |
1925 return true; | 1941 return contentEntry->fState.fFont; |
1926 } | 1942 } |
1927 | 1943 |
1928 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { | 1944 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { |
1929 sk_sp<SkPDFFont> newFont( | 1945 sk_sp<SkPDFFont> newFont( |
1930 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); | 1946 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); |
1931 if (!newFont) { | 1947 if (!newFont) { |
1932 return -1; | 1948 return -1; |
1933 } | 1949 } |
1934 int resourceIndex = fFontResources.find(newFont.get()); | 1950 int resourceIndex = fFontResources.find(newFont.get()); |
1935 if (resourceIndex < 0) { | 1951 if (resourceIndex < 0) { |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2145 } | 2161 } |
2146 | 2162 |
2147 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2163 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2148 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), | 2164 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), |
2149 image->makeNonTextureImage()); | 2165 image->makeNonTextureImage()); |
2150 } | 2166 } |
2151 | 2167 |
2152 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2168 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2153 return nullptr; | 2169 return nullptr; |
2154 } | 2170 } |
OLD | NEW |