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 | 9 |
| 10 #include "SkAdvancedTypefaceMetrics.h" |
10 #include "SkAnnotationKeys.h" | 11 #include "SkAnnotationKeys.h" |
11 #include "SkBitmapDevice.h" | 12 #include "SkBitmapDevice.h" |
12 #include "SkBitmapKey.h" | 13 #include "SkBitmapKey.h" |
13 #include "SkColor.h" | 14 #include "SkColor.h" |
14 #include "SkColorFilter.h" | 15 #include "SkColorFilter.h" |
15 #include "SkDraw.h" | 16 #include "SkDraw.h" |
16 #include "SkDrawFilter.h" | 17 #include "SkDrawFilter.h" |
17 #include "SkGlyphCache.h" | 18 #include "SkGlyphCache.h" |
18 #include "SkMakeUnique.h" | 19 #include "SkMakeUnique.h" |
19 #include "SkPath.h" | 20 #include "SkPath.h" |
(...skipping 10 matching lines...) Expand all Loading... |
30 #include "SkPDFTypes.h" | 31 #include "SkPDFTypes.h" |
31 #include "SkPDFUtils.h" | 32 #include "SkPDFUtils.h" |
32 #include "SkRasterClip.h" | 33 #include "SkRasterClip.h" |
33 #include "SkRRect.h" | 34 #include "SkRRect.h" |
34 #include "SkScopeExit.h" | 35 #include "SkScopeExit.h" |
35 #include "SkString.h" | 36 #include "SkString.h" |
36 #include "SkSurface.h" | 37 #include "SkSurface.h" |
37 #include "SkTemplates.h" | 38 #include "SkTemplates.h" |
38 #include "SkTextBlobRunIterator.h" | 39 #include "SkTextBlobRunIterator.h" |
39 #include "SkTextFormatParams.h" | 40 #include "SkTextFormatParams.h" |
| 41 #include "SkUtils.h" |
40 #include "SkXfermodeInterpretation.h" | 42 #include "SkXfermodeInterpretation.h" |
41 | 43 |
42 #define DPI_FOR_RASTER_SCALE_ONE 72 | 44 #define DPI_FOR_RASTER_SCALE_ONE 72 |
43 | 45 |
44 // Utility functions | 46 // Utility functions |
45 | 47 |
46 // If the paint will definitely draw opaquely, replace kSrc_Mode with | 48 // If the paint will definitely draw opaquely, replace kSrc_Mode with |
47 // kSrcOver_Mode. http://crbug.com/473572 | 49 // kSrcOver_Mode. http://crbug.com/473572 |
48 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { | 50 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { |
49 if (kSrcOver_SkXfermodeInterpretation | 51 if (kSrcOver_SkXfermodeInterpretation |
(...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
915 private: | 917 private: |
916 SkDynamicMemoryWStream* fContent; | 918 SkDynamicMemoryWStream* fContent; |
917 SkPoint fCurrentMatrixOrigin; | 919 SkPoint fCurrentMatrixOrigin; |
918 SkScalar fXAdvance = 0.0f; | 920 SkScalar fXAdvance = 0.0f; |
919 SkScalar fTextSkewX; | 921 SkScalar fTextSkewX; |
920 bool fWideChars; | 922 bool fWideChars; |
921 bool fInText = false; | 923 bool fInText = false; |
922 bool fInitialized = false; | 924 bool fInitialized = false; |
923 const bool fDefaultPositioning; | 925 const bool fDefaultPositioning; |
924 }; | 926 }; |
| 927 |
| 928 /** Given the m-to-n glyph-to-character mapping data (as returned by |
| 929 harfbuzz), iterate over the clusters. */ |
| 930 class Clusterator { |
| 931 public: |
| 932 Clusterator() : fClusters(nullptr), fUtf8Text(nullptr), fGlyphCount(0), fTex
tByteLength(0) {} |
| 933 explicit Clusterator(uint32_t glyphCount) |
| 934 : fClusters(nullptr) |
| 935 , fUtf8Text(nullptr) |
| 936 , fGlyphCount(glyphCount) |
| 937 , fTextByteLength(0) {} |
| 938 // The clusters[] array is an array of offsets into utf8Text[], |
| 939 // one offset for each glyph. See SkTextBlobBuilder for more info. |
| 940 Clusterator(const uint32_t* clusters, |
| 941 const char* utf8Text, |
| 942 uint32_t glyphCount, |
| 943 uint32_t textByteLength) |
| 944 : fClusters(clusters) |
| 945 , fUtf8Text(utf8Text) |
| 946 , fGlyphCount(glyphCount) |
| 947 , fTextByteLength(textByteLength) { |
| 948 // This is a cheap heuristic for /ReversedChars which seems to |
| 949 // work for clusters produced by HarfBuzz, which either |
| 950 // increase from zero (LTR) or decrease to zero (RTL). |
| 951 // "ReversedChars" is how PDF deals with RTL text. |
| 952 fReversedChars = |
| 953 fUtf8Text && fClusters && fGlyphCount && fClusters[0] != 0; |
| 954 } |
| 955 struct Cluster { |
| 956 const char* fUtf8Text; |
| 957 uint32_t fTextByteLength; |
| 958 uint32_t fGlyphIndex; |
| 959 uint32_t fGlyphCount; |
| 960 explicit operator bool() const { return fGlyphCount != 0; } |
| 961 }; |
| 962 // True if this looks like right-to-left text. |
| 963 bool reversedChars() const { return fReversedChars; } |
| 964 Cluster next() { |
| 965 if ((!fUtf8Text || !fClusters) && fGlyphCount) { |
| 966 // These glyphs have no text. Treat as one "cluster". |
| 967 uint32_t glyphCount = fGlyphCount; |
| 968 fGlyphCount = 0; |
| 969 return Cluster{nullptr, 0, 0, glyphCount}; |
| 970 } |
| 971 if (fGlyphCount == 0 || fTextByteLength == 0) { |
| 972 return Cluster{nullptr, 0, 0, 0}; // empty |
| 973 } |
| 974 SkASSERT(fUtf8Text); |
| 975 SkASSERT(fClusters); |
| 976 uint32_t cluster = fClusters[0]; |
| 977 if (cluster >= fTextByteLength) { |
| 978 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 979 } |
| 980 uint32_t glyphsInCluster = 1; |
| 981 while (glyphsInCluster < fGlyphCount && |
| 982 fClusters[glyphsInCluster] == cluster) { |
| 983 ++glyphsInCluster; |
| 984 } |
| 985 SkASSERT(glyphsInCluster <= fGlyphCount); |
| 986 uint32_t textLength = 0; |
| 987 if (glyphsInCluster == fGlyphCount) { |
| 988 // consumes rest of glyphs and rest of text |
| 989 if (kInvalidCluster == fPreviousCluster) { // LTR text or single clu
ster |
| 990 textLength = fTextByteLength - cluster; |
| 991 } else { // RTL text; last cluster. |
| 992 SkASSERT(fPreviousCluster < fTextByteLength); |
| 993 if (fPreviousCluster <= cluster) { // bad input. |
| 994 return Cluster{nullptr, 0, 0, 0}; |
| 995 } |
| 996 textLength = fPreviousCluster - cluster; |
| 997 } |
| 998 fGlyphCount = 0; |
| 999 return Cluster{fUtf8Text + cluster, |
| 1000 textLength, |
| 1001 fGlyphIndex, |
| 1002 glyphsInCluster}; |
| 1003 } |
| 1004 SkASSERT(glyphsInCluster < fGlyphCount); |
| 1005 uint32_t nextCluster = fClusters[glyphsInCluster]; |
| 1006 if (nextCluster >= fTextByteLength) { |
| 1007 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 1008 } |
| 1009 if (nextCluster > cluster) { // LTR text |
| 1010 if (kInvalidCluster != fPreviousCluster) { |
| 1011 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 1012 } |
| 1013 textLength = nextCluster - cluster; |
| 1014 } else { // RTL text |
| 1015 SkASSERT(nextCluster < cluster); |
| 1016 if (kInvalidCluster == fPreviousCluster) { // first cluster |
| 1017 textLength = fTextByteLength - cluster; |
| 1018 } else { // later cluster |
| 1019 if (fPreviousCluster <= cluster) { |
| 1020 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 1021 } |
| 1022 textLength = fPreviousCluster - cluster; |
| 1023 } |
| 1024 fPreviousCluster = cluster; |
| 1025 } |
| 1026 uint32_t glyphIndex = fGlyphIndex; |
| 1027 fGlyphCount -= glyphsInCluster; |
| 1028 fGlyphIndex += glyphsInCluster; |
| 1029 fClusters += glyphsInCluster; |
| 1030 return Cluster{fUtf8Text + cluster, |
| 1031 textLength, |
| 1032 glyphIndex, |
| 1033 glyphsInCluster}; |
| 1034 } |
| 1035 |
| 1036 private: |
| 1037 static constexpr uint32_t kInvalidCluster = 0xFFFFFFFF; |
| 1038 const uint32_t* fClusters; |
| 1039 const char* fUtf8Text; |
| 1040 uint32_t fGlyphCount; |
| 1041 uint32_t fTextByteLength; |
| 1042 uint32_t fGlyphIndex = 0; |
| 1043 uint32_t fPreviousCluster = kInvalidCluster; |
| 1044 bool fReversedChars = false; |
| 1045 }; |
| 1046 |
| 1047 struct TextStorage { |
| 1048 SkAutoTMalloc<char> fUtf8textStorage; |
| 1049 SkAutoTMalloc<uint32_t> fClusterStorage; |
| 1050 SkAutoTMalloc<SkGlyphID> fGlyphStorage; |
| 1051 }; |
925 } // namespace | 1052 } // namespace |
926 | 1053 |
| 1054 /** Given some unicode text (as passed to drawText(), convert to |
| 1055 glyphs (via primitive shaping), while preserving |
| 1056 glyph-to-character mapping information. */ |
| 1057 static Clusterator make_clusterator( |
| 1058 const void* sourceText, |
| 1059 size_t sourceByteCount, |
| 1060 const SkPaint& paint, |
| 1061 TextStorage* storage, |
| 1062 int glyphCount) { |
| 1063 SkASSERT(SkPaint::kGlyphID_TextEncoding != paint.getTextEncoding()); |
| 1064 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, nullp
tr)); |
| 1065 SkASSERT(glyphCount > 0); |
| 1066 storage->fGlyphStorage.reset(SkToSizeT(glyphCount)); |
| 1067 (void)paint.textToGlyphs(sourceText, sourceByteCount, storage->fGlyphStorage
.get()); |
| 1068 storage->fClusterStorage.reset(SkToSizeT(glyphCount)); |
| 1069 uint32_t* clusters = storage->fClusterStorage.get(); |
| 1070 uint32_t utf8ByteCount = 0; |
| 1071 const char* utf8Text = nullptr; |
| 1072 switch (paint.getTextEncoding()) { |
| 1073 case SkPaint::kUTF8_TextEncoding: { |
| 1074 const char* txtPtr = (const char*)sourceText; |
| 1075 for (int i = 0; i < glyphCount; ++i) { |
| 1076 clusters[i] = SkToU32(txtPtr - (const char*)sourceText); |
| 1077 txtPtr += SkUTF8_LeadByteToCount(*(const unsigned char*)txtPtr); |
| 1078 SkASSERT(txtPtr <= (const char*)sourceText + sourceByteCount); |
| 1079 } |
| 1080 SkASSERT(txtPtr == (const char*)sourceText + sourceByteCount); |
| 1081 utf8ByteCount = SkToU32(sourceByteCount); |
| 1082 utf8Text = (const char*)sourceText; |
| 1083 break; |
| 1084 } |
| 1085 case SkPaint::kUTF16_TextEncoding: { |
| 1086 const uint16_t* utf16ptr = (const uint16_t*)sourceText; |
| 1087 int utf16count = SkToInt(sourceByteCount / sizeof(uint16_t)); |
| 1088 utf8ByteCount = SkToU32(SkUTF16_ToUTF8(utf16ptr, utf16count)); |
| 1089 storage->fUtf8textStorage.reset(utf8ByteCount); |
| 1090 char* txtPtr = storage->fUtf8textStorage.get(); |
| 1091 utf8Text = txtPtr; |
| 1092 int clusterIndex = 0; |
| 1093 while (utf16ptr < (const uint16_t*)sourceText + utf16count) { |
| 1094 clusters[clusterIndex++] = SkToU32(txtPtr - utf8Text); |
| 1095 SkUnichar uni = SkUTF16_NextUnichar(&utf16ptr); |
| 1096 txtPtr += SkUTF8_FromUnichar(uni, txtPtr); |
| 1097 } |
| 1098 SkASSERT(clusterIndex == glyphCount); |
| 1099 SkASSERT(txtPtr == storage->fUtf8textStorage.get() + utf8ByteCount); |
| 1100 SkASSERT(utf16ptr == (const uint16_t*)sourceText + utf16count); |
| 1101 break; |
| 1102 } |
| 1103 case SkPaint::kUTF32_TextEncoding: { |
| 1104 const SkUnichar* utf32 = (const SkUnichar*)sourceText; |
| 1105 int utf32count = SkToInt(sourceByteCount / sizeof(SkUnichar)); |
| 1106 SkASSERT(glyphCount == utf32count); |
| 1107 for (int i = 0; i < utf32count; ++i) { |
| 1108 utf8ByteCount += SkToU32(SkUTF8_FromUnichar(utf32[i])); |
| 1109 } |
| 1110 storage->fUtf8textStorage.reset(SkToSizeT(utf8ByteCount)); |
| 1111 char* txtPtr = storage->fUtf8textStorage.get(); |
| 1112 utf8Text = txtPtr; |
| 1113 for (int i = 0; i < utf32count; ++i) { |
| 1114 clusters[i] = SkToU32(txtPtr - utf8Text); |
| 1115 txtPtr += SkUTF8_FromUnichar(utf32[i], txtPtr); |
| 1116 } |
| 1117 break; |
| 1118 } |
| 1119 default: |
| 1120 SkDEBUGFAIL(""); |
| 1121 break; |
| 1122 } |
| 1123 return Clusterator(clusters, utf8Text, SkToU32(glyphCount), utf8ByteCount); |
| 1124 } |
| 1125 |
927 static void draw_transparent_text(SkPDFDevice* device, | 1126 static void draw_transparent_text(SkPDFDevice* device, |
928 const SkDraw& d, | 1127 const SkDraw& d, |
929 const void* text, size_t len, | 1128 const void* text, size_t len, |
930 SkScalar x, SkScalar y, | 1129 SkScalar x, SkScalar y, |
931 const SkPaint& srcPaint) { | 1130 const SkPaint& srcPaint) { |
932 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); | 1131 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); |
933 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { | 1132 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { |
934 SkDebugf("SkPDF: default typeface should be embeddable"); | 1133 SkDebugf("SkPDF: default typeface should be embeddable"); |
935 return; // Avoid infinite loop in release. | 1134 return; // Avoid infinite loop in release. |
936 } | 1135 } |
(...skipping 21 matching lines...) Expand all Loading... |
958 case SkPaint::kUTF16_TextEncoding: | 1157 case SkPaint::kUTF16_TextEncoding: |
959 case SkPaint::kUTF32_TextEncoding: | 1158 case SkPaint::kUTF32_TextEncoding: |
960 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 1159 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
961 device->drawText(d, text, len, x, y, transparent); | 1160 device->drawText(d, text, len, x, y, transparent); |
962 break; | 1161 break; |
963 default: | 1162 default: |
964 SkFAIL("unknown text encoding"); | 1163 SkFAIL("unknown text encoding"); |
965 } | 1164 } |
966 } | 1165 } |
967 | 1166 |
| 1167 static SkUnichar map_glyph(const SkTDArray<SkUnichar>& glyphToUnicode, SkGlyphID
glyph) { |
| 1168 return SkToInt(glyph) < glyphToUnicode.count() ? glyphToUnicode[SkToInt(glyp
h)] : -1; |
| 1169 } |
| 1170 |
968 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { | 1171 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { |
969 wStream->writeText("/"); | 1172 wStream->writeText("/"); |
970 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF
ont_ResourceType); | 1173 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF
ont_ResourceType); |
971 wStream->write(&prefix, 1); | 1174 wStream->write(&prefix, 1); |
972 wStream->writeDecAsText(fontIndex); | 1175 wStream->writeDecAsText(fontIndex); |
973 wStream->writeText(" "); | 1176 wStream->writeText(" "); |
974 SkPDFUtils::AppendScalar(textSize, wStream); | 1177 SkPDFUtils::AppendScalar(textSize, wStream); |
975 wStream->writeText(" Tf\n"); | 1178 wStream->writeText(" Tf\n"); |
976 } | 1179 } |
977 | 1180 |
978 void SkPDFDevice::internalDrawText( | 1181 void SkPDFDevice::internalDrawText( |
979 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 1182 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
980 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 1183 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
981 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, | 1184 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, |
982 uint32_t textByteLength, const char* utf8Text) { | 1185 uint32_t textByteLength, const char* utf8Text) { |
983 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 1186 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
984 if (srcPaint.getMaskFilter() != nullptr) { | 1187 if (srcPaint.getMaskFilter() != nullptr) { |
985 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 1188 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
986 // making text unreadable (e.g. same text twice when using CSS shadows). | 1189 // making text unreadable (e.g. same text twice when using CSS shadows). |
987 return; | 1190 return; |
988 } | 1191 } |
989 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); | 1192 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); |
990 if (srcPaint.isVerticalText()) { | 1193 if (srcPaint.isVerticalText()) { |
991 // Don't pretend we support drawing vertical text. It is not | 1194 // Don't pretend we support drawing vertical text. It is not |
992 // clear to me how to switch to "vertical writing" mode in PDF. | 1195 // clear to me how to switch to "vertical writing" mode in PDF. |
993 // Currently neither Chromium or Android set this flag. | 1196 // Currently neither Chromium or Android set this flag. |
994 // https://bug.skia.org/5665 | 1197 // https://bug.skia.org/5665 |
995 return; | 1198 return; |
996 } | 1199 } |
997 // TODO(halcanary): implement /ActualText with these values. | 1200 if (0 == sourceByteCount || !sourceText) { |
998 (void)clusters; | 1201 return; |
999 (void)textByteLength; | |
1000 (void)utf8Text; | |
1001 if (textByteLength > 0) { | |
1002 SkASSERT(clusters); | |
1003 SkASSERT(utf8Text); | |
1004 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); | |
1005 } else { | |
1006 SkASSERT(nullptr == clusters); | |
1007 SkASSERT(nullptr == utf8Text); | |
1008 } | 1202 } |
1009 | |
1010 SkPaint paint = calculate_text_paint(srcPaint); | 1203 SkPaint paint = calculate_text_paint(srcPaint); |
1011 replace_srcmode_on_opaque_paint(&paint); | 1204 replace_srcmode_on_opaque_paint(&paint); |
1012 if (!paint.getTypeface()) { | 1205 if (!paint.getTypeface()) { |
1013 paint.setTypeface(SkTypeface::MakeDefault()); | 1206 paint.setTypeface(SkTypeface::MakeDefault()); |
1014 } | 1207 } |
1015 SkTypeface* typeface = paint.getTypeface(); | 1208 SkTypeface* typeface = paint.getTypeface(); |
1016 if (!typeface) { | 1209 if (!typeface) { |
1017 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); | 1210 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
1018 return; | 1211 return; |
1019 } | 1212 } |
1020 | 1213 |
1021 const SkAdvancedTypefaceMetrics* metrics = | 1214 const SkAdvancedTypefaceMetrics* metrics = |
1022 SkPDFFont::GetMetrics(typeface, fDocument->canon()); | 1215 SkPDFFont::GetMetrics(typeface, fDocument->canon()); |
1023 if (!metrics) { | 1216 if (!metrics) { |
1024 return; | 1217 return; |
1025 } | 1218 } |
1026 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); | 1219 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); |
1027 if (glyphCount <= 0) { | 1220 if (glyphCount <= 0) { |
1028 return; | 1221 return; |
1029 } | 1222 } |
1030 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. | 1223 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. |
1031 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; | |
1032 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { | 1224 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
1033 SkPath path; // https://bug.skia.org/3866 | 1225 SkPath path; // https://bug.skia.org/3866 |
1034 switch (positioning) { | 1226 switch (positioning) { |
1035 case SkTextBlob::kDefault_Positioning: | 1227 case SkTextBlob::kDefault_Positioning: |
1036 srcPaint.getTextPath(sourceText, sourceByteCount, | 1228 srcPaint.getTextPath(sourceText, sourceByteCount, |
1037 offset.x(), offset.y(), &path); | 1229 offset.x(), offset.y(), &path); |
1038 break; | 1230 break; |
1039 case SkTextBlob::kHorizontal_Positioning: { | 1231 case SkTextBlob::kHorizontal_Positioning: { |
1040 SkAutoTMalloc<SkPoint> positionsBuffer(glyphCount); | 1232 SkAutoTMalloc<SkPoint> positionsBuffer(glyphCount); |
1041 for (int i = 0; i < glyphCount; ++i) { | 1233 for (int i = 0; i < glyphCount; ++i) { |
(...skipping 12 matching lines...) Expand all Loading... |
1054 &positionsBuffer[0], &path); | 1246 &positionsBuffer[0], &path); |
1055 break; | 1247 break; |
1056 } | 1248 } |
1057 } | 1249 } |
1058 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1250 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
1059 // Draw text transparently to make it copyable/searchable/accessable. | 1251 // Draw text transparently to make it copyable/searchable/accessable. |
1060 draw_transparent_text(this, d, sourceText, sourceByteCount, | 1252 draw_transparent_text(this, d, sourceText, sourceByteCount, |
1061 offset.x(), offset.y(), paint); | 1253 offset.x(), offset.y(), paint); |
1062 return; | 1254 return; |
1063 } | 1255 } |
1064 SkAutoSTMalloc<128, SkGlyphID> glyphStorage; | 1256 |
| 1257 // These three heap buffers are only used in the case where no glyphs |
| 1258 // are passed to drawText() (most clients pass glyphs or a textblob). |
| 1259 TextStorage storage; |
1065 const SkGlyphID* glyphs = nullptr; | 1260 const SkGlyphID* glyphs = nullptr; |
1066 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { | 1261 Clusterator clusterator; |
| 1262 if (textByteLength > 0) { |
| 1263 SkASSERT(glyphCount == SkToInt(sourceByteCount / sizeof(SkGlyphID))); |
1067 glyphs = (const SkGlyphID*)sourceText; | 1264 glyphs = (const SkGlyphID*)sourceText; |
1068 // validate input later. | 1265 clusterator = Clusterator(clusters, utf8Text, SkToU32(glyphCount), textB
yteLength); |
| 1266 SkASSERT(clusters); |
| 1267 SkASSERT(utf8Text); |
| 1268 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); |
| 1269 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n
ullptr)); |
| 1270 } else if (SkPaint::kGlyphID_TextEncoding == srcPaint.getTextEncoding()) { |
| 1271 SkASSERT(glyphCount == SkToInt(sourceByteCount / sizeof(SkGlyphID))); |
| 1272 glyphs = (const SkGlyphID*)sourceText; |
| 1273 clusterator = Clusterator(SkToU32(glyphCount)); |
| 1274 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n
ullptr)); |
| 1275 SkASSERT(nullptr == clusters); |
| 1276 SkASSERT(nullptr == utf8Text); |
1069 } else { | 1277 } else { |
1070 glyphStorage.reset(SkToSizeT(glyphCount)); | 1278 SkASSERT(nullptr == clusters); |
1071 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get()
); | 1279 SkASSERT(nullptr == utf8Text); |
1072 glyphs = glyphStorage.get(); | 1280 clusterator = make_clusterator(sourceText, sourceByteCount, srcPaint, |
1073 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 1281 &storage, glyphCount); |
| 1282 glyphs = storage.fGlyphStorage; |
1074 } | 1283 } |
1075 | |
1076 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); | 1284 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
1077 paint.setHinting(SkPaint::kNo_Hinting); | 1285 paint.setHinting(SkPaint::kNo_Hinting); |
1078 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); | 1286 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
1079 | 1287 |
1080 SkPaint::Align alignment = paint.getTextAlign(); | 1288 SkPaint::Align alignment = paint.getTextAlign(); |
1081 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : | 1289 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : |
1082 SkPaint::kCenter_Align == alignment ? -0.5f : | 1290 SkPaint::kCenter_Align == alignment ? -0.5f : |
1083 /* SkPaint::kRight_Align */ -1.0f; | 1291 /* SkPaint::kRight_Align */ -1.0f; |
1084 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { | 1292 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
1085 SkScalar advance = 0; | 1293 SkScalar advance = 0; |
1086 for (int i = 0; i < glyphCount; ++i) { | 1294 for (int i = 0; i < glyphCount; ++i) { |
1087 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; | 1295 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
1088 } | 1296 } |
1089 offset.offset(alignmentFactor * advance, 0); | 1297 offset.offset(alignmentFactor * advance, 0); |
1090 } | 1298 } |
1091 ScopedContentEntry content(this, d, paint, true); | 1299 ScopedContentEntry content(this, d, paint, true); |
1092 if (!content.entry()) { | 1300 if (!content.entry()) { |
1093 return; | 1301 return; |
1094 } | 1302 } |
1095 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1303 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
1096 SkScalar textSize = paint.getTextSize(); | 1304 SkScalar textSize = paint.getTextSize(); |
| 1305 const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode; |
1097 | 1306 |
1098 out->writeText("BT\n"); | 1307 out->writeText("BT\n"); |
1099 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); | 1308 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); |
1100 | 1309 |
| 1310 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; |
1101 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics))
; | 1311 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics))
; |
| 1312 if (clusterator.reversedChars()) { |
| 1313 out->writeText("/ReversedChars BMC\n"); |
| 1314 } |
| 1315 SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("EMC\n");
} ); |
1102 GlyphPositioner glyphPositioner(out, | 1316 GlyphPositioner glyphPositioner(out, |
1103 paint.getTextSkewX(), | 1317 paint.getTextSkewX(), |
1104 multiByteGlyphs, | 1318 multiByteGlyphs, |
1105 defaultPositioning, | 1319 defaultPositioning, |
1106 offset); | 1320 offset); |
1107 SkPDFFont* font = nullptr; | 1321 SkPDFFont* font = nullptr; |
1108 for (int index = 0; index < glyphCount; ++index) { | 1322 |
1109 SkGlyphID gid = glyphs[index]; | 1323 while (Clusterator::Cluster c = clusterator.next()) { |
1110 if (gid > maxGlyphID) { | 1324 int index = c.fGlyphIndex; |
1111 continue; // Skip this invalid glyphID. | 1325 int glyphLimit = index + c.fGlyphCount; |
1112 } | 1326 |
1113 if (!font || !font->hasGlyph(gid)) { | 1327 bool actualText = false; |
1114 // Either this is the first loop iteration or the current | 1328 SK_AT_SCOPE_EXIT(if (actualText) { glyphPositioner.flush(); out->writeTe
xt("EMC\n"); } ); |
1115 // PDFFont cannot encode this glyph. | 1329 if (c.fUtf8Text) { // real cluster |
1116 glyphPositioner.flush(); | 1330 // Check if `/ActualText` needed. |
1117 // Try to get a font which can encode the glyph. | 1331 const char* textPtr = c.fUtf8Text; |
1118 int fontIndex = this->getFontResourceIndex(typeface, gid); | 1332 // TODO(halcanary): validate utf8 input. |
1119 SkASSERT(fontIndex >= 0); | 1333 SkUnichar unichar = SkUTF8_NextUnichar(&textPtr); |
1120 if (fontIndex < 0) { return; } | 1334 const char* textEnd = c.fUtf8Text + c.fTextByteLength; |
1121 update_font(out, fontIndex, textSize); | 1335 if (textPtr < textEnd || // more ch
aracters left |
1122 font = fFontResources[fontIndex]; | 1336 glyphLimit > index + 1 || // toUnico
de wouldn't work |
1123 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource
are met. | 1337 unichar != map_glyph(glyphToUnicode, glyphs[index])) // test si
ngle Unichar map |
1124 if (!font) { return; } | 1338 { |
1125 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); | 1339 glyphPositioner.flush(); |
1126 } | 1340 out->writeText("/Span<</ActualText <"); |
1127 font->noteGlyphUsage(gid); | 1341 SkPDFUtils::WriteUTF16beHex(out, 0xFEFF); // U+FEFF = BYTE ORDE
R MARK |
1128 SkScalar advance{0.0f}; | 1342 // the BOM marks this text as UTF-16BE, not PDFDocEncoding. |
1129 SkPoint xy{0.0f, 0.0f}; | 1343 SkPDFUtils::WriteUTF16beHex(out, unichar); // first char |
1130 if (!defaultPositioning) { | 1344 while (textPtr < textEnd) { |
1131 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; | 1345 unichar = SkUTF8_NextUnichar(&textPtr); |
1132 xy = SkTextBlob::kFull_Positioning == positioning | 1346 SkPDFUtils::WriteUTF16beHex(out, unichar); |
1133 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | 1347 } |
1134 : SkPoint{pos[index], 0}; | 1348 out->writeText("> >> BDC\n"); // begin marked-content sequence |
1135 if (alignment != SkPaint::kLeft_Align) { | 1349 // with an associated property li
st. |
1136 xy.offset(alignmentFactor * advance, 0); | 1350 actualText = true; |
1137 } | 1351 } |
1138 } | 1352 } |
1139 SkGlyphID encodedGlyph = | 1353 for (; index < glyphLimit; ++index) { |
1140 multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); | 1354 SkGlyphID gid = glyphs[index]; |
1141 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | 1355 if (gid > maxGlyphID) { |
| 1356 continue; |
| 1357 } |
| 1358 if (!font || !font->hasGlyph(gid)) { |
| 1359 // Not yet specified font or need to switch font. |
| 1360 int fontIndex = this->getFontResourceIndex(typeface, gid); |
| 1361 // All preconditions for SkPDFFont::GetFontResource are met. |
| 1362 SkASSERT(fontIndex >= 0); |
| 1363 if (fontIndex < 0) { |
| 1364 return; |
| 1365 } |
| 1366 glyphPositioner.flush(); |
| 1367 update_font(out, fontIndex, textSize); |
| 1368 font = fFontResources[fontIndex]; |
| 1369 SkASSERT(font); // All preconditions for SkPDFFont::GetFontReso
urce are met. |
| 1370 if (!font) { |
| 1371 return; |
| 1372 } |
| 1373 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); |
| 1374 } |
| 1375 SkPoint xy{0, 0}; |
| 1376 SkScalar advance{0}; |
| 1377 if (!defaultPositioning) { |
| 1378 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; |
| 1379 xy = SkTextBlob::kFull_Positioning == positioning |
| 1380 ? SkPoint{pos[2 * index], pos[2 * index + 1]} |
| 1381 : SkPoint{pos[index], 0}; |
| 1382 if (alignment != SkPaint::kLeft_Align) { |
| 1383 xy.offset(alignmentFactor * advance, 0); |
| 1384 } |
| 1385 } |
| 1386 font->noteGlyphUsage(gid); |
| 1387 SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFon
tEncoding(gid); |
| 1388 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); |
| 1389 } |
1142 } | 1390 } |
1143 } | 1391 } |
1144 | 1392 |
1145 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1393 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1146 SkScalar x, SkScalar y, const SkPaint& paint) { | 1394 SkScalar x, SkScalar y, const SkPaint& paint) { |
1147 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, | 1395 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, |
1148 SkPoint{x, y}, paint, nullptr, 0, nullptr); | 1396 SkPoint{x, y}, paint, nullptr, 0, nullptr); |
1149 } | 1397 } |
1150 | 1398 |
1151 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1399 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2061 } | 2309 } |
2062 | 2310 |
2063 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2311 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2064 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2312 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
2065 image->makeNonTextureImage()); | 2313 image->makeNonTextureImage()); |
2066 } | 2314 } |
2067 | 2315 |
2068 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2316 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2069 return nullptr; | 2317 return nullptr; |
2070 } | 2318 } |
OLD | NEW |