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