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. | |
bungeman-skia
2016/09/13 22:08:05
nit: this is a doc comment (not an implementation
hal.canary
2016/09/14 01:36:37
Done.
| |
930 class Clusterator { | |
931 public: | |
932 Clusterator(int glyphCount = 0) | |
bungeman-skia
2016/09/13 22:08:05
Should be marked explicit. Is there a good reason
hal.canary
2016/09/14 01:36:37
Done.
I also want an "empty Clusterator" construc
| |
933 : fClusters(nullptr) | |
934 , fGlyphCount(SkToU32(glyphCount)) | |
bungeman-skia
2016/09/13 22:08:05
Seems strange to take an int for glyphCount and th
hal.canary
2016/09/14 01:36:37
Done.
| |
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 | |
bungeman-skia
2016/09/13 22:08:05
nit: doc comment
hal.canary
2016/09/14 01:36:37
Done.
| |
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 | |
968 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { | 1164 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { |
969 wStream->writeText("/"); | 1165 wStream->writeText("/"); |
970 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF ont_ResourceType); | 1166 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF ont_ResourceType); |
971 wStream->write(&prefix, 1); | 1167 wStream->write(&prefix, 1); |
972 wStream->writeDecAsText(fontIndex); | 1168 wStream->writeDecAsText(fontIndex); |
973 wStream->writeText(" "); | 1169 wStream->writeText(" "); |
974 SkPDFUtils::AppendScalar(textSize, wStream); | 1170 SkPDFUtils::AppendScalar(textSize, wStream); |
975 wStream->writeText(" Tf\n"); | 1171 wStream->writeText(" Tf\n"); |
976 } | 1172 } |
977 | 1173 |
978 void SkPDFDevice::internalDrawText( | 1174 void SkPDFDevice::internalDrawText( |
979 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 1175 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
980 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 1176 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
981 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, | 1177 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, |
982 uint32_t textByteLength, const char* utf8Text) { | 1178 uint32_t textByteLength, const char* utf8Text) { |
983 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 1179 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
984 if (srcPaint.getMaskFilter() != nullptr) { | 1180 if (srcPaint.getMaskFilter() != nullptr) { |
985 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 1181 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
986 // making text unreadable (e.g. same text twice when using CSS shadows). | 1182 // making text unreadable (e.g. same text twice when using CSS shadows). |
987 return; | 1183 return; |
988 } | 1184 } |
989 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); | 1185 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); |
990 if (srcPaint.isVerticalText()) { | 1186 if (srcPaint.isVerticalText()) { |
991 // Don't pretend we support drawing vertical text. It is not | 1187 // Don't pretend we support drawing vertical text. It is not |
992 // clear to me how to switch to "vertical writing" mode in PDF. | 1188 // clear to me how to switch to "vertical writing" mode in PDF. |
993 // Currently neither Chromium or Android set this flag. | 1189 // Currently neither Chromium or Android set this flag. |
994 // https://bug.skia.org/5665 | 1190 // https://bug.skia.org/5665 |
995 return; | 1191 return; |
996 } | 1192 } |
997 // TODO(halcanary): implement /ActualText with these values. | 1193 if (0 == sourceByteCount || !sourceText) { |
998 (void)clusters; | 1194 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 } | 1195 } |
1009 | |
1010 SkPaint paint = calculate_text_paint(srcPaint); | 1196 SkPaint paint = calculate_text_paint(srcPaint); |
1011 replace_srcmode_on_opaque_paint(&paint); | 1197 replace_srcmode_on_opaque_paint(&paint); |
1012 if (!paint.getTypeface()) { | 1198 if (!paint.getTypeface()) { |
1013 paint.setTypeface(SkTypeface::MakeDefault()); | 1199 paint.setTypeface(SkTypeface::MakeDefault()); |
1014 } | 1200 } |
1015 SkTypeface* typeface = paint.getTypeface(); | 1201 SkTypeface* typeface = paint.getTypeface(); |
1016 if (!typeface) { | 1202 if (!typeface) { |
1017 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); | 1203 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
1018 return; | 1204 return; |
1019 } | 1205 } |
1020 | 1206 |
1021 const SkAdvancedTypefaceMetrics* metrics = | 1207 const SkAdvancedTypefaceMetrics* metrics = |
1022 SkPDFFont::GetMetrics(typeface, fDocument->canon()); | 1208 SkPDFFont::GetMetrics(typeface, fDocument->canon()); |
1023 if (!metrics) { | 1209 if (!metrics) { |
1024 return; | 1210 return; |
1025 } | 1211 } |
1026 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. | 1212 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. |
1027 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; | |
1028 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { | 1213 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
1029 SkPath path; // https://bug.skia.org/3866 | 1214 SkPath path; // https://bug.skia.org/3866 |
1030 paint.getTextPath(sourceText, sourceByteCount, | 1215 paint.getTextPath(sourceText, sourceByteCount, |
1031 offset.x(), offset.y(), &path); | 1216 offset.x(), offset.y(), &path); |
1032 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1217 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
1033 // Draw text transparently to make it copyable/searchable/accessable. | 1218 // Draw text transparently to make it copyable/searchable/accessable. |
1034 draw_transparent_text(this, d, sourceText, sourceByteCount, | 1219 draw_transparent_text(this, d, sourceText, sourceByteCount, |
1035 offset.x(), offset.y(), paint); | 1220 offset.x(), offset.y(), paint); |
1036 return; | 1221 return; |
1037 } | 1222 } |
1038 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); | 1223 |
1039 if (glyphCount <= 0) { | 1224 // These three heap buffers are only used in the case where no glyphs |
1225 // are passed to drawText() (most clients pass glyphs or a textblob). | |
1226 TextStorage storage; | |
1227 int glyphCount = 0; | |
1228 const SkGlyphID* glyphs = nullptr; | |
1229 Clusterator clusterator; | |
1230 if (textByteLength > 0) { | |
1231 glyphCount = SkToInt(sourceByteCount / sizeof(SkGlyphID)); | |
1232 glyphs = (const SkGlyphID*)sourceText; | |
1233 clusterator = Clusterator(clusters, glyphCount, textByteLength, utf8Text ); | |
1234 SkASSERT(clusters); | |
1235 SkASSERT(utf8Text); | |
1236 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); | |
1237 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n ullptr)); | |
1238 } else if (SkPaint::kGlyphID_TextEncoding == srcPaint.getTextEncoding()) { | |
1239 glyphCount = SkToInt(sourceByteCount / sizeof(SkGlyphID)); | |
1240 glyphs = (const SkGlyphID*)sourceText; | |
1241 clusterator = Clusterator(glyphCount); | |
1242 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n ullptr)); | |
1243 SkASSERT(nullptr == clusters); | |
1244 SkASSERT(nullptr == utf8Text); | |
1245 } else { | |
1246 SkASSERT(nullptr == clusters); | |
1247 SkASSERT(nullptr == utf8Text); | |
1248 clusterator = make_clusterator(sourceText, sourceByteCount, srcPaint, | |
1249 &storage, &glyphCount); | |
1250 glyphs = storage.fGlyphStorage; | |
1251 } | |
1252 if (0 == glyphCount) { | |
1040 return; | 1253 return; |
1041 } | 1254 } |
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); | 1255 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
1055 paint.setHinting(SkPaint::kNo_Hinting); | 1256 paint.setHinting(SkPaint::kNo_Hinting); |
1056 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); | 1257 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
1057 | 1258 |
1058 SkPaint::Align alignment = paint.getTextAlign(); | 1259 SkPaint::Align alignment = paint.getTextAlign(); |
1059 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : | 1260 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : |
1060 SkPaint::kCenter_Align == alignment ? -0.5f : | 1261 SkPaint::kCenter_Align == alignment ? -0.5f : |
1061 /* SkPaint::kRight_Align */ -1.0f; | 1262 /* SkPaint::kRight_Align */ -1.0f; |
1062 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { | 1263 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
1063 SkScalar advance = 0; | 1264 SkScalar advance = 0; |
1064 for (int i = 0; i < glyphCount; ++i) { | 1265 for (int i = 0; i < glyphCount; ++i) { |
1065 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; | 1266 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
1066 } | 1267 } |
1067 offset.offset(alignmentFactor * advance, 0); | 1268 offset.offset(alignmentFactor * advance, 0); |
1068 } | 1269 } |
1069 ScopedContentEntry content(this, d, paint, true); | 1270 ScopedContentEntry content(this, d, paint, true); |
1070 if (!content.entry()) { | 1271 if (!content.entry()) { |
1071 return; | 1272 return; |
1072 } | 1273 } |
1073 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1274 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
1074 SkScalar textSize = paint.getTextSize(); | 1275 SkScalar textSize = paint.getTextSize(); |
1276 const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode; | |
1075 | 1277 |
1076 out->writeText("BT\n"); | 1278 out->writeText("BT\n"); |
1077 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); | 1279 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); |
1078 | 1280 |
1281 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; | |
1079 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)) ; | 1282 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)) ; |
1283 if (clusterator.reversedChars()) { | |
1284 out->writeText("/ReversedChars BMC\n"); | |
1285 } | |
1286 SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("EMC\n"); } ); | |
1080 GlyphPositioner glyphPositioner(out, | 1287 GlyphPositioner glyphPositioner(out, |
1081 paint.getTextSkewX(), | 1288 paint.getTextSkewX(), |
1082 multiByteGlyphs, | 1289 multiByteGlyphs, |
1083 defaultPositioning, | 1290 defaultPositioning, |
1084 offset); | 1291 offset); |
1085 SkPDFFont* font = nullptr; | 1292 SkPDFFont* font = nullptr; |
1086 for (int index = 0; index < glyphCount; ++index) { | 1293 |
1087 SkGlyphID gid = glyphs[index]; | 1294 while (Clusterator::Cluster c = clusterator.next()) { |
1088 if (gid > maxGlyphID) { | 1295 int index = c.fGlyphIndex; |
1089 continue; // Skip this invalid glyphID. | 1296 int glyphLimit = index + c.fGlyphCount; |
1090 } | 1297 |
1091 if (!font || !font->hasGlyph(gid)) { | 1298 bool actualText = false; |
1092 // Either this is the first loop iteration or the current | 1299 SK_AT_SCOPE_EXIT(if (actualText) { glyphPositioner.flush(); out->writeTe xt("EMC\n"); } ); |
bungeman-skia
2016/09/13 22:08:05
I really wish there were a better way to structure
hal.canary
2016/09/14 01:36:37
Acknowledged.
| |
1093 // PDFFont cannot encode this glyph. | 1300 if (c.fUtf8Text) { // real cluster |
1094 glyphPositioner.flush(); | 1301 // Check if `/ActualText` needed. |
1095 // Try to get a font which can encode the glyph. | 1302 const char* textPtr = c.fUtf8Text; |
1096 int fontIndex = this->getFontResourceIndex(typeface, gid); | 1303 // TODO(halcanary): validate utf8 input. |
1097 SkASSERT(fontIndex >= 0); | 1304 SkUnichar unichar = SkUTF8_NextUnichar(&textPtr); |
1098 if (fontIndex < 0) { return; } | 1305 const char* textEnd = c.fUtf8Text + c.fTextByteLength; |
1099 update_font(out, fontIndex, textSize); | 1306 if (textPtr < textEnd || // more characters left |
1100 font = fFontResources[fontIndex]; | 1307 glyphLimit > index + 1 || // toUni code wouldn't work |
1101 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met. | 1308 unichar != map_glyph(glyphToUnicode, glyphs[index])) { // test single Unichar map |
bungeman-skia
2016/09/13 22:08:05
The '{' being at the end of this line makes it dif
hal.canary
2016/09/14 01:36:37
Done.
| |
1102 if (!font) { return; } | 1309 glyphPositioner.flush(); |
1103 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); | 1310 out->writeText("/Span<</ActualText <"); |
1104 } | 1311 SkPDFUtils::WriteUTF16beHex(out, 0xFEFF); // U+FEFF = BYTE ORDE R MARK |
1105 font->noteGlyphUsage(gid); | 1312 // the BOM marks this text as UTF-16BE, not PDFDocEncoding. |
1106 SkScalar advance{0.0f}; | 1313 SkPDFUtils::WriteUTF16beHex(out, unichar); // first char |
1107 SkPoint xy{0.0f, 0.0f}; | 1314 while (textPtr < textEnd) { |
1108 if (!defaultPositioning) { | 1315 unichar = SkUTF8_NextUnichar(&textPtr); |
1109 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; | 1316 SkPDFUtils::WriteUTF16beHex(out, unichar); |
1110 xy = SkTextBlob::kFull_Positioning == positioning | 1317 } |
1111 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | 1318 out->writeText("> >> BDC\n"); // begin marked-content sequence |
1112 : SkPoint{pos[index], 0}; | 1319 // with an associated property li st. |
1113 if (alignment != SkPaint::kLeft_Align) { | 1320 actualText = true; |
1114 xy.offset(alignmentFactor * advance, 0); | |
1115 } | 1321 } |
1116 } | 1322 } |
1117 SkGlyphID encodedGlyph = | 1323 for (; index < glyphLimit; ++index) { |
1118 multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); | 1324 SkGlyphID gid = glyphs[index]; |
1119 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | 1325 if (gid > maxGlyphID) { |
1326 continue; | |
1327 } | |
1328 if (!font || !font->hasGlyph(gid)) { | |
1329 // Not yet specified font or need to switch font. | |
1330 int fontIndex = this->getFontResourceIndex(typeface, gid); | |
1331 // All preconditions for SkPDFFont::GetFontResource are met. | |
1332 SkASSERT(fontIndex >= 0); | |
1333 if (fontIndex < 0) { | |
1334 return; | |
1335 } | |
1336 glyphPositioner.flush(); | |
1337 update_font(out, fontIndex, textSize); | |
1338 font = fFontResources[fontIndex]; | |
1339 SkASSERT(font); // All preconditions for SkPDFFont::GetFontReso urce are met. | |
1340 if (!font) { | |
1341 return; | |
1342 } | |
1343 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); | |
1344 } | |
1345 SkPoint xy{0, 0}; | |
1346 SkScalar advance{0}; | |
1347 if (!defaultPositioning) { | |
1348 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; | |
1349 xy = SkTextBlob::kFull_Positioning == positioning | |
1350 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | |
1351 : SkPoint{pos[index], 0}; | |
1352 if (alignment != SkPaint::kLeft_Align) { | |
1353 xy.offset(alignmentFactor * advance, 0); | |
1354 } | |
1355 } | |
1356 font->noteGlyphUsage(gid); | |
1357 SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFon tEncoding(gid); | |
1358 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | |
1359 } | |
1120 } | 1360 } |
1121 } | 1361 } |
1122 | 1362 |
1123 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1363 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1124 SkScalar x, SkScalar y, const SkPaint& paint) { | 1364 SkScalar x, SkScalar y, const SkPaint& paint) { |
1125 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, | 1365 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, |
1126 SkPoint{x, y}, paint, nullptr, 0, nullptr); | 1366 SkPoint{x, y}, paint, nullptr, 0, nullptr); |
1127 } | 1367 } |
1128 | 1368 |
1129 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1369 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 } | 2279 } |
2040 | 2280 |
2041 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2281 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2042 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), | 2282 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), |
2043 image->makeNonTextureImage()); | 2283 image->makeNonTextureImage()); |
2044 } | 2284 } |
2045 | 2285 |
2046 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2286 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2047 return nullptr; | 2287 return nullptr; |
2048 } | 2288 } |
OLD | NEW |