aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Hal Canary <halcanary@google.com>2018-07-23 10:50:49 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-23 15:14:24 +0000
commit98caedd213775b61d93a320909e947735c626968 (patch)
tree89d5a6867a44c99d315e9063fc2ae19043485058 /src
parent5e6cd2affe41af71399c247fcd144e8d28a3ec16 (diff)
SkPDF: only draw text with SkglyphRuns
Change-Id: I24e79c73a9c65a5d6a974bf52b0d0aee21be07db Reviewed-on: https://skia-review.googlesource.com/142695 Commit-Queue: Hal Canary <halcanary@google.com> Reviewed-by: Herb Derby <herb@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/pdf/SkClusterator.cpp98
-rw-r--r--src/pdf/SkClusterator.h17
-rw-r--r--src/pdf/SkPDFDevice.cpp182
-rw-r--r--src/pdf/SkPDFDevice.h6
4 files changed, 71 insertions, 232 deletions
diff --git a/src/pdf/SkClusterator.cpp b/src/pdf/SkClusterator.cpp
index 6c56eb6b45..1b74d38f11 100644
--- a/src/pdf/SkClusterator.cpp
+++ b/src/pdf/SkClusterator.cpp
@@ -7,6 +7,7 @@
#include "SkClusterator.h"
+#include "SkGlyphRun.h"
#include "SkTo.h"
#include "SkUtils.h"
@@ -24,90 +25,18 @@ static bool is_reversed(const uint32_t* clusters, uint32_t count) {
return true;
}
-SkClusterator::SkClusterator(const void* sourceText,
- size_t sourceByteCount,
- const SkPaint& paint,
- const uint32_t* clusters,
- uint32_t utf8TextByteLength,
- const char* utf8Text) {
- if (SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding()) {
- fGlyphs = reinterpret_cast<const SkGlyphID*>(sourceText);
- fClusters = clusters;
- fUtf8Text = utf8Text;
- fGlyphCount = sourceByteCount / sizeof(SkGlyphID);
- fTextByteLength = utf8TextByteLength;
- if (fClusters) {
- SkASSERT(fUtf8Text && fTextByteLength > 0 && fGlyphCount > 0);
- fReversedChars = is_reversed(fClusters, fGlyphCount);
- } else {
- SkASSERT(!fUtf8Text && fTextByteLength == 0);
- }
- return;
- }
-
- // If Skia is given text (not glyphs), then our fallback primitive shaping will
- // produce a simple 1-1 cluster mapping.
- fGlyphCount = SkToU32(paint.textToGlyphs(sourceText, sourceByteCount, nullptr));
- fGlyphStorage.resize(fGlyphCount);
- (void)paint.textToGlyphs(sourceText, sourceByteCount, fGlyphStorage.data());
- fGlyphs = fGlyphStorage.data();
- fClusterStorage.resize(fGlyphCount);
- fClusters = fClusterStorage.data();
-
- switch (paint.getTextEncoding()) {
- case SkPaint::kUTF8_TextEncoding:
- {
- fUtf8Text = reinterpret_cast<const char*>(sourceText);
- fTextByteLength = SkToU32(sourceByteCount);
- const char* txtPtr = fUtf8Text;
- for (uint32_t i = 0; i < fGlyphCount; ++i) {
- fClusterStorage[i] = SkToU32(txtPtr - fUtf8Text);
- txtPtr += SkUTF8_LeadByteToCount(*(const unsigned char*)txtPtr);
- SkASSERT(txtPtr <= fUtf8Text + sourceByteCount);
- }
- SkASSERT(txtPtr == fUtf8Text + sourceByteCount);
- return;
- }
- case SkPaint::kUTF16_TextEncoding:
- {
- const uint16_t* utf16ptr = reinterpret_cast<const uint16_t*>(sourceText);
- int utf16count = SkToInt(sourceByteCount / sizeof(uint16_t));
- fTextByteLength = SkToU32(SkUTF16_ToUTF8(utf16ptr, utf16count));
- fUtf8textStorage.resize(fTextByteLength);
- fUtf8Text = fUtf8textStorage.data();
- char* txtPtr = fUtf8textStorage.data();
- uint32_t clusterIndex = 0;
- while (utf16ptr < (const uint16_t*)sourceText + utf16count) {
- fClusterStorage[clusterIndex++] = SkToU32(txtPtr - fUtf8Text);
- SkUnichar uni = SkUTF16_NextUnichar(&utf16ptr);
- txtPtr += SkUTF8_FromUnichar(uni, txtPtr);
- }
- SkASSERT(clusterIndex == fGlyphCount);
- SkASSERT(txtPtr == fUtf8textStorage.data() + fTextByteLength);
- SkASSERT(utf16ptr == (const uint16_t*)sourceText + utf16count);
- return;
- }
- case SkPaint::kUTF32_TextEncoding:
- {
- const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(sourceText);
- uint32_t utf32count = SkToU32(sourceByteCount / sizeof(SkUnichar));
- SkASSERT(fGlyphCount == utf32count);
- fTextByteLength = 0;
- for (uint32_t i = 0; i < utf32count; ++i) {
- fTextByteLength += SkToU32(SkUTF8_FromUnichar(utf32[i]));
- }
- fUtf8textStorage.resize(SkToSizeT(fTextByteLength));
- fUtf8Text = fUtf8textStorage.data();
- char* txtPtr = fUtf8textStorage.data();
- for (uint32_t i = 0; i < utf32count; ++i) {
- fClusterStorage[i] = SkToU32(txtPtr - fUtf8Text);
- txtPtr += SkUTF8_FromUnichar(utf32[i], txtPtr);
- }
- return;
- }
- default:
- SkDEBUGFAIL("");
- break;
+SkClusterator::SkClusterator(const SkGlyphRun& run)
+ : fClusters(run.clusters().data())
+ , fUtf8Text(run.text().data())
+ , fGlyphCount(SkToU32(run.shuntGlyphsIDs().size()))
+ , fTextByteLength(SkToU32(run.text().size()))
+{
+ SkASSERT(SkPaint::kGlyphID_TextEncoding == run.paint().getTextEncoding());
+ if (fClusters) {
+ SkASSERT(fUtf8Text && fTextByteLength > 0 && fGlyphCount > 0);
+ fReversedChars = is_reversed(fClusters, fGlyphCount);
+ } else {
+ SkASSERT(!fUtf8Text && fTextByteLength == 0);
}
}
@@ -134,4 +63,3 @@ SkClusterator::Cluster SkClusterator::next() {
uint32_t clusterLen = clusterEnd - cluster;
return Cluster{fUtf8Text + cluster, clusterLen, clusterGlyphIndex, clusterGlyphCount};
}
-
diff --git a/src/pdf/SkClusterator.h b/src/pdf/SkClusterator.h
index 97aded2197..40d9994ba3 100644
--- a/src/pdf/SkClusterator.h
+++ b/src/pdf/SkClusterator.h
@@ -8,21 +8,15 @@
#define SkClusterator_DEFINED
#include <vector>
+#include <cstdint>
-#include "SkTypes.h"
-#include "SkPaint.h"
+class SkGlyphRun;
/** Given the m-to-n glyph-to-character mapping data (as returned by
harfbuzz), iterate over the clusters. */
class SkClusterator {
public:
- SkClusterator(const void* sourceText,
- size_t sourceByteCount,
- const SkPaint& paint,
- const uint32_t* clusters,
- uint32_t utf8TextByteLength,
- const char* utf8Text);
- const SkGlyphID* glyphs() const { return fGlyphs; }
+ SkClusterator(const SkGlyphRun& run);
uint32_t glyphCount() const { return fGlyphCount; }
bool reversedChars() const { return fReversedChars; }
struct Cluster {
@@ -37,15 +31,10 @@ public:
&& fGlyphIndex == o.fGlyphIndex
&& fGlyphCount == o.fGlyphCount;
}
-
};
Cluster next();
private:
- std::vector<SkGlyphID> fGlyphStorage;
- std::vector<char> fUtf8textStorage;
- std::vector<uint32_t> fClusterStorage;
- const SkGlyphID* fGlyphs;
const uint32_t* fClusters;
const char* fUtf8Text;
uint32_t fGlyphCount;
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index d7a0f501c1..88955a1b9c 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1033,13 +1033,11 @@ public:
GlyphPositioner(SkDynamicMemoryWStream* content,
SkScalar textSkewX,
bool wideChars,
- bool defaultPositioning,
SkPoint origin)
: fContent(content)
, fCurrentMatrixOrigin(origin)
, fTextSkewX(textSkewX)
- , fWideChars(wideChars)
- , fDefaultPositioning(defaultPositioning) {
+ , fWideChars(wideChars) {
}
~GlyphPositioner() { this->flush(); }
void flush() {
@@ -1064,19 +1062,17 @@ public:
fCurrentMatrixOrigin.set(0.0f, 0.0f);
fInitialized = true;
}
- if (!fDefaultPositioning) {
- SkPoint position = xy - fCurrentMatrixOrigin;
- if (position != SkPoint{fXAdvance, 0}) {
- this->flush();
- SkPDFUtils::AppendScalar(position.x() - position.y() * fTextSkewX, fContent);
- fContent->writeText(" ");
- SkPDFUtils::AppendScalar(-position.y(), fContent);
- fContent->writeText(" Td ");
- fCurrentMatrixOrigin = xy;
- fXAdvance = 0;
- }
- fXAdvance += advanceWidth;
+ SkPoint position = xy - fCurrentMatrixOrigin;
+ if (position != SkPoint{fXAdvance, 0}) {
+ this->flush();
+ SkPDFUtils::AppendScalar(position.x() - position.y() * fTextSkewX, fContent);
+ fContent->writeText(" ");
+ SkPDFUtils::AppendScalar(-position.y(), fContent);
+ fContent->writeText(" Td ");
+ fCurrentMatrixOrigin = xy;
+ fXAdvance = 0;
}
+ fXAdvance += advanceWidth;
if (!fInText) {
fContent->writeText("<");
fInText = true;
@@ -1097,7 +1093,6 @@ private:
bool fWideChars;
bool fInText = false;
bool fInitialized = false;
- const bool fDefaultPositioning;
};
} // namespace
@@ -1115,30 +1110,15 @@ static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) {
wStream->writeText(" Tf\n");
}
-static SkPath draw_text_as_path(const void* sourceText, size_t sourceByteCount,
- const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
- SkPoint offset, const SkPaint& srcPaint) {
+static void draw_glyph_run_as_path(SkPDFDevice* dev, const SkGlyphRun& glyphRun, SkPoint offset) {
SkPath path;
- int glyphCount;
- SkAutoTMalloc<SkPoint> tmpPoints;
- switch (positioning) {
- case SkTextBlob::kDefault_Positioning:
- srcPaint.getTextPath(sourceText, sourceByteCount, offset.x(), offset.y(), &path);
- break;
- case SkTextBlob::kHorizontal_Positioning:
- glyphCount = srcPaint.countText(sourceText, sourceByteCount);
- tmpPoints.realloc(glyphCount);
- for (int i = 0; i < glyphCount; ++i) {
- tmpPoints[i] = {pos[i] + offset.x(), offset.y()};
- }
- srcPaint.getPosTextPath(sourceText, sourceByteCount, tmpPoints.get(), &path);
- break;
- case SkTextBlob::kFull_Positioning:
- srcPaint.getPosTextPath(sourceText, sourceByteCount, (const SkPoint*)pos, &path);
- path.offset(offset.x(), offset.y());
- break;
- }
- return path;
+ SkASSERT(glyphRun.paint().getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+ glyphRun.paint().getPosTextPath(glyphRun.shuntGlyphsIDs().data(),
+ glyphRun.shuntGlyphsIDs().size() * sizeof(SkGlyphID),
+ glyphRun.positions().data(),
+ &path);
+ path.offset(offset.x(), offset.y());
+ dev->drawPath(path, glyphRun.paint(), nullptr, true);
}
static bool has_outline_glyph(SkGlyphID gid, SkGlyphCache* cache) {
@@ -1205,36 +1185,25 @@ static sk_sp<SkImage> image_from_mask(const SkMask& mask) {
}
}
-void SkPDFDevice::internalDrawText(
- const void* sourceText, size_t sourceByteCount,
- const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
- SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters,
- uint32_t textByteLength, const char* utf8Text) {
- if (0 == sourceByteCount || !sourceText || srcPaint.getTextSize() <= 0) {
- return;
- }
- if (this->hasEmptyClip()) {
+void SkPDFDevice::internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset) {
+
+ const SkGlyphID* glyphs = glyphRun.shuntGlyphsIDs().data();
+ uint32_t glyphCount = SkToU32(glyphRun.shuntGlyphsIDs().size());
+ const SkPaint& srcPaint = glyphRun.paint();
+ if (!glyphCount || !glyphs || srcPaint.getTextSize() <= 0 || this->hasEmptyClip()) {
return;
}
- NOT_IMPLEMENTED(srcPaint.isVerticalText(), false);
- if (srcPaint.isVerticalText()) {
- // Don't pretend we support drawing vertical text. It is not
- // clear to me how to switch to "vertical writing" mode in PDF.
- // Currently neither Chromium or Android set this flag.
- // https://bug.skia.org/5665
- }
if (srcPaint.getPathEffect()
- || srcPaint.getMaskFilter()
- || SkPaint::kFill_Style != srcPaint.getStyle()) {
+ || srcPaint.getMaskFilter()
+ || srcPaint.isVerticalText()
+ || SkPaint::kFill_Style != srcPaint.getStyle()) {
// Stroked Text doesn't work well with Type3 fonts.
- SkPath path = draw_text_as_path(sourceText, sourceByteCount, pos,
- positioning, offset, srcPaint);
- this->drawPath(path, srcPaint, nullptr, true);
- return;
+ return draw_glyph_run_as_path(this, glyphRun, offset);
}
SkPaint paint = calculate_text_paint(srcPaint);
remove_color_filter(&paint);
replace_srcmode_on_opaque_paint(&paint);
+ paint.setHinting(SkPaint::kNo_Hinting);
if (!paint.getTypeface()) {
paint.setTypeface(SkTypeface::MakeDefault());
}
@@ -1243,25 +1212,14 @@ void SkPDFDevice::internalDrawText(
SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
return;
}
-
- const SkAdvancedTypefaceMetrics* metrics =
- SkPDFFont::GetMetrics(typeface, fDocument->canon());
+ const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, fDocument->canon());
if (!metrics) {
return;
}
const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(
typeface, fDocument->canon());
- SkClusterator clusterator(sourceText, sourceByteCount, paint,
- clusters, textByteLength, utf8Text);
- const SkGlyphID* glyphs = clusterator.glyphs();
- uint32_t glyphCount = clusterator.glyphCount();
- if (glyphCount == 0) {
- return;
- }
-
- bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
- paint.setHinting(SkPaint::kNo_Hinting);
+ SkClusterator clusterator(glyphRun);
int emSize;
auto glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize);
@@ -1273,23 +1231,13 @@ void SkPDFDevice::internalDrawText(
SkScalar textScaleY = textSize / emSize;
SkScalar textScaleX = advanceScale + paint.getTextSkewX() * textScaleY;
- SkPaint::Align alignment = paint.getTextAlign();
- float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f :
- SkPaint::kCenter_Align == alignment ? -0.5f :
- /* SkPaint::kRight_Align */ -1.0f;
- if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
- SkScalar advance = 0;
- for (uint32_t i = 0; i < glyphCount; ++i) {
- advance += advanceScale * glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
- }
- offset.offset(alignmentFactor * advance, 0);
- }
+ SkASSERT(paint.getTextAlign() == SkPaint::kLeft_Align);
SkRect clipStackBounds = this->cs().bounds(this->bounds());
struct PositionedGlyph {
SkPoint fPos;
SkGlyphID fGlyph;
};
- SkTArray<PositionedGlyph> fMissingGlyphs;
+ SkTArray<PositionedGlyph> missingGlyphs;
{
ScopedContentEntry content(this, paint, true);
if (!content.entry()) {
@@ -1310,7 +1258,6 @@ void SkPDFDevice::internalDrawText(
GlyphPositioner glyphPositioner(out,
paint.getTextSkewX(),
multiByteGlyphs,
- defaultPositioning,
offset);
SkPDFFont* font = nullptr;
@@ -1374,45 +1321,33 @@ void SkPDFDevice::internalDrawText(
}
SkASSERT(font->multiByteGlyphs() == multiByteGlyphs);
}
- SkPoint xy = {0, 0};
- SkScalar advance = advanceScale * glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
- if (!defaultPositioning) {
- xy = SkTextBlob::kFull_Positioning == positioning
- ? SkPoint{pos[2 * index], pos[2 * index + 1]}
- : SkPoint{pos[index], 0};
- if (alignment != SkPaint::kLeft_Align) {
- xy.offset(alignmentFactor * advance, 0);
- }
- // Do a glyph-by-glyph bounds-reject if positions are absolute.
- SkRect glyphBounds = get_glyph_bounds_device_space(
- gid, glyphCache.get(), textScaleX, textScaleY,
- xy + offset, this->ctm());
- if (glyphBounds.isEmpty()) {
- if (!contains(clipStackBounds, {glyphBounds.x(), glyphBounds.y()})) {
- continue;
- }
- } else {
- if (!clipStackBounds.intersects(glyphBounds)) {
- continue; // reject glyphs as out of bounds
- }
- }
- if (!has_outline_glyph(gid, glyphCache.get())) {
- fMissingGlyphs.push_back({xy + offset, gid});
+ SkPoint xy = glyphRun.positions()[index];
+ // Do a glyph-by-glyph bounds-reject if positions are absolute.
+ SkRect glyphBounds = get_glyph_bounds_device_space(
+ gid, glyphCache.get(), textScaleX, textScaleY,
+ xy + offset, this->ctm());
+ if (glyphBounds.isEmpty()) {
+ if (!contains(clipStackBounds, {glyphBounds.x(), glyphBounds.y()})) {
+ continue;
}
} else {
- if (!has_outline_glyph(gid, glyphCache.get())) {
- fMissingGlyphs.push_back({offset, gid});
+ if (!clipStackBounds.intersects(glyphBounds)) {
+ continue; // reject glyphs as out of bounds
}
- offset += SkPoint{advance, 0};
}
+ if (!has_outline_glyph(gid, glyphCache.get())) {
+ missingGlyphs.push_back({xy + offset, gid});
+ }
+
font->noteGlyphUsage(gid);
SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid);
+ SkScalar advance = advanceScale * glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
}
}
}
- if (fMissingGlyphs.count() > 0) {
+ if (missingGlyphs.count() > 0) {
// Fall back on images.
SkPaint scaledGlyphCachePaint;
scaledGlyphCachePaint.setTextSize(paint.getTextSize());
@@ -1422,7 +1357,7 @@ void SkPDFDevice::internalDrawText(
auto scaledGlyphCache = SkStrikeCache::FindOrCreateStrikeExclusive(scaledGlyphCachePaint);
SkTHashMap<SkPDFCanon::BitmapGlyphKey, SkPDFCanon::BitmapGlyph>* map =
&this->getCanon()->fBitmapGlyphImages;
- for (PositionedGlyph positionedGlyph : fMissingGlyphs) {
+ for (PositionedGlyph positionedGlyph : missingGlyphs) {
SkPDFCanon::BitmapGlyphKey key = {typeface->uniqueID(),
paint.getTextSize(),
paint.getTextScaleX(),
@@ -1451,20 +1386,9 @@ void SkPDFDevice::internalDrawText(
}
}
-void SkPDFDevice::drawPosText(const void* text, size_t len,
- const SkScalar pos[], int scalarsPerPos,
- const SkPoint& offset, const SkPaint& paint) {
- this->internalDrawText(text, len, pos, (SkTextBlob::GlyphPositioning)scalarsPerPos,
- offset, paint, nullptr, 0, nullptr);
-}
-
void SkPDFDevice::drawGlyphRunList(SkGlyphRunList* glyphRunList) {
- for (SkGlyphRunListIterator it(glyphRunList); !it.done(); it.next()) {
- SkPaint runPaint;
- it.applyFontToPaint(&runPaint);
- this->internalDrawText(it.glyphs(), sizeof(SkGlyphID) * it.glyphCount(),
- it.pos(), it.positioning(), glyphRunList->origin(), runPaint,
- it.clusters(), it.textSize(), it.text());
+ for (const SkGlyphRun& glyphRun : *glyphRunList) {
+ this->internalDrawGlyphRun(glyphRun, glyphRunList->origin());
}
}
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index eb293fc8a4..1ef4a20ed6 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -97,7 +97,7 @@ public:
SkCanvas::SrcRectConstraint) override;
void drawPosText(const void* text, size_t len,
const SkScalar pos[], int scalarsPerPos,
- const SkPoint& offset, const SkPaint&) override;
+ const SkPoint& offset, const SkPaint&) override { SkASSERT(false); }
void drawGlyphRunList(SkGlyphRunList* glyphRunList) override;
void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
const SkPaint&) override;
@@ -242,9 +242,7 @@ private:
int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
- void internalDrawText( const void*, size_t, const SkScalar pos[],
- SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&,
- const uint32_t*, uint32_t, const char*);
+ void internalDrawGlyphRun(const SkGlyphRun& glyphRun, SkPoint offset);
void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);