Chromium Code Reviews| 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(int glyphCount = 0) | |
| 933 : fClusters(nullptr) | |
| 934 , fGlyphCount(SkToU32(glyphCount)) | |
| 935 , fTextByteLength(0) | |
| 936 , fUtf8Text(nullptr) {} | |
| 937 Clusterator(const uint32_t* clusters, | |
| 938 int glyphCount, | |
| 939 uint32_t textByteLength, | |
| 940 const char* utf8Text) | |
| 941 : fClusters(clusters) | |
| 942 , fGlyphCount(SkToU32(glyphCount)) | |
| 943 , fTextByteLength(textByteLength) | |
| 944 , fUtf8Text(utf8Text) { | |
| 945 // This is a cheap heuristic for /ReversedChars which seems to | |
| 946 // work for clusters produced by HarfBuzz | |
| 947 fReversedChars = | |
| 948 fUtf8Text && fClusters && fGlyphCount && fClusters[0] != 0; | |
| 949 } | |
| 950 struct Cluster { | |
| 951 const char* fUtf8Text; | |
| 952 uint32_t fTextByteLength; | |
| 953 uint32_t fGlyphIndex; | |
| 954 uint32_t fGlyphCount; | |
| 955 explicit operator bool() const { return fGlyphCount != 0; } | |
| 956 }; | |
| 957 bool reversedChars() const { return fReversedChars; } | |
| 958 Cluster next() { | |
| 959 if (!fUtf8Text || !fClusters) { | |
| 960 // These glyphs have no text. Treat as one "cluster". | |
| 961 uint32_t glyphCount = fGlyphCount; | |
| 962 fGlyphCount = 0; | |
| 963 return Cluster{nullptr, 0, 0, glyphCount}; | |
| 964 } | |
| 965 if (fGlyphCount == 0 || fTextByteLength == 0) { | |
| 966 return Cluster{nullptr, 0, 0, 0}; // empty | |
| 967 } | |
| 968 uint32_t cluster = fClusters[0]; | |
| 969 if (cluster >= fTextByteLength) { | |
| 970 return Cluster{nullptr, 0, 0, 0}; // bad input. | |
| 971 } | |
| 972 uint32_t glyphsInCluster = 1; | |
| 973 while (fClusters[glyphsInCluster] == cluster && | |
| 974 glyphsInCluster < fGlyphCount) { | |
| 975 ++glyphsInCluster; | |
| 976 } | |
| 977 SkASSERT(glyphsInCluster <= fGlyphCount); | |
| 978 uint32_t textLength = 0; | |
| 979 if (glyphsInCluster == fGlyphCount) { | |
| 980 // consumes rest of glyphs and rest of text | |
| 981 if (kInvalidCluster == fPreviousCluster) { // LTR text or single clu ster | |
| 982 textLength = fTextByteLength - cluster; | |
| 983 } else { // RTL text; last cluster. | |
| 984 SkASSERT(fPreviousCluster < fTextByteLength); | |
| 985 if (fPreviousCluster <= cluster) { // bad input. | |
| 986 return Cluster{nullptr, 0, 0, 0}; | |
| 987 } | |
| 988 textLength = fPreviousCluster - cluster; | |
| 989 } | |
| 990 fGlyphCount = 0; | |
| 991 return Cluster{fUtf8Text + cluster, | |
| 992 textLength, | |
| 993 fGlyphIndex, | |
| 994 glyphsInCluster}; | |
| 995 } | |
| 996 uint32_t nextCluster = fClusters[glyphsInCluster]; | |
| 997 if (nextCluster >= fTextByteLength) { | |
| 998 return Cluster{nullptr, 0, 0, 0}; // bad input. | |
| 999 } | |
| 1000 if (nextCluster > cluster) { // LTR text | |
| 1001 if (kInvalidCluster != fPreviousCluster) { | |
| 1002 return Cluster{nullptr, 0, 0, 0}; // bad input. | |
| 1003 } | |
| 1004 textLength = nextCluster - cluster; | |
| 1005 } else { // RTL text | |
| 1006 SkASSERT(nextCluster < cluster); | |
| 1007 if (kInvalidCluster == fPreviousCluster) { // first cluster | |
| 1008 textLength = fTextByteLength - cluster; | |
| 1009 } else { // later cluster | |
| 1010 if (fPreviousCluster <= cluster) { | |
| 1011 return Cluster{nullptr, 0, 0, 0}; // bad input. | |
| 1012 } | |
| 1013 textLength = fPreviousCluster - cluster; | |
| 1014 } | |
| 1015 fPreviousCluster = cluster; | |
| 1016 } | |
| 1017 uint32_t glyphIndex = fGlyphIndex; | |
| 1018 fGlyphCount -= glyphsInCluster; | |
| 1019 fGlyphIndex += glyphsInCluster; | |
| 1020 fClusters += glyphsInCluster; | |
| 1021 return Cluster{fUtf8Text + cluster, | |
| 1022 textLength, | |
| 1023 glyphIndex, | |
| 1024 glyphsInCluster}; | |
| 1025 } | |
| 1026 | |
| 1027 private: | |
| 1028 static constexpr uint32_t kInvalidCluster = 0xFFFFFFFF; | |
| 1029 const uint32_t* fClusters; | |
| 1030 uint32_t fGlyphIndex = 0; | |
| 1031 uint32_t fGlyphCount; | |
| 1032 uint32_t fPreviousCluster = kInvalidCluster; | |
| 1033 uint32_t fTextByteLength; | |
| 1034 const char* fUtf8Text; | |
| 1035 bool fReversedChars = false; | |
| 1036 }; | |
| 1037 | |
| 1038 struct TextStorage { | |
| 1039 SkAutoTMalloc<char> fUtf8textStorage; | |
| 1040 SkAutoTMalloc<uint32_t> fClusterStorage; | |
| 1041 SkAutoTMalloc<SkGlyphID> fGlyphStorage; | |
| 1042 }; | |
| 925 } // namespace | 1043 } // namespace |
| 926 | 1044 |
| 1045 // given some unicode text (as passed to drawText(), convert to glyphs | |
| 1046 // (via primitive shaping), while preserving glyph-to-character | |
| 1047 // mapping information. | |
| 1048 static Clusterator make_clusterator( | |
| 1049 const void* sourceText, | |
| 1050 size_t sourceByteCount, | |
| 1051 const SkPaint& paint, | |
| 1052 TextStorage* storage, | |
| 1053 int* glyphCountOut) { | |
| 1054 SkASSERT(SkPaint::kGlyphID_TextEncoding != paint.getTextEncoding()); | |
| 1055 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); | |
| 1056 if (glyphCountOut) { | |
| 1057 *glyphCountOut = glyphCount; | |
| 1058 } | |
| 1059 if (!glyphCount) { | |
| 1060 return Clusterator(); | |
| 1061 } | |
| 1062 storage->fGlyphStorage.reset(SkToSizeT(glyphCount)); | |
| 1063 (void)paint.textToGlyphs(sourceText, sourceByteCount, storage->fGlyphStorage .get()); | |
| 1064 storage->fClusterStorage.reset(SkToSizeT(glyphCount)); | |
| 1065 uint32_t* clusters = storage->fClusterStorage.get(); | |
| 1066 uint32_t utf8ByteCount = 0; | |
| 1067 const char* utf8Text = nullptr; | |
| 1068 switch (paint.getTextEncoding()) { | |
| 1069 case SkPaint::kUTF8_TextEncoding: { | |
| 1070 const char* txtPtr = (const char*)sourceText; | |
| 1071 for (int i = 0; i < glyphCount; ++i) { | |
| 1072 clusters[i] = SkToU32(txtPtr - (const char*)sourceText); | |
| 1073 txtPtr += SkUTF8_LeadByteToCount(*(const unsigned char*)txtPtr); | |
| 1074 SkASSERT(txtPtr <= (const char*)sourceText + sourceByteCount); | |
| 1075 } | |
| 1076 utf8ByteCount = SkToU32(sourceByteCount); | |
| 1077 utf8Text = (const char*)sourceText; | |
| 1078 break; | |
| 1079 } | |
| 1080 case SkPaint::kUTF16_TextEncoding: { | |
| 1081 const uint16_t* utf16ptr = (const uint16_t*)sourceText; | |
| 1082 int utf16count = SkToInt(sourceByteCount / sizeof(uint16_t)); | |
| 1083 utf8ByteCount = SkToU32(SkUTF16_ToUTF8(utf16ptr, utf16count)); | |
| 1084 storage->fUtf8textStorage.reset(utf8ByteCount); | |
| 1085 char* txtPtr = storage->fUtf8textStorage.get(); | |
| 1086 utf8Text = txtPtr; | |
| 1087 int clusterIndex = 0; | |
| 1088 while (utf16ptr < (const uint16_t*)sourceText + sourceByteCount) { | |
| 1089 clusters[clusterIndex++] = SkToU32(txtPtr - utf8Text); | |
| 1090 SkUnichar uni = SkUTF16_NextUnichar(&utf16ptr); | |
| 1091 txtPtr += SkUTF8_FromUnichar(uni, txtPtr); | |
| 1092 } | |
| 1093 SkASSERT(clusterIndex == glyphCount); | |
| 1094 SkASSERT(txtPtr == storage->fUtf8textStorage.get() + utf8ByteCount); | |
| 1095 SkASSERT(utf16ptr == (const uint16_t*)sourceText + sourceByteCount); | |
| 1096 break; | |
| 1097 } | |
| 1098 case SkPaint::kUTF32_TextEncoding: { | |
| 1099 const SkUnichar* utf32 = (const SkUnichar*)sourceText; | |
| 1100 for (size_t i = 0; i < sourceByteCount / sizeof(SkUnichar); ++i) { | |
| 1101 utf8ByteCount += SkToU32(SkUTF8_FromUnichar(utf32[i])); | |
| 1102 } | |
| 1103 storage->fUtf8textStorage.reset(SkToSizeT(utf8ByteCount)); | |
| 1104 char* txtPtr = storage->fUtf8textStorage.get(); | |
| 1105 utf8Text = txtPtr; | |
| 1106 for (size_t i = 0; i < sourceByteCount / sizeof(SkUnichar); ++i) { | |
| 1107 clusters[i] = SkToU32(txtPtr - utf8Text); | |
| 1108 txtPtr += SkUTF8_FromUnichar(utf32[i], txtPtr); | |
| 1109 } | |
| 1110 break; | |
| 1111 } | |
| 1112 default: | |
| 1113 SkDEBUGFAIL(""); | |
| 1114 break; | |
| 1115 } | |
| 1116 return Clusterator(clusters, glyphCount, utf8ByteCount, utf8Text); | |
| 1117 } | |
| 1118 | |
| 927 static void draw_transparent_text(SkPDFDevice* device, | 1119 static void draw_transparent_text(SkPDFDevice* device, |
| 928 const SkDraw& d, | 1120 const SkDraw& d, |
| 929 const void* text, size_t len, | 1121 const void* text, size_t len, |
| 930 SkScalar x, SkScalar y, | 1122 SkScalar x, SkScalar y, |
| 931 const SkPaint& srcPaint) { | 1123 const SkPaint& srcPaint) { |
| 932 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); | 1124 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); |
| 933 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { | 1125 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { |
| 934 SkDebugf("SkPDF: default typeface should be embeddable"); | 1126 SkDebugf("SkPDF: default typeface should be embeddable"); |
| 935 return; // Avoid infinite loop in release. | 1127 return; // Avoid infinite loop in release. |
| 936 } | 1128 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 958 case SkPaint::kUTF16_TextEncoding: | 1150 case SkPaint::kUTF16_TextEncoding: |
| 959 case SkPaint::kUTF32_TextEncoding: | 1151 case SkPaint::kUTF32_TextEncoding: |
| 960 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 1152 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
| 961 device->drawText(d, text, len, x, y, transparent); | 1153 device->drawText(d, text, len, x, y, transparent); |
| 962 break; | 1154 break; |
| 963 default: | 1155 default: |
| 964 SkFAIL("unknown text encoding"); | 1156 SkFAIL("unknown text encoding"); |
| 965 } | 1157 } |
| 966 } | 1158 } |
| 967 | 1159 |
| 1160 static SkUnichar map_glyph(const SkTDArray<SkUnichar>& glyphToUnicode, SkGlyphID glyph) { | |
| 1161 return SkToInt(glyph) < glyphToUnicode.count() ? glyphToUnicode[SkToInt(glyp h)] : -1; | |
| 1162 } | |
| 1163 | |
| 1164 // TODO: move into SkPDFUtils.h | |
|
bungeman-skia
2016/09/13 18:28:24
Any reason not to do this now?
hal.canary
2016/09/14 01:36:36
Only an effort to keep this CL small.
Fixed in pa
| |
| 1165 static void write_utf16be(SkDynamicMemoryWStream* wStream, SkUnichar utf32) { | |
| 1166 SkGlyphID utf16[2] = {0, 0}; | |
| 1167 size_t len = SkUTF16_FromUnichar(utf32, utf16); | |
| 1168 SkASSERT(len == 1 || len == 2); | |
| 1169 SkPDFUtils::WriteUInt16BE(wStream, utf16[0]); | |
| 1170 if (len == 2) { | |
| 1171 SkPDFUtils::WriteUInt16BE(wStream, utf16[1]); | |
| 1172 } | |
| 1173 } | |
| 1174 | |
| 968 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { | 1175 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { |
| 969 wStream->writeText("/"); | 1176 wStream->writeText("/"); |
| 970 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF ont_ResourceType); | 1177 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF ont_ResourceType); |
| 971 wStream->write(&prefix, 1); | 1178 wStream->write(&prefix, 1); |
| 972 wStream->writeDecAsText(fontIndex); | 1179 wStream->writeDecAsText(fontIndex); |
| 973 wStream->writeText(" "); | 1180 wStream->writeText(" "); |
| 974 SkPDFUtils::AppendScalar(textSize, wStream); | 1181 SkPDFUtils::AppendScalar(textSize, wStream); |
| 975 wStream->writeText(" Tf\n"); | 1182 wStream->writeText(" Tf\n"); |
| 976 } | 1183 } |
| 977 | 1184 |
| 978 void SkPDFDevice::internalDrawText( | 1185 void SkPDFDevice::internalDrawText( |
| 979 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 1186 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
| 980 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 1187 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
| 981 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, | 1188 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, |
| 982 uint32_t textByteLength, const char* utf8Text) { | 1189 uint32_t textByteLength, const char* utf8Text) { |
| 983 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 1190 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
| 984 if (srcPaint.getMaskFilter() != nullptr) { | 1191 if (srcPaint.getMaskFilter() != nullptr) { |
| 985 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 1192 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
| 986 // making text unreadable (e.g. same text twice when using CSS shadows). | 1193 // making text unreadable (e.g. same text twice when using CSS shadows). |
| 987 return; | 1194 return; |
| 988 } | 1195 } |
| 989 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); | 1196 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); |
| 990 if (srcPaint.isVerticalText()) { | 1197 if (srcPaint.isVerticalText()) { |
| 991 // Don't pretend we support drawing vertical text. It is not | 1198 // Don't pretend we support drawing vertical text. It is not |
| 992 // clear to me how to switch to "vertical writing" mode in PDF. | 1199 // clear to me how to switch to "vertical writing" mode in PDF. |
| 993 // Currently neither Chromium or Android set this flag. | 1200 // Currently neither Chromium or Android set this flag. |
| 994 // https://bug.skia.org/5665 | 1201 // https://bug.skia.org/5665 |
| 995 return; | 1202 return; |
| 996 } | 1203 } |
| 997 // TODO(halcanary): implement /ActualText with these values. | 1204 if (0 == sourceByteCount || !sourceText) { |
| 998 (void)clusters; | 1205 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 } | 1206 } |
| 1009 | |
| 1010 SkPaint paint = calculate_text_paint(srcPaint); | 1207 SkPaint paint = calculate_text_paint(srcPaint); |
| 1011 replace_srcmode_on_opaque_paint(&paint); | 1208 replace_srcmode_on_opaque_paint(&paint); |
| 1012 if (!paint.getTypeface()) { | 1209 if (!paint.getTypeface()) { |
| 1013 paint.setTypeface(SkTypeface::MakeDefault()); | 1210 paint.setTypeface(SkTypeface::MakeDefault()); |
| 1014 } | 1211 } |
| 1015 SkTypeface* typeface = paint.getTypeface(); | 1212 SkTypeface* typeface = paint.getTypeface(); |
| 1016 if (!typeface) { | 1213 if (!typeface) { |
| 1017 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); | 1214 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
| 1018 return; | 1215 return; |
| 1019 } | 1216 } |
| 1020 | 1217 |
| 1021 const SkAdvancedTypefaceMetrics* metrics = | 1218 const SkAdvancedTypefaceMetrics* metrics = |
| 1022 SkPDFFont::GetMetrics(typeface, fDocument->canon()); | 1219 SkPDFFont::GetMetrics(typeface, fDocument->canon()); |
| 1023 if (!metrics) { | 1220 if (!metrics) { |
| 1024 return; | 1221 return; |
| 1025 } | 1222 } |
| 1026 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. | 1223 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. |
| 1027 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; | |
| 1028 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { | 1224 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
| 1029 SkPath path; // https://bug.skia.org/3866 | 1225 SkPath path; // https://bug.skia.org/3866 |
| 1030 paint.getTextPath(sourceText, sourceByteCount, | 1226 paint.getTextPath(sourceText, sourceByteCount, |
| 1031 offset.x(), offset.y(), &path); | 1227 offset.x(), offset.y(), &path); |
| 1032 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1228 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
| 1033 // Draw text transparently to make it copyable/searchable/accessable. | 1229 // Draw text transparently to make it copyable/searchable/accessable. |
| 1034 draw_transparent_text(this, d, sourceText, sourceByteCount, | 1230 draw_transparent_text(this, d, sourceText, sourceByteCount, |
| 1035 offset.x(), offset.y(), paint); | 1231 offset.x(), offset.y(), paint); |
| 1036 return; | 1232 return; |
| 1037 } | 1233 } |
| 1038 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); | 1234 |
| 1039 if (glyphCount <= 0) { | 1235 // These three heap buffers are only used in the case where no glyphs |
| 1236 // are passed to drawText() (most clients pass glyphs or a textblob). | |
| 1237 TextStorage storage; | |
| 1238 int glyphCount = 0; | |
| 1239 const SkGlyphID* glyphs = nullptr; | |
| 1240 Clusterator clusterator; | |
| 1241 if (textByteLength > 0) { | |
| 1242 glyphCount = SkToInt(sourceByteCount / sizeof(SkGlyphID)); | |
| 1243 glyphs = (const SkGlyphID*)sourceText; | |
| 1244 clusterator = Clusterator(clusters, glyphCount, textByteLength, utf8Text ); | |
| 1245 SkASSERT(clusters); | |
| 1246 SkASSERT(utf8Text); | |
| 1247 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); | |
| 1248 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n ullptr)); | |
| 1249 } else if (SkPaint::kGlyphID_TextEncoding == srcPaint.getTextEncoding()) { | |
| 1250 glyphCount = SkToInt(sourceByteCount / sizeof(SkGlyphID)); | |
| 1251 glyphs = (const SkGlyphID*)sourceText; | |
| 1252 clusterator = Clusterator(glyphCount); | |
| 1253 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n ullptr)); | |
| 1254 SkASSERT(nullptr == clusters); | |
| 1255 SkASSERT(nullptr == utf8Text); | |
| 1256 } else { | |
| 1257 SkASSERT(nullptr == clusters); | |
| 1258 SkASSERT(nullptr == utf8Text); | |
| 1259 clusterator = make_clusterator(sourceText, sourceByteCount, srcPaint, | |
| 1260 &storage, &glyphCount); | |
| 1261 glyphs = storage.fGlyphStorage; | |
| 1262 } | |
| 1263 if (0 == glyphCount) { | |
| 1040 return; | 1264 return; |
| 1041 } | 1265 } |
| 1042 SkAutoSTMalloc<128, SkGlyphID> glyphStorage; | |
| 1043 const SkGlyphID* glyphs = nullptr; | |
| 1044 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { | |
| 1045 glyphs = (const SkGlyphID*)sourceText; | |
| 1046 // validate input later. | |
| 1047 } else { | |
| 1048 glyphStorage.reset(SkToSizeT(glyphCount)); | |
| 1049 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get() ); | |
| 1050 glyphs = glyphStorage.get(); | |
| 1051 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
| 1052 } | |
| 1053 | |
| 1054 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); | 1266 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
| 1055 paint.setHinting(SkPaint::kNo_Hinting); | 1267 paint.setHinting(SkPaint::kNo_Hinting); |
| 1056 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); | 1268 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
| 1057 | 1269 |
| 1058 SkPaint::Align alignment = paint.getTextAlign(); | 1270 SkPaint::Align alignment = paint.getTextAlign(); |
| 1059 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : | 1271 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : |
| 1060 SkPaint::kCenter_Align == alignment ? -0.5f : | 1272 SkPaint::kCenter_Align == alignment ? -0.5f : |
| 1061 /* SkPaint::kRight_Align */ -1.0f; | 1273 /* SkPaint::kRight_Align */ -1.0f; |
| 1062 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { | 1274 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
| 1063 SkScalar advance = 0; | 1275 SkScalar advance = 0; |
| 1064 for (int i = 0; i < glyphCount; ++i) { | 1276 for (int i = 0; i < glyphCount; ++i) { |
| 1065 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; | 1277 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
| 1066 } | 1278 } |
| 1067 offset.offset(alignmentFactor * advance, 0); | 1279 offset.offset(alignmentFactor * advance, 0); |
| 1068 } | 1280 } |
| 1069 ScopedContentEntry content(this, d, paint, true); | 1281 ScopedContentEntry content(this, d, paint, true); |
| 1070 if (!content.entry()) { | 1282 if (!content.entry()) { |
| 1071 return; | 1283 return; |
| 1072 } | 1284 } |
| 1073 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1285 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
| 1074 SkScalar textSize = paint.getTextSize(); | 1286 SkScalar textSize = paint.getTextSize(); |
| 1287 const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode; | |
| 1075 | 1288 |
| 1076 out->writeText("BT\n"); | 1289 out->writeText("BT\n"); |
| 1077 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); | 1290 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); |
| 1078 | 1291 |
| 1292 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; | |
| 1079 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)) ; | 1293 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)) ; |
| 1294 if (clusterator.reversedChars()) { | |
| 1295 out->writeText("/ReversedChars BMC\n"); | |
| 1296 } | |
| 1297 SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("/EMC\n") ; } ); | |
| 1080 GlyphPositioner glyphPositioner(out, | 1298 GlyphPositioner glyphPositioner(out, |
| 1081 paint.getTextSkewX(), | 1299 paint.getTextSkewX(), |
| 1082 multiByteGlyphs, | 1300 multiByteGlyphs, |
| 1083 defaultPositioning, | 1301 defaultPositioning, |
| 1084 offset); | 1302 offset); |
| 1085 SkPDFFont* font = nullptr; | 1303 SkPDFFont* font = nullptr; |
| 1086 for (int index = 0; index < glyphCount; ++index) { | 1304 |
| 1087 SkGlyphID gid = glyphs[index]; | 1305 while (Clusterator::Cluster c = clusterator.next()) { |
| 1088 if (gid > maxGlyphID) { | 1306 int index = c.fGlyphIndex; |
| 1089 continue; // Skip this invalid glyphID. | 1307 int glyphLimit = index + c.fGlyphCount; |
| 1090 } | 1308 |
| 1091 if (!font || !font->hasGlyph(gid)) { | 1309 bool actualText = false; |
| 1092 // Either this is the first loop iteration or the current | 1310 SK_AT_SCOPE_EXIT(if (actualText) { glyphPositioner.flush(); out->writeTe xt("EMC\n"); } ); |
| 1093 // PDFFont cannot encode this glyph. | 1311 if (c.fUtf8Text) { // real cluster |
| 1094 glyphPositioner.flush(); | 1312 // Check if `/ActualText` needed. |
| 1095 // Try to get a font which can encode the glyph. | 1313 const char* textPtr = c.fUtf8Text; |
| 1096 int fontIndex = this->getFontResourceIndex(typeface, gid); | 1314 // TODO(halcanary): validate utf8 input. |
| 1097 SkASSERT(fontIndex >= 0); | 1315 SkUnichar unichar = SkUTF8_NextUnichar(&textPtr); |
| 1098 if (fontIndex < 0) { return; } | 1316 const char* textEnd = c.fUtf8Text + c.fTextByteLength; |
| 1099 update_font(out, fontIndex, textSize); | 1317 if (textPtr < textEnd || // more characters left |
| 1100 font = fFontResources[fontIndex]; | 1318 glyphLimit > index + 1 || // toUni code wouldn't work |
| 1101 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met. | 1319 unichar != map_glyph(glyphToUnicode, glyphs[index])) { // test single Unichar map |
| 1102 if (!font) { return; } | 1320 glyphPositioner.flush(); |
| 1103 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); | 1321 out->writeText("/Span<</ActualText <"); |
| 1104 } | 1322 write_utf16be(out, 0xFEFF); // U+FEFF = BYTE ORDER MARK |
| 1105 font->noteGlyphUsage(gid); | 1323 // the BOM marks this text as UTF-16BE, not PDFDocEncoding. |
| 1106 SkScalar advance{0.0f}; | 1324 write_utf16be(out, unichar); // first char |
| 1107 SkPoint xy{0.0f, 0.0f}; | 1325 while (textPtr < textEnd) { |
| 1108 if (!defaultPositioning) { | 1326 unichar = SkUTF8_NextUnichar(&textPtr); |
| 1109 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; | 1327 write_utf16be(out, unichar); |
| 1110 xy = SkTextBlob::kFull_Positioning == positioning | 1328 } |
| 1111 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | 1329 out->writeText("> >> BDC\n"); // begin marked-content sequence |
| 1112 : SkPoint{pos[index], 0}; | 1330 // with an associated property li st. |
| 1113 if (alignment != SkPaint::kLeft_Align) { | 1331 actualText = true; |
| 1114 xy.offset(alignmentFactor * advance, 0); | |
| 1115 } | 1332 } |
| 1116 } | 1333 } |
| 1117 SkGlyphID encodedGlyph = | 1334 for (; index < glyphLimit; ++index) { |
| 1118 multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); | 1335 SkGlyphID gid = glyphs[index]; |
| 1119 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | 1336 if (gid > maxGlyphID) { |
| 1337 continue; | |
| 1338 } | |
| 1339 if (!font || !font->hasGlyph(gid)) { | |
| 1340 // Not yet specified font or need to switch font. | |
| 1341 int fontIndex = this->getFontResourceIndex(typeface, gid); | |
| 1342 // All preconditions for SkPDFFont::GetFontResource are met. | |
| 1343 SkASSERT(fontIndex >= 0); | |
| 1344 if (fontIndex < 0) { | |
| 1345 return; | |
| 1346 } | |
| 1347 glyphPositioner.flush(); | |
| 1348 update_font(out, fontIndex, textSize); | |
| 1349 font = fFontResources[fontIndex]; | |
| 1350 SkASSERT(font); // All preconditions for SkPDFFont::GetFontReso urce are met. | |
| 1351 if (!font) { | |
| 1352 return; | |
| 1353 } | |
| 1354 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); | |
| 1355 } | |
| 1356 SkPoint xy{0, 0}; | |
| 1357 SkScalar advance{0}; | |
| 1358 if (!defaultPositioning) { | |
| 1359 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; | |
| 1360 xy = SkTextBlob::kFull_Positioning == positioning | |
| 1361 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | |
| 1362 : SkPoint{pos[index], 0}; | |
| 1363 if (alignment != SkPaint::kLeft_Align) { | |
| 1364 xy.offset(alignmentFactor * advance, 0); | |
| 1365 } | |
| 1366 } | |
| 1367 font->noteGlyphUsage(gid); | |
| 1368 SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFon tEncoding(gid); | |
| 1369 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | |
| 1370 } | |
| 1120 } | 1371 } |
| 1121 } | 1372 } |
| 1122 | 1373 |
| 1123 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1374 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
| 1124 SkScalar x, SkScalar y, const SkPaint& paint) { | 1375 SkScalar x, SkScalar y, const SkPaint& paint) { |
| 1125 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, | 1376 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, |
| 1126 SkPoint{x, y}, paint, nullptr, 0, nullptr); | 1377 SkPoint{x, y}, paint, nullptr, 0, nullptr); |
| 1127 } | 1378 } |
| 1128 | 1379 |
| 1129 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1380 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... | |
| 2039 } | 2290 } |
| 2040 | 2291 |
| 2041 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2292 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
| 2042 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), | 2293 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), |
| 2043 image->makeNonTextureImage()); | 2294 image->makeNonTextureImage()); |
| 2044 } | 2295 } |
| 2045 | 2296 |
| 2046 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2297 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
| 2047 return nullptr; | 2298 return nullptr; |
| 2048 } | 2299 } |
| OLD | NEW |