aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
authorGravatar Herb Derby <herb@google.com>2018-05-29 15:53:40 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-30 04:04:07 +0000
commit264182c3f7d282e57a4b1d46fde3ef702b81c5c3 (patch)
tree85c68bfa138662fd60cc3ab3bcad26f83cb9b80d /tools
parent09725b0c3fd52b008743c63feb09ec1ab8bc2eea (diff)
Make SkShaper a module
Change-Id: I3709e49ba865f14260660cc07a762b9ac837cb3c Reviewed-on: https://skia-review.googlesource.com/130602 Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Herb Derby <herb@google.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/shape/SkShaper.h47
-rw-r--r--tools/shape/SkShaper_harfbuzz.cpp728
-rw-r--r--tools/shape/SkShaper_primitive.cpp76
-rw-r--r--tools/using_skia_and_harfbuzz.cpp (renamed from tools/shape/using_skia_and_harfbuzz.cpp)0
4 files changed, 0 insertions, 851 deletions
diff --git a/tools/shape/SkShaper.h b/tools/shape/SkShaper.h
deleted file mode 100644
index 190a4d834e..0000000000
--- a/tools/shape/SkShaper.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkShaper_DEFINED
-#define SkShaper_DEFINED
-
-#include <memory>
-
-#include "SkPoint.h"
-#include "SkTypeface.h"
-
-class SkPaint;
-class SkTextBlobBuilder;
-
-/**
- Shapes text using HarfBuzz and places the shaped text into a
- TextBlob.
-
- If compiled without HarfBuzz, fall back on SkPaint::textToGlyphs.
- */
-class SkShaper {
-public:
- SkShaper(sk_sp<SkTypeface> face);
- ~SkShaper();
-
- bool good() const;
- SkPoint shape(SkTextBlobBuilder* dest,
- const SkPaint& srcPaint,
- const char* utf8text,
- size_t textBytes,
- bool leftToRight,
- SkPoint point,
- SkScalar width) const;
-
-private:
- SkShaper(const SkShaper&) = delete;
- SkShaper& operator=(const SkShaper&) = delete;
-
- struct Impl;
- std::unique_ptr<Impl> fImpl;
-};
-
-#endif // SkShaper_DEFINED
diff --git a/tools/shape/SkShaper_harfbuzz.cpp b/tools/shape/SkShaper_harfbuzz.cpp
deleted file mode 100644
index 40414d9a79..0000000000
--- a/tools/shape/SkShaper_harfbuzz.cpp
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <hb-ot.h>
-#include <unicode/brkiter.h>
-#include <unicode/locid.h>
-#include <unicode/stringpiece.h>
-#include <unicode/ubidi.h>
-#include <unicode/uchriter.h>
-#include <unicode/unistr.h>
-#include <unicode/uscript.h>
-
-#include "SkFontMgr.h"
-#include "SkLoadICU.h"
-#include "SkOnce.h"
-#include "SkShaper.h"
-#include "SkStream.h"
-#include "SkTDPQueue.h"
-#include "SkTLazy.h"
-#include "SkTemplates.h"
-#include "SkTextBlob.h"
-#include "SkTypeface.h"
-#include "SkUtils.h"
-
-namespace {
-template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
-using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
-using HBFace = resource<hb_face_t , hb_face_destroy >;
-using HBFont = resource<hb_font_t , hb_font_destroy >;
-using HBBuffer = resource<hb_buffer_t, hb_buffer_destroy>;
-using ICUBiDi = resource<UBiDi , ubidi_close >;
-
-HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
- size_t size = asset->getLength();
- HBBlob blob;
- if (const void* base = asset->getMemoryBase()) {
- blob.reset(hb_blob_create((char*)base, SkToUInt(size),
- HB_MEMORY_MODE_READONLY, asset.release(),
- [](void* p) { delete (SkStreamAsset*)p; }));
- } else {
- // SkDebugf("Extra SkStreamAsset copy\n");
- void* ptr = size ? sk_malloc_throw(size) : nullptr;
- asset->read(ptr, size);
- blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
- HB_MEMORY_MODE_READONLY, ptr, sk_free));
- }
- SkASSERT(blob);
- hb_blob_make_immutable(blob.get());
- return blob;
-}
-
-HBFont create_hb_font(SkTypeface* tf) {
- int index;
- HBBlob blob(stream_to_blob(std::unique_ptr<SkStreamAsset>(tf->openStream(&index))));
- HBFace face(hb_face_create(blob.get(), (unsigned)index));
- SkASSERT(face);
- if (!face) {
- return nullptr;
- }
- hb_face_set_index(face.get(), (unsigned)index);
- hb_face_set_upem(face.get(), tf->getUnitsPerEm());
-
- HBFont font(hb_font_create(face.get()));
- SkASSERT(font);
- if (!font) {
- return nullptr;
- }
- hb_ot_font_set_funcs(font.get());
- int axis_count = tf->getVariationDesignPosition(nullptr, 0);
- if (axis_count > 0) {
- SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
- if (tf->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
- hb_font_set_variations(font.get(),
- reinterpret_cast<hb_variation_t*>(axis_values.get()),
- axis_count);
- }
- }
- return font;
-}
-
-class RunIterator {
-public:
- virtual ~RunIterator() {}
- virtual void consume() = 0;
- // Pointer one past the last (utf8) element in the current run.
- virtual const char* endOfCurrentRun() const = 0;
- virtual bool atEnd() const = 0;
- bool operator<(const RunIterator& that) const {
- return this->endOfCurrentRun() < that.endOfCurrentRun();
- }
-};
-
-class BiDiRunIterator : public RunIterator {
-public:
- static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
- SkTLazy<BiDiRunIterator> ret;
-
- // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
- // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
- if (!SkTFitsIn<int32_t>(utf8Bytes)) {
- SkDebugf("Bidi error: text too long");
- return ret;
- }
- icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, utf8Bytes));
-
- UErrorCode status = U_ZERO_ERROR;
- ICUBiDi bidi(ubidi_openSized(utf16.length(), 0, &status));
- if (U_FAILURE(status)) {
- SkDebugf("Bidi error: %s", u_errorName(status));
- return ret;
- }
- SkASSERT(bidi);
-
- // The required lifetime of utf16 isn't well documented.
- // It appears it isn't used after ubidi_setPara except through ubidi_getText.
- ubidi_setPara(bidi.get(), utf16.getBuffer(), utf16.length(), level, nullptr, &status);
- if (U_FAILURE(status)) {
- SkDebugf("Bidi error: %s", u_errorName(status));
- return ret;
- }
-
- ret.init(utf8, std::move(bidi));
- return ret;
- }
- BiDiRunIterator(const char* utf8, ICUBiDi bidi)
- : fBidi(std::move(bidi))
- , fEndOfCurrentRun(utf8)
- , fUTF16LogicalPosition(0)
- , fLevel(UBIDI_DEFAULT_LTR)
- {}
- void consume() override {
- SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
- int32_t endPosition = ubidi_getLength(fBidi.get());
- fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
- SkUnichar u = SkUTF8_NextUnichar(&fEndOfCurrentRun);
- fUTF16LogicalPosition += SkUTF16_FromUnichar(u);
- UBiDiLevel level;
- while (fUTF16LogicalPosition < endPosition) {
- level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
- if (level != fLevel) {
- break;
- }
- u = SkUTF8_NextUnichar(&fEndOfCurrentRun);
- fUTF16LogicalPosition += SkUTF16_FromUnichar(u);
- }
- }
- const char* endOfCurrentRun() const override {
- return fEndOfCurrentRun;
- }
- bool atEnd() const override {
- return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
- }
-
- UBiDiLevel currentLevel() const {
- return fLevel;
- }
-private:
- ICUBiDi fBidi;
- const char* fEndOfCurrentRun;
- int32_t fUTF16LogicalPosition;
- UBiDiLevel fLevel;
-};
-
-class ScriptRunIterator : public RunIterator {
-public:
- static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
- hb_unicode_funcs_t* hbUnicode)
- {
- SkTLazy<ScriptRunIterator> ret;
- ret.init(utf8, utf8Bytes, hbUnicode);
- return ret;
- }
- ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
- : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
- , fHBUnicode(hbUnicode)
- , fCurrentScript(HB_SCRIPT_UNKNOWN)
- {}
- void consume() override {
- SkASSERT(fCurrent < fEnd);
- SkUnichar u = SkUTF8_NextUnichar(&fCurrent);
- fCurrentScript = hb_unicode_script(fHBUnicode, u);
- while (fCurrent < fEnd) {
- const char* prev = fCurrent;
- u = SkUTF8_NextUnichar(&fCurrent);
- const hb_script_t script = hb_unicode_script(fHBUnicode, u);
- if (script != fCurrentScript) {
- if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
- fCurrentScript = script;
- } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
- continue;
- } else {
- fCurrent = prev;
- break;
- }
- }
- }
- if (fCurrentScript == HB_SCRIPT_INHERITED) {
- fCurrentScript = HB_SCRIPT_COMMON;
- }
- }
- const char* endOfCurrentRun() const override {
- return fCurrent;
- }
- bool atEnd() const override {
- return fCurrent == fEnd;
- }
-
- hb_script_t currentScript() const {
- return fCurrentScript;
- }
-private:
- const char* fCurrent;
- const char* fEnd;
- hb_unicode_funcs_t* fHBUnicode;
- hb_script_t fCurrentScript;
-};
-
-class FontRunIterator : public RunIterator {
-public:
- static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
- sk_sp<SkTypeface> typeface,
- hb_font_t* hbFace,
- sk_sp<SkFontMgr> fallbackMgr)
- {
- SkTLazy<FontRunIterator> ret;
- ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
- return ret;
- }
- FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
- hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
- : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
- , fFallbackMgr(std::move(fallbackMgr))
- , fHBFont(hbFace), fTypeface(std::move(typeface))
- , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
- , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
- {}
- void consume() override {
- SkASSERT(fCurrent < fEnd);
- SkUnichar u = SkUTF8_NextUnichar(&fCurrent);
- // If the starting typeface can handle this character, use it.
- if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
- fFallbackTypeface.reset();
- // If not, try to find a fallback typeface
- } else {
- fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
- nullptr, fTypeface->fontStyle(), nullptr, 0, u));
- }
-
- if (fFallbackTypeface) {
- fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
- fCurrentTypeface = fFallbackTypeface.get();
- fCurrentHBFont = fFallbackHBFont.get();
- } else {
- fFallbackHBFont.reset();
- fCurrentTypeface = fTypeface.get();
- fCurrentHBFont = fHBFont;
- }
-
- while (fCurrent < fEnd) {
- const char* prev = fCurrent;
- u = SkUTF8_NextUnichar(&fCurrent);
-
- // If using a fallback and the initial typeface has this character, stop fallback.
- if (fFallbackTypeface &&
- fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
- {
- fCurrent = prev;
- return;
- }
- // If the current typeface cannot handle this character, stop using it.
- if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
- fCurrent = prev;
- return;
- }
- }
- }
- const char* endOfCurrentRun() const override {
- return fCurrent;
- }
- bool atEnd() const override {
- return fCurrent == fEnd;
- }
-
- SkTypeface* currentTypeface() const {
- return fCurrentTypeface;
- }
- hb_font_t* currentHBFont() const {
- return fCurrentHBFont;
- }
-private:
- const char* fCurrent;
- const char* fEnd;
- sk_sp<SkFontMgr> fFallbackMgr;
- hb_font_t* fHBFont;
- sk_sp<SkTypeface> fTypeface;
- HBFont fFallbackHBFont;
- sk_sp<SkTypeface> fFallbackTypeface;
- hb_font_t* fCurrentHBFont;
- SkTypeface* fCurrentTypeface;
-};
-
-class RunIteratorQueue {
-public:
- void insert(RunIterator* runIterator) {
- fRunIterators.insert(runIterator);
- }
-
- bool advanceRuns() {
- const RunIterator* leastRun = fRunIterators.peek();
- if (leastRun->atEnd()) {
- SkASSERT(this->allRunsAreAtEnd());
- return false;
- }
- const char* leastEnd = leastRun->endOfCurrentRun();
- RunIterator* currentRun = nullptr;
- SkDEBUGCODE(const char* previousEndOfCurrentRun);
- while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
- fRunIterators.pop();
- SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
- currentRun->consume();
- SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
- fRunIterators.insert(currentRun);
- }
- return true;
- }
-
- const char* endOfCurrentRun() const {
- return fRunIterators.peek()->endOfCurrentRun();
- }
-
-private:
- bool allRunsAreAtEnd() const {
- for (int i = 0; i < fRunIterators.count(); ++i) {
- if (!fRunIterators.at(i)->atEnd()) {
- return false;
- }
- }
- return true;
- }
-
- static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
- return *a < *b;
- }
- SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
-};
-
-struct ShapedGlyph {
- SkGlyphID fID;
- uint32_t fCluster;
- SkPoint fOffset;
- SkVector fAdvance;
- bool fMayLineBreakBefore;
- bool fMustLineBreakBefore;
- bool fHasVisual;
-};
-struct ShapedRun {
- ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkPaint& paint,
- UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
- : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fPaint(paint)
- , fLevel(level), fGlyphs(std::move(glyphs))
- {}
-
- const char* fUtf8Start;
- const char* fUtf8End;
- int fNumGlyphs;
- SkPaint fPaint;
- UBiDiLevel fLevel;
- std::unique_ptr<ShapedGlyph[]> fGlyphs;
-};
-
-static constexpr bool is_LTR(UBiDiLevel level) {
- return (level & 1) == 0;
-}
-
-static void append(SkTextBlobBuilder* b, const ShapedRun& run, int start, int end, SkPoint* p) {
- unsigned len = end - start;
- auto runBuffer = b->allocRunTextPos(run.fPaint, len, run.fUtf8End - run.fUtf8Start, SkString());
- memcpy(runBuffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
-
- for (unsigned i = 0; i < len; i++) {
- // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
- const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
- runBuffer.glyphs[i] = glyph.fID;
- runBuffer.clusters[i] = glyph.fCluster;
- reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
- SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
- p->fX += glyph.fAdvance.fX;
- p->fY += glyph.fAdvance.fY;
- }
-}
-
-struct ShapedRunGlyphIterator {
- ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
- : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
- { }
-
- ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
- ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
- bool operator==(const ShapedRunGlyphIterator& that) const {
- return fRuns == that.fRuns &&
- fRunIndex == that.fRunIndex &&
- fGlyphIndex == that.fGlyphIndex;
- }
- bool operator!=(const ShapedRunGlyphIterator& that) const {
- return fRuns != that.fRuns ||
- fRunIndex != that.fRunIndex ||
- fGlyphIndex != that.fGlyphIndex;
- }
-
- ShapedGlyph* next() {
- const SkTArray<ShapedRun>& runs = *fRuns;
- SkASSERT(fRunIndex < runs.count());
- SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
-
- ++fGlyphIndex;
- if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
- fGlyphIndex = 0;
- ++fRunIndex;
- if (fRunIndex >= runs.count()) {
- return nullptr;
- }
- }
- return &runs[fRunIndex].fGlyphs[fGlyphIndex];
- }
-
- ShapedGlyph* current() {
- const SkTArray<ShapedRun>& runs = *fRuns;
- if (fRunIndex >= runs.count()) {
- return nullptr;
- }
- return &runs[fRunIndex].fGlyphs[fGlyphIndex];
- }
-
- const SkTArray<ShapedRun>* fRuns;
- int fRunIndex;
- int fGlyphIndex;
-};
-
-} // namespace
-
-struct SkShaper::Impl {
- HBFont fHarfBuzzFont;
- HBBuffer fBuffer;
- sk_sp<SkTypeface> fTypeface;
- std::unique_ptr<icu::BreakIterator> fBreakIterator;
-};
-
-SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
- SkOnce once;
- once([] { SkLoadICU(); });
-
- fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
- fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
- SkASSERT(fImpl->fHarfBuzzFont);
- fImpl->fBuffer.reset(hb_buffer_create());
- SkASSERT(fImpl->fBuffer);
-
- icu::Locale thai("th");
- UErrorCode status = U_ZERO_ERROR;
- fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
- if (U_FAILURE(status)) {
- SkDebugf("Could not create break iterator: %s", u_errorName(status));
- SK_ABORT("");
- }
-}
-
-SkShaper::~SkShaper() {}
-
-bool SkShaper::good() const {
- return fImpl->fHarfBuzzFont &&
- fImpl->fBuffer &&
- fImpl->fTypeface &&
- fImpl->fBreakIterator;
-}
-
-SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
- const SkPaint& srcPaint,
- const char* utf8,
- size_t utf8Bytes,
- bool leftToRight,
- SkPoint point,
- SkScalar width) const {
- sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
- SkASSERT(builder);
- UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
- //hb_script_t script = ...
-
- SkTArray<ShapedRun> runs;
-{
- RunIteratorQueue runSegmenter;
-
- SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
- BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
- if (!bidi) {
- return point;
- }
- runSegmenter.insert(bidi);
-
- hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
- SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
- ScriptRunIterator* script = maybeScript.getMaybeNull();
- if (!script) {
- return point;
- }
- runSegmenter.insert(script);
-
- SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
- fImpl->fTypeface,
- fImpl->fHarfBuzzFont.get(),
- std::move(fontMgr)));
- FontRunIterator* font = maybeFont.getMaybeNull();
- if (!font) {
- return point;
- }
- runSegmenter.insert(font);
-
- icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
- {
- UErrorCode status = U_ZERO_ERROR;
- UText utf8UText = UTEXT_INITIALIZER;
- utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
- std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
- if (U_FAILURE(status)) {
- SkDebugf("Could not create utf8UText: %s", u_errorName(status));
- return point;
- }
- breakIterator.setText(&utf8UText, status);
- //utext_close(&utf8UText);
- if (U_FAILURE(status)) {
- SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
- return point;
- }
- }
-
- const char* utf8Start = nullptr;
- const char* utf8End = utf8;
- while (runSegmenter.advanceRuns()) {
- utf8Start = utf8End;
- utf8End = runSegmenter.endOfCurrentRun();
-
- hb_buffer_t* buffer = fImpl->fBuffer.get();
- SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
- hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
- hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
-
- // Populate the hb_buffer directly with utf8 cluster indexes.
- const char* utf8Current = utf8Start;
- while (utf8Current < utf8End) {
- unsigned int cluster = utf8Current - utf8Start;
- hb_codepoint_t u = SkUTF8_NextUnichar(&utf8Current);
- hb_buffer_add(buffer, u, cluster);
- }
-
- size_t utf8runLength = utf8End - utf8Start;
- if (!SkTFitsIn<int>(utf8runLength)) {
- SkDebugf("Shaping error: utf8 too long");
- return point;
- }
- hb_buffer_set_script(buffer, script->currentScript());
- hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
- hb_buffer_set_direction(buffer, direction);
- // TODO: language
- hb_buffer_guess_segment_properties(buffer);
- // TODO: features
- hb_shape(font->currentHBFont(), buffer, nullptr, 0);
- unsigned len = hb_buffer_get_length(buffer);
- if (len == 0) {
- continue;
- }
-
- if (direction == HB_DIRECTION_RTL) {
- // Put the clusters back in logical order.
- // Note that the advances remain ltr.
- hb_buffer_reverse(buffer);
- }
- hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
- hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
-
- if (!SkTFitsIn<int>(len)) {
- SkDebugf("Shaping error: too many glyphs");
- return point;
- }
-
- SkPaint paint(srcPaint);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setTypeface(sk_ref_sp(font->currentTypeface()));
- ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
- std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
- int scaleX, scaleY;
- hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
- double textSizeY = run.fPaint.getTextSize() / scaleY;
- double textSizeX = run.fPaint.getTextSize() / scaleX * run.fPaint.getTextScaleX();
- for (unsigned i = 0; i < len; i++) {
- ShapedGlyph& glyph = run.fGlyphs[i];
- glyph.fID = info[i].codepoint;
- glyph.fCluster = info[i].cluster;
- glyph.fOffset.fX = pos[i].x_offset * textSizeX;
- glyph.fOffset.fY = pos[i].y_offset * textSizeY;
- glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
- glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
- glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
- //info->mask safe_to_break;
- glyph.fMustLineBreakBefore = false;
- }
-
- int32_t clusterOffset = utf8Start - utf8;
- uint32_t previousCluster = 0xFFFFFFFF;
- for (unsigned i = 0; i < len; ++i) {
- ShapedGlyph& glyph = run.fGlyphs[i];
- int32_t glyphCluster = glyph.fCluster + clusterOffset;
- int32_t breakIteratorCurrent = breakIterator.current();
- while (breakIteratorCurrent != icu::BreakIterator::DONE &&
- breakIteratorCurrent < glyphCluster)
- {
- breakIteratorCurrent = breakIterator.next();
- }
- glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
- breakIteratorCurrent == glyphCluster;
- previousCluster = glyph.fCluster;
- }
- }
-}
-
-// Iterate over the glyphs in logical order to mark line endings.
-{
- SkScalar widthSoFar = 0;
- bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
- bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
- ShapedRunGlyphIterator previousBreak(runs);
- ShapedRunGlyphIterator glyphIterator(runs);
- while (ShapedGlyph* glyph = glyphIterator.current()) {
- if (canAddBreakNow && glyph->fMayLineBreakBefore) {
- previousBreakValid = true;
- previousBreak = glyphIterator;
- }
- SkScalar glyphWidth = glyph->fAdvance.fX;
- if (widthSoFar + glyphWidth < width) {
- widthSoFar += glyphWidth;
- glyphIterator.next();
- canAddBreakNow = true;
- continue;
- }
-
- if (widthSoFar == 0) {
- // Adding just this glyph is too much, just break with this glyph
- glyphIterator.next();
- previousBreak = glyphIterator;
- } else if (!previousBreakValid) {
- // No break opprotunity found yet, just break without this glyph
- previousBreak = glyphIterator;
- }
- glyphIterator = previousBreak;
- glyph = glyphIterator.current();
- if (glyph) {
- glyph->fMustLineBreakBefore = true;
- }
- widthSoFar = 0;
- previousBreakValid = false;
- canAddBreakNow = false;
- }
-}
-
-// Reorder the runs and glyphs per line and write them out.
- SkPoint currentPoint = point;
-{
- ShapedRunGlyphIterator previousBreak(runs);
- ShapedRunGlyphIterator glyphIterator(runs);
- SkScalar maxAscent = 0;
- SkScalar maxDescent = 0;
- SkScalar maxLeading = 0;
- int previousRunIndex = -1;
- while (glyphIterator.current()) {
- int runIndex = glyphIterator.fRunIndex;
- int glyphIndex = glyphIterator.fGlyphIndex;
- ShapedGlyph* nextGlyph = glyphIterator.next();
-
- if (previousRunIndex != runIndex) {
- SkPaint::FontMetrics metrics;
- runs[runIndex].fPaint.getFontMetrics(&metrics);
- maxAscent = SkTMin(maxAscent, metrics.fAscent);
- maxDescent = SkTMax(maxDescent, metrics.fDescent);
- maxLeading = SkTMax(maxLeading, metrics.fLeading);
- previousRunIndex = runIndex;
- }
-
- // Nothing can be written until the baseline is known.
- if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
- continue;
- }
-
- currentPoint.fY -= maxAscent;
-
- int numRuns = runIndex - previousBreak.fRunIndex + 1;
- SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
- for (int i = 0; i < numRuns; ++i) {
- runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
- }
- SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
- ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
-
- for (int i = 0; i < numRuns; ++i) {
- int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
-
- int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
- ? previousBreak.fGlyphIndex
- : 0;
- int endGlyphIndex = (logicalIndex == runIndex)
- ? glyphIndex + 1
- : runs[logicalIndex].fNumGlyphs;
- append(builder, runs[logicalIndex], startGlyphIndex, endGlyphIndex, &currentPoint);
- }
-
- currentPoint.fY += maxDescent + maxLeading;
- currentPoint.fX = point.fX;
- maxAscent = 0;
- maxDescent = 0;
- maxLeading = 0;
- previousRunIndex = -1;
- previousBreak = glyphIterator;
- }
-}
-
- return currentPoint;
-}
diff --git a/tools/shape/SkShaper_primitive.cpp b/tools/shape/SkShaper_primitive.cpp
deleted file mode 100644
index 06a8bec41c..0000000000
--- a/tools/shape/SkShaper_primitive.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "SkShaper.h"
-#include "SkStream.h"
-#include "SkTextBlob.h"
-#include "SkTypeface.h"
-
-struct SkShaper::Impl {
- sk_sp<SkTypeface> fTypeface;
-};
-
-SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
- fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
-}
-
-SkShaper::~SkShaper() {}
-
-bool SkShaper::good() const { return true; }
-
-// This example only uses public API, so we don't use SkUTF8_NextUnichar.
-unsigned utf8_lead_byte_to_count(const char* ptr) {
- uint8_t c = *(const uint8_t*)ptr;
- SkASSERT(c <= 0xF7);
- SkASSERT((c & 0xC0) != 0x80);
- return (((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1;
-}
-
-SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
- const SkPaint& srcPaint,
- const char* utf8text,
- size_t textBytes,
- bool leftToRight,
- SkPoint point,
- SkScalar width) const {
- sk_ignore_unused_variable(leftToRight);
-
- SkPaint paint(srcPaint);
- paint.setTypeface(fImpl->fTypeface);
- paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- int glyphCount = paint.countText(utf8text, textBytes);
- if (glyphCount <= 0) {
- return point;
- }
- SkRect bounds;
- SkPaint::FontMetrics metrics;
- paint.getFontMetrics(&metrics);
- point.fY -= metrics.fAscent;
- (void)paint.measureText(utf8text, textBytes, &bounds);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- const SkTextBlobBuilder::RunBuffer& runBuffer =
- builder->allocRunTextPosH(paint, glyphCount, point.y(), textBytes, SkString(), &bounds);
- memcpy(runBuffer.utf8text, utf8text, textBytes);
- const char* txtPtr = utf8text;
- for (int i = 0; i < glyphCount; ++i) {
- // Each charater maps to exactly one glyph via SkGlyphCache::unicharToGlyph().
- runBuffer.clusters[i] = SkToU32(txtPtr - utf8text);
- txtPtr += utf8_lead_byte_to_count(txtPtr);
- SkASSERT(txtPtr <= utf8text + textBytes);
- }
- paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- (void)paint.textToGlyphs(utf8text, textBytes, runBuffer.glyphs);
- (void)paint.getTextWidths(utf8text, textBytes, runBuffer.pos);
- SkScalar x = point.x();
- for (int i = 0; i < glyphCount; ++i) {
- SkScalar w = runBuffer.pos[i];
- runBuffer.pos[i] = x;
- x += w;
- }
- point.fY += metrics.fDescent + metrics.fLeading;
-
- return point;
-}
diff --git a/tools/shape/using_skia_and_harfbuzz.cpp b/tools/using_skia_and_harfbuzz.cpp
index 5a74866794..5a74866794 100644
--- a/tools/shape/using_skia_and_harfbuzz.cpp
+++ b/tools/using_skia_and_harfbuzz.cpp