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>
This commit is contained in:
parent
5e6cd2affe
commit
98caedd213
@ -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};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
if (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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "SkData.h"
|
||||
#include "SkDeflate.h"
|
||||
#include "SkDocument.h"
|
||||
#include "SkGlyphRun.h"
|
||||
#include "SkImageEncoder.h"
|
||||
#include "SkImageFilterPriv.h"
|
||||
#include "SkMakeUnique.h"
|
||||
@ -488,14 +489,30 @@ DEF_TEST(SkPDF_Primitives_Color, reporter) {
|
||||
}
|
||||
}
|
||||
|
||||
static SkGlyphRun make_run(size_t len, const SkGlyphID* glyphs, const SkPoint* pos,
|
||||
SkPaint paint, const uint32_t* clusters,
|
||||
size_t utf8TextByteLength, const char* utf8Text) {
|
||||
return SkGlyphRun(std::move(paint),
|
||||
SkSpan<const uint16_t>{}, // No dense indices for now.
|
||||
SkSpan<const SkPoint>{pos, len},
|
||||
SkSpan<const SkGlyphID>{glyphs, len},
|
||||
SkSpan<const SkGlyphID>{},
|
||||
SkSpan<const char>{utf8Text, utf8TextByteLength},
|
||||
SkSpan<const uint32_t>{clusters, len});
|
||||
}
|
||||
|
||||
DEF_TEST(SkPDF_Clusterator, reporter) {
|
||||
SkPaint paint;
|
||||
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
{
|
||||
const uint32_t clusters[11] = { 3, 2, 2, 1, 0, 4, 4, 7, 6, 6, 5 };
|
||||
const SkGlyphID glyphs[11] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
constexpr unsigned len = 11;
|
||||
const uint32_t clusters[len] = { 3, 2, 2, 1, 0, 4, 4, 7, 6, 6, 5 };
|
||||
const SkGlyphID glyphs[len] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
const SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
|
||||
const char text[] = "abcdefgh";
|
||||
SkClusterator clusterator(glyphs, sizeof(glyphs), paint, clusters, strlen(text), text);
|
||||
SkGlyphRun run = make_run(len, glyphs, pos, paint, clusters, strlen(text), text);
|
||||
SkClusterator clusterator(run);
|
||||
SkClusterator::Cluster expectations[] = {
|
||||
{&text[3], 1, 0, 1},
|
||||
{&text[2], 1, 1, 2},
|
||||
@ -512,10 +529,13 @@ DEF_TEST(SkPDF_Clusterator, reporter) {
|
||||
}
|
||||
}
|
||||
{
|
||||
const uint32_t clusters[5] = { 0, 1, 4, 5, 6 };
|
||||
const SkGlyphID glyphs[5] = { 43, 167, 79, 79, 82, };
|
||||
constexpr unsigned len = 5;
|
||||
const uint32_t clusters[len] = { 0, 1, 4, 5, 6 };
|
||||
const SkGlyphID glyphs[len] = { 43, 167, 79, 79, 82, };
|
||||
const SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
|
||||
const char text[] = "Ha\xCC\x8A" "llo";
|
||||
SkClusterator clusterator(glyphs, sizeof(glyphs), paint, clusters, strlen(text), text);
|
||||
SkGlyphRun run = make_run(len, glyphs, pos, paint, clusters, strlen(text), text);
|
||||
SkClusterator clusterator(run);
|
||||
SkClusterator::Cluster expectations[] = {
|
||||
{&text[0], 1, 0, 1},
|
||||
{&text[1], 3, 1, 1},
|
||||
|
Loading…
Reference in New Issue
Block a user