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

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

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