Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: src/pdf/SkPDFDevice.cpp

Issue 2322403002: SkPDF: Implement /ActualText to make text extraction correct. (Closed)
Patch Set: asserts, bounds check before read, not after Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/pdf/SkPDFMakeToUnicodeCmap.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | src/pdf/SkPDFMakeToUnicodeCmap.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698