Adding locale
Change-Id: I4f118f37a1226f4259d0e5be3b6b557b38b3b316 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/222785 Commit-Queue: Julia Lavrova <jlavrova@google.com> Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
65eb084e78
commit
35f88226bb
@ -29,7 +29,7 @@ public:
|
|||||||
|
|
||||||
sk_sp<SkTypeface> matchTypeface(const char familyName[], SkFontStyle fontStyle);
|
sk_sp<SkTypeface> matchTypeface(const char familyName[], SkFontStyle fontStyle);
|
||||||
sk_sp<SkTypeface> matchDefaultTypeface(SkFontStyle fontStyle);
|
sk_sp<SkTypeface> matchDefaultTypeface(SkFontStyle fontStyle);
|
||||||
sk_sp<SkTypeface> defaultFallback(SkUnichar unicode, SkFontStyle fontStyle);
|
sk_sp<SkTypeface> defaultFallback(SkUnichar unicode, SkFontStyle fontStyle, SkString locale);
|
||||||
|
|
||||||
void disableFontFallback();
|
void disableFontFallback();
|
||||||
bool fontFallbackEnabled() { return fEnableFontFallback; }
|
bool fontFallbackEnabled() { return fEnableFontFallback; }
|
||||||
|
@ -18,12 +18,9 @@ skparagraph_public = [
|
|||||||
|
|
||||||
skparagraph_sources = [
|
skparagraph_sources = [
|
||||||
"$_src/FontCollection.cpp",
|
"$_src/FontCollection.cpp",
|
||||||
"$_src/FontIterator.h",
|
|
||||||
"$_src/FontIterator.cpp",
|
|
||||||
"$_src/FontResolver.h",
|
"$_src/FontResolver.h",
|
||||||
"$_src/FontResolver.cpp",
|
"$_src/FontResolver.cpp",
|
||||||
"$_src/TextLine.h",
|
"$_src/Iterator.h",
|
||||||
"$_src/TextLine.cpp",
|
|
||||||
"$_src/ParagraphBuilderImpl.h",
|
"$_src/ParagraphBuilderImpl.h",
|
||||||
"$_src/ParagraphBuilderImpl.cpp",
|
"$_src/ParagraphBuilderImpl.cpp",
|
||||||
"$_src/ParagraphImpl.h",
|
"$_src/ParagraphImpl.h",
|
||||||
@ -31,6 +28,8 @@ skparagraph_sources = [
|
|||||||
"$_src/ParagraphStyle.cpp",
|
"$_src/ParagraphStyle.cpp",
|
||||||
"$_src/Run.h",
|
"$_src/Run.h",
|
||||||
"$_src/Run.cpp",
|
"$_src/Run.cpp",
|
||||||
|
"$_src/TextLine.h",
|
||||||
|
"$_src/TextLine.cpp",
|
||||||
"$_src/TextShadow.cpp",
|
"$_src/TextShadow.cpp",
|
||||||
"$_src/TextStyle.cpp",
|
"$_src/TextStyle.cpp",
|
||||||
"$_src/TextWrapper.h",
|
"$_src/TextWrapper.h",
|
||||||
|
@ -117,10 +117,13 @@ sk_sp<SkTypeface> FontCollection::matchDefaultTypeface(SkFontStyle fontStyle) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkTypeface> FontCollection::defaultFallback(SkUnichar unicode, SkFontStyle fontStyle) {
|
sk_sp<SkTypeface> FontCollection::defaultFallback(SkUnichar unicode, SkFontStyle fontStyle, SkString locale) {
|
||||||
|
|
||||||
for (const auto& manager : this->getFontManagerOrder()) {
|
for (const auto& manager : this->getFontManagerOrder()) {
|
||||||
std::vector<const char*> bcp47;
|
std::vector<const char*> bcp47;
|
||||||
|
if (!locale.isEmpty()) {
|
||||||
|
bcp47.push_back(locale.c_str());
|
||||||
|
}
|
||||||
sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
|
sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
|
||||||
0, fontStyle, bcp47.data(), bcp47.size(), unicode));
|
0, fontStyle, bcp47.data(), bcp47.size(), unicode));
|
||||||
if (typeface != nullptr) {
|
if (typeface != nullptr) {
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
// Copyright 2019 Google LLC.
|
|
||||||
#include "modules/skparagraph/src/FontIterator.h"
|
|
||||||
#include <unicode/brkiter.h>
|
|
||||||
#include <unicode/ubidi.h>
|
|
||||||
#include "include/core/SkBlurTypes.h"
|
|
||||||
#include "include/core/SkCanvas.h"
|
|
||||||
#include "include/core/SkFontMgr.h"
|
|
||||||
#include "include/core/SkPictureRecorder.h"
|
|
||||||
#include "modules/skparagraph/src/ParagraphImpl.h"
|
|
||||||
#include "src/core/SkSpan.h"
|
|
||||||
#include "src/utils/SkUTF.h"
|
|
||||||
|
|
||||||
// TODO: FontCollection and FontIterator have common functionality
|
|
||||||
namespace skia {
|
|
||||||
namespace textlayout {
|
|
||||||
|
|
||||||
FontIterator::FontIterator(SkSpan<const char> utf8,
|
|
||||||
SkSpan<TextBlock> styles,
|
|
||||||
sk_sp<FontCollection> fonts)
|
|
||||||
: fText(utf8)
|
|
||||||
, fStyles(styles)
|
|
||||||
, fCurrentChar(utf8.begin())
|
|
||||||
, fFontResolver(std::move(fonts)) {
|
|
||||||
findAllFontsForAllStyledBlocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FontIterator::consume() {
|
|
||||||
SkASSERT(fCurrentChar < fText.end());
|
|
||||||
auto found = fFontResolver.findFirst(fCurrentChar, &fFont, &fLineHeight);
|
|
||||||
SkASSERT(found);
|
|
||||||
|
|
||||||
// Move until we find the first character that cannot be resolved with the current font
|
|
||||||
while (++fCurrentChar != fText.end()) {
|
|
||||||
SkFont font;
|
|
||||||
SkScalar height;
|
|
||||||
found = fFontResolver.findNext(fCurrentChar, &font, &height);
|
|
||||||
if (found) {
|
|
||||||
if (fFont == font && fLineHeight == height) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FontIterator::findAllFontsForAllStyledBlocks() {
|
|
||||||
TextBlock combined;
|
|
||||||
for (auto& block : fStyles) {
|
|
||||||
SkASSERT(combined.text().begin() == nullptr ||
|
|
||||||
combined.text().end() == block.text().begin());
|
|
||||||
|
|
||||||
if (combined.text().begin() != nullptr &&
|
|
||||||
block.style().matchOneAttribute(StyleType::kFont, combined.style())) {
|
|
||||||
combined.add(block.text());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!combined.text().empty()) {
|
|
||||||
fFontResolver.findAllFontsForStyledBlock(combined.style(), combined.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
combined = block;
|
|
||||||
}
|
|
||||||
fFontResolver.findAllFontsForStyledBlock(combined.style(), combined.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace textlayout
|
|
||||||
} // namespace skia
|
|
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2019 Google LLC.
|
|
||||||
#ifndef FontIterator_DEFINED
|
|
||||||
#define FontIterator_DEFINED
|
|
||||||
|
|
||||||
#include <unicode/brkiter.h>
|
|
||||||
#include <unicode/ubidi.h>
|
|
||||||
#include "include/core/SkBlurTypes.h"
|
|
||||||
#include "include/core/SkCanvas.h"
|
|
||||||
#include "include/core/SkFontMgr.h"
|
|
||||||
#include "include/core/SkPictureRecorder.h"
|
|
||||||
#include "modules/skparagraph/src/FontResolver.h"
|
|
||||||
#include "modules/skparagraph/src/ParagraphImpl.h"
|
|
||||||
#include "src/core/SkSpan.h"
|
|
||||||
#include "src/utils/SkUTF.h"
|
|
||||||
|
|
||||||
namespace skia {
|
|
||||||
namespace textlayout {
|
|
||||||
|
|
||||||
class FontIterator final : public SkShaper::FontRunIterator {
|
|
||||||
public:
|
|
||||||
FontIterator(SkSpan<const char> utf8,
|
|
||||||
SkSpan<TextBlock> styles,
|
|
||||||
sk_sp<FontCollection> fonts);
|
|
||||||
|
|
||||||
void consume() override;
|
|
||||||
|
|
||||||
size_t endOfCurrentRun() const override { return fCurrentChar - fText.begin(); }
|
|
||||||
bool atEnd() const override { return fCurrentChar == fText.end(); }
|
|
||||||
const SkFont& currentFont() const override { return fFont; }
|
|
||||||
SkScalar lineHeight() const { return fLineHeight; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Hash {
|
|
||||||
uint32_t operator()(const std::pair<SkFont, SkScalar>& key) const {
|
|
||||||
return SkTypeface::UniqueID(key.first.getTypeface()) +
|
|
||||||
SkScalarCeilToInt(key.first.getSize()) + SkScalarCeilToInt(key.second);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void findAllFontsForAllStyledBlocks();
|
|
||||||
|
|
||||||
SkSpan<const char> fText;
|
|
||||||
SkSpan<TextBlock> fStyles;
|
|
||||||
const char* fCurrentChar;
|
|
||||||
SkFont fFont;
|
|
||||||
SkScalar fLineHeight;
|
|
||||||
FontResolver fFontResolver;
|
|
||||||
};
|
|
||||||
} // namespace textlayout
|
|
||||||
} // namespace skia
|
|
||||||
|
|
||||||
#endif // FontIterator_DEFINED
|
|
@ -22,9 +22,6 @@ SkUnichar utf8_next(const char** ptr, const char* end) {
|
|||||||
namespace skia {
|
namespace skia {
|
||||||
namespace textlayout {
|
namespace textlayout {
|
||||||
|
|
||||||
FontResolver::FontResolver(sk_sp<FontCollection> fontCollection)
|
|
||||||
: fFontCollection(fontCollection) {}
|
|
||||||
|
|
||||||
bool FontResolver::findFirst(const char* codepoint, SkFont* font, SkScalar* height) {
|
bool FontResolver::findFirst(const char* codepoint, SkFont* font, SkScalar* height) {
|
||||||
auto found = fFontMapping.find(codepoint);
|
auto found = fFontMapping.find(codepoint);
|
||||||
if (found == nullptr) {
|
if (found == nullptr) {
|
||||||
@ -34,8 +31,8 @@ bool FontResolver::findFirst(const char* codepoint, SkFont* font, SkScalar* heig
|
|||||||
if (found == nullptr) {
|
if (found == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*font = found->first;
|
*font = found->fFont;
|
||||||
*height = found->second;
|
*height = found->fHeight;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +41,8 @@ bool FontResolver::findNext(const char* codepoint, SkFont* font, SkScalar* heigh
|
|||||||
if (found == nullptr) {
|
if (found == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*font = found->first;
|
*font = found->fFont;
|
||||||
*height = found->second;
|
*height = found->fHeight;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +90,7 @@ void FontResolver::findAllFontsForStyledBlock(const TextStyle& style, SkSpan<con
|
|||||||
if (fUnresolved > 0 && fFontCollection->fontFallbackEnabled()) {
|
if (fUnresolved > 0 && fFontCollection->fontFallbackEnabled()) {
|
||||||
while (fUnresolved > 0) {
|
while (fUnresolved > 0) {
|
||||||
auto unicode = firstUnresolved();
|
auto unicode = firstUnresolved();
|
||||||
auto typeface = fFontCollection->defaultFallback(unicode, style.getFontStyle());
|
auto typeface = fFontCollection->defaultFallback(unicode, style.getFontStyle(), style.getLocale());
|
||||||
if (typeface == nullptr) {
|
if (typeface == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -110,11 +107,12 @@ void FontResolver::findAllFontsForStyledBlock(const TextStyle& style, SkSpan<con
|
|||||||
|
|
||||||
// In case something still unresolved
|
// In case something still unresolved
|
||||||
if (fResolvedFonts.count() == 0) {
|
if (fResolvedFonts.count() == 0) {
|
||||||
makeFont(fFontCollection->defaultFallback(firstUnresolved(), style.getFontStyle()),
|
makeFont(fFontCollection->defaultFallback(firstUnresolved(), style.getFontStyle(), style.getLocale()),
|
||||||
style.getFontSize(), style.getHeight());
|
style.getFontSize(),
|
||||||
if (fFirstResolvedFont.first.getTypeface() != nullptr) {
|
style.getHeight());
|
||||||
|
if (fFirstResolvedFont.fFont.getTypeface() != nullptr) {
|
||||||
SkString name;
|
SkString name;
|
||||||
fFirstResolvedFont.first.getTypeface()->getFamilyName(&name);
|
fFirstResolvedFont.fFont.getTypeface()->getFamilyName(&name);
|
||||||
SkDebugf("Urgent font resolution: %s\n", name.c_str());
|
SkDebugf("Urgent font resolution: %s\n", name.c_str());
|
||||||
} else {
|
} else {
|
||||||
SkDebugf("No font!!!\n");
|
SkDebugf("No font!!!\n");
|
||||||
@ -122,11 +120,11 @@ void FontResolver::findAllFontsForStyledBlock(const TextStyle& style, SkSpan<con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FontResolver::resolveAllCharactersByFont(std::pair<SkFont, SkScalar> font) {
|
size_t FontResolver::resolveAllCharactersByFont(const FontDescr& font) {
|
||||||
// Consolidate all unresolved unicodes in one array to make a batch call
|
// Consolidate all unresolved unicodes in one array to make a batch call
|
||||||
SkTArray<SkGlyphID> glyphs(fUnresolved);
|
SkTArray<SkGlyphID> glyphs(fUnresolved);
|
||||||
glyphs.push_back_n(fUnresolved, SkGlyphID(0));
|
glyphs.push_back_n(fUnresolved, SkGlyphID(0));
|
||||||
font.first.getTypeface()->unicharsToGlyphs(
|
font.fFont.getTypeface()->unicharsToGlyphs(
|
||||||
fUnresolved == fCodepoints.size() ? fCodepoints.data() : fUnresolvedCodepoints.data(),
|
fUnresolved == fCodepoints.size() ? fCodepoints.data() : fUnresolvedCodepoints.data(),
|
||||||
fUnresolved, glyphs.data());
|
fUnresolved, glyphs.data());
|
||||||
|
|
||||||
@ -209,24 +207,23 @@ void FontResolver::addResolvedWhitespacesToMapping() {
|
|||||||
fUnresolved -= resolvedWhitespaces;
|
fUnresolved -= resolvedWhitespaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<SkFont, SkScalar> FontResolver::makeFont(sk_sp<SkTypeface> typeface,
|
FontResolver::FontDescr FontResolver::makeFont(sk_sp<SkTypeface> typeface,
|
||||||
SkScalar size,
|
SkScalar size,
|
||||||
SkScalar height) {
|
SkScalar height) {
|
||||||
SkFont font(typeface, size);
|
SkFont font(typeface, size);
|
||||||
font.setEdging(SkFont::Edging::kAntiAlias);
|
font.setEdging(SkFont::Edging::kAntiAlias);
|
||||||
font.setHinting(SkFontHinting::kSlight);
|
font.setHinting(SkFontHinting::kSlight);
|
||||||
font.setSubpixel(true);
|
font.setSubpixel(true);
|
||||||
auto pair = std::make_pair(font, height);
|
FontDescr descr(font, height);
|
||||||
|
|
||||||
auto foundFont = fResolvedFonts.find(pair);
|
const FontDescr* foundFont = fResolvedFonts.find(descr);
|
||||||
if (foundFont == nullptr) {
|
if (foundFont == nullptr) {
|
||||||
if (fResolvedFonts.count() == 0) {
|
if (fResolvedFonts.count() == 0) {
|
||||||
fFirstResolvedFont = pair;
|
fFirstResolvedFont = descr;
|
||||||
}
|
}
|
||||||
fResolvedFonts.add(pair);
|
fResolvedFonts.add(descr);
|
||||||
}
|
}
|
||||||
|
return descr;
|
||||||
return pair;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkUnichar FontResolver::firstUnresolved() {
|
SkUnichar FontResolver::firstUnresolved() {
|
||||||
@ -236,5 +233,31 @@ SkUnichar FontResolver::firstUnresolved() {
|
|||||||
auto index = firstTry ? 0 : fUnresolvedIndexes[0];
|
auto index = firstTry ? 0 : fUnresolvedIndexes[0];
|
||||||
return fCodepoints[index];
|
return fCodepoints[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FontResolver::findAllFontsForAllStyledBlocks(SkSpan<const char> utf8,
|
||||||
|
SkSpan<TextBlock> styles,
|
||||||
|
sk_sp<FontCollection> fontCollection) {
|
||||||
|
fFontCollection = fontCollection;
|
||||||
|
fStyles = styles;
|
||||||
|
fText = utf8;
|
||||||
|
TextBlock combined;
|
||||||
|
for (auto& block : fStyles) {
|
||||||
|
SkASSERT(combined.text().begin() == nullptr ||
|
||||||
|
combined.text().end() == block.text().begin());
|
||||||
|
|
||||||
|
if (combined.text().begin() != nullptr &&
|
||||||
|
block.style().matchOneAttribute(StyleType::kFont, combined.style())) {
|
||||||
|
combined.add(block.text());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!combined.text().empty()) {
|
||||||
|
this->findAllFontsForStyledBlock(combined.style(), combined.text());
|
||||||
|
}
|
||||||
|
|
||||||
|
combined = block;
|
||||||
|
}
|
||||||
|
this->findAllFontsForStyledBlock(combined.style(), combined.text());
|
||||||
|
}
|
||||||
} // namespace textlayout
|
} // namespace textlayout
|
||||||
} // namespace skia
|
} // namespace skia
|
||||||
|
@ -2,54 +2,70 @@
|
|||||||
#ifndef FontResolver_DEFINED
|
#ifndef FontResolver_DEFINED
|
||||||
#define FontResolver_DEFINED
|
#define FontResolver_DEFINED
|
||||||
|
|
||||||
#include "src/core/SkSpan.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include "modules/skparagraph/src/TextLine.h"
|
||||||
#include "include/core/SkFontMgr.h"
|
#include "include/core/SkFontMgr.h"
|
||||||
#include "include/core/SkRefCnt.h"
|
#include "include/core/SkRefCnt.h"
|
||||||
#include "include/private/SkTHash.h"
|
#include "include/private/SkTHash.h"
|
||||||
#include "modules/skparagraph/include/FontCollection.h"
|
#include "modules/skparagraph/include/FontCollection.h"
|
||||||
#include "modules/skparagraph/include/TextStyle.h"
|
#include "modules/skparagraph/include/TextStyle.h"
|
||||||
|
#include "src/core/SkSpan.h"
|
||||||
|
|
||||||
namespace skia {
|
namespace skia {
|
||||||
namespace textlayout {
|
namespace textlayout {
|
||||||
|
|
||||||
class FontResolver {
|
class FontResolver {
|
||||||
public:
|
public:
|
||||||
FontResolver(sk_sp<FontCollection> fontCollection);
|
struct FontDescr {
|
||||||
|
FontDescr() {}
|
||||||
|
FontDescr(SkFont font, SkScalar height)
|
||||||
|
: fFont(font), fHeight(height) {}
|
||||||
|
bool operator==(const FontDescr& a) const {
|
||||||
|
return this->fFont == a.fFont && this->fHeight == a.fHeight;
|
||||||
|
}
|
||||||
|
SkFont fFont;
|
||||||
|
SkScalar fHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
FontResolver() = default;
|
||||||
~FontResolver() = default;
|
~FontResolver() = default;
|
||||||
|
|
||||||
void findAllFontsForStyledBlock(const TextStyle& style, SkSpan<const char> text);
|
void findAllFontsForAllStyledBlocks(SkSpan<const char> utf8,
|
||||||
|
SkSpan<TextBlock> styles,
|
||||||
|
sk_sp<FontCollection> fontCollection);
|
||||||
bool findFirst(const char* codepoint, SkFont* font, SkScalar* height);
|
bool findFirst(const char* codepoint, SkFont* font, SkScalar* height);
|
||||||
bool findNext(const char* codepoint, SkFont* font, SkScalar* height);
|
bool findNext(const char* codepoint, SkFont* font, SkScalar* height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::pair<SkFont, SkScalar> makeFont(sk_sp<SkTypeface> typeface, SkScalar size,
|
void findAllFontsForStyledBlock(const TextStyle& style, SkSpan<const char> text);
|
||||||
SkScalar height);
|
FontDescr makeFont(sk_sp<SkTypeface> typeface, SkScalar size, SkScalar height);
|
||||||
|
size_t resolveAllCharactersByFont(const FontDescr& fontDescr);
|
||||||
size_t resolveAllCharactersByFont(std::pair<SkFont, SkScalar> font);
|
|
||||||
void addResolvedWhitespacesToMapping();
|
void addResolvedWhitespacesToMapping();
|
||||||
|
|
||||||
struct Hash {
|
struct Hash {
|
||||||
uint32_t operator()(const std::pair<SkFont, SkScalar>& key) const {
|
uint32_t operator()(const FontDescr& key) const {
|
||||||
return SkTypeface::UniqueID(key.first.getTypeface()) +
|
return SkTypeface::UniqueID(key.fFont.getTypeface()) +
|
||||||
SkScalarCeilToInt(key.first.getSize()) + SkScalarCeilToInt(key.second);
|
SkScalarCeilToInt(key.fFont.getSize()) +
|
||||||
|
SkScalarCeilToInt(key.fHeight);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SkUnichar firstUnresolved();
|
SkUnichar firstUnresolved();
|
||||||
|
|
||||||
sk_sp<FontCollection> fFontCollection;
|
sk_sp<FontCollection> fFontCollection;
|
||||||
|
SkSpan<const char> fText;
|
||||||
|
SkSpan<TextBlock> fStyles;
|
||||||
|
|
||||||
SkTHashMap<const char*, std::pair<SkFont, SkScalar>> fFontMapping;
|
SkTHashMap<const char*, FontDescr> fFontMapping;
|
||||||
SkTHashSet<std::pair<SkFont, SkScalar>, Hash> fResolvedFonts;
|
SkTHashSet<FontDescr, Hash> fResolvedFonts;
|
||||||
std::pair<SkFont, SkScalar> fFirstResolvedFont;
|
FontDescr fFirstResolvedFont;
|
||||||
|
|
||||||
SkTArray<SkUnichar> fCodepoints;
|
SkTArray<SkUnichar> fCodepoints;
|
||||||
SkTArray<const char*> fCharacters;
|
SkTArray<const char*> fCharacters;
|
||||||
SkTArray<size_t> fUnresolvedIndexes;
|
SkTArray<size_t> fUnresolvedIndexes;
|
||||||
SkTArray<SkUnichar> fUnresolvedCodepoints;
|
SkTArray<SkUnichar> fUnresolvedCodepoints;
|
||||||
SkTHashMap<size_t, std::pair<SkFont, SkScalar>> fWhitespaces;
|
SkTHashMap<size_t, FontDescr> fWhitespaces;
|
||||||
size_t fUnresolved;
|
size_t fUnresolved;
|
||||||
};
|
};
|
||||||
} // namespace textlayout
|
} // namespace textlayout
|
||||||
|
100
modules/skparagraph/src/Iterators.h
Normal file
100
modules/skparagraph/src/Iterators.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2019 Google LLC.
|
||||||
|
#ifndef FontIterator_DEFINED
|
||||||
|
#define FontIterator_DEFINED
|
||||||
|
|
||||||
|
#include <unicode/brkiter.h>
|
||||||
|
#include <unicode/ubidi.h>
|
||||||
|
#include "include/core/SkBlurTypes.h"
|
||||||
|
#include "include/core/SkCanvas.h"
|
||||||
|
#include "include/core/SkFontMgr.h"
|
||||||
|
#include "include/core/SkPictureRecorder.h"
|
||||||
|
#include "modules/skparagraph/src/FontResolver.h"
|
||||||
|
#include "modules/skparagraph/src/ParagraphImpl.h"
|
||||||
|
#include "src/core/SkSpan.h"
|
||||||
|
#include "src/utils/SkUTF.h"
|
||||||
|
|
||||||
|
namespace skia {
|
||||||
|
namespace textlayout {
|
||||||
|
|
||||||
|
class FontIterator final : public SkShaper::FontRunIterator {
|
||||||
|
public:
|
||||||
|
FontIterator(SkSpan<const char> utf8, FontResolver* fontResolver)
|
||||||
|
: fText(utf8), fCurrentChar(utf8.begin()), fFontResolver(fontResolver) { }
|
||||||
|
|
||||||
|
void consume() override {
|
||||||
|
SkASSERT(fCurrentChar < fText.end());
|
||||||
|
SkString locale;
|
||||||
|
auto found = fFontResolver->findFirst(fCurrentChar, &fFont, &fLineHeight);
|
||||||
|
SkASSERT(found);
|
||||||
|
|
||||||
|
// Move until we find the first character that cannot be resolved with the current font
|
||||||
|
while (++fCurrentChar != fText.end()) {
|
||||||
|
SkFont font;
|
||||||
|
SkScalar height;
|
||||||
|
SkString locale;
|
||||||
|
found = fFontResolver->findNext(fCurrentChar, &font, &height);
|
||||||
|
if (found) {
|
||||||
|
if (fFont == font && fLineHeight == height) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t endOfCurrentRun() const override { return fCurrentChar - fText.begin(); }
|
||||||
|
bool atEnd() const override { return fCurrentChar == fText.end(); }
|
||||||
|
const SkFont& currentFont() const override { return fFont; }
|
||||||
|
SkScalar currentLineHeight() const { return fLineHeight; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SkSpan<const char> fText;
|
||||||
|
const char* fCurrentChar;
|
||||||
|
SkFont fFont;
|
||||||
|
SkScalar fLineHeight;
|
||||||
|
FontResolver* fFontResolver;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LangIterator final : public SkShaper::LanguageRunIterator {
|
||||||
|
public:
|
||||||
|
LangIterator(SkSpan<const char> utf8, SkSpan<TextBlock> styles, TextStyle defaultStyle)
|
||||||
|
: fText(utf8)
|
||||||
|
, fTextStyles(styles)
|
||||||
|
, fCurrentChar(utf8.begin())
|
||||||
|
, fCurrentStyle(fTextStyles.begin())
|
||||||
|
, fCurrentLocale(defaultStyle.getLocale()) {}
|
||||||
|
|
||||||
|
void consume() override {
|
||||||
|
SkASSERT(fCurrentChar < fText.end());
|
||||||
|
|
||||||
|
if (fCurrentStyle == fTextStyles.end()) {
|
||||||
|
fCurrentChar = fText.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fCurrentChar = fCurrentStyle->text().end();
|
||||||
|
fCurrentLocale = fCurrentStyle->style().getLocale();
|
||||||
|
while (++fCurrentStyle != fTextStyles.end()) {
|
||||||
|
if (fCurrentStyle->style().getLocale() != fCurrentLocale) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fCurrentChar = fCurrentStyle->text().end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t endOfCurrentRun() const override { return fCurrentChar - fText.begin(); }
|
||||||
|
bool atEnd() const override { return fCurrentChar == fText.end(); }
|
||||||
|
const char* currentLanguage() const override { return fCurrentLocale.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkSpan<const char> fText;
|
||||||
|
SkSpan<TextBlock> fTextStyles;
|
||||||
|
const char* fCurrentChar;
|
||||||
|
TextBlock* fCurrentStyle;
|
||||||
|
SkString fCurrentLocale;
|
||||||
|
};
|
||||||
|
} // namespace textlayout
|
||||||
|
} // namespace skia
|
||||||
|
|
||||||
|
#endif // FontIterator_DEFINED
|
@ -7,7 +7,7 @@
|
|||||||
#include "include/core/SkCanvas.h"
|
#include "include/core/SkCanvas.h"
|
||||||
#include "include/core/SkFontMgr.h"
|
#include "include/core/SkFontMgr.h"
|
||||||
#include "include/core/SkPictureRecorder.h"
|
#include "include/core/SkPictureRecorder.h"
|
||||||
#include "modules/skparagraph/src/FontIterator.h"
|
#include "modules/skparagraph/src/Iterators.h"
|
||||||
#include "modules/skparagraph/src/Run.h"
|
#include "modules/skparagraph/src/Run.h"
|
||||||
#include "modules/skparagraph/src/TextWrapper.h"
|
#include "modules/skparagraph/src/TextWrapper.h"
|
||||||
#include "src/core/SkSpan.h"
|
#include "src/core/SkSpan.h"
|
||||||
@ -85,6 +85,24 @@ private:
|
|||||||
namespace skia {
|
namespace skia {
|
||||||
namespace textlayout {
|
namespace textlayout {
|
||||||
|
|
||||||
|
ParagraphImpl::ParagraphImpl(const SkString& text,
|
||||||
|
ParagraphStyle style,
|
||||||
|
std::vector<Block> blocks,
|
||||||
|
sk_sp<FontCollection> fonts)
|
||||||
|
: Paragraph(std::move(style), std::move(fonts))
|
||||||
|
, fText(text)
|
||||||
|
, fTextSpan(fText.c_str(), fText.size())
|
||||||
|
, fDirtyLayout(true)
|
||||||
|
, fOldWidth(0)
|
||||||
|
, fPicture(nullptr) {
|
||||||
|
fTextStyles.reserve(blocks.size());
|
||||||
|
for (auto& block : blocks) {
|
||||||
|
fTextStyles.emplace_back(
|
||||||
|
SkSpan<const char>(fTextSpan.begin() + block.fStart, block.fEnd - block.fStart),
|
||||||
|
block.fStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ParagraphImpl::ParagraphImpl(const std::u16string& utf16text,
|
ParagraphImpl::ParagraphImpl(const std::u16string& utf16text,
|
||||||
ParagraphStyle style,
|
ParagraphStyle style,
|
||||||
std::vector<Block> blocks,
|
std::vector<Block> blocks,
|
||||||
@ -124,11 +142,10 @@ void ParagraphImpl::layout(SkScalar width) {
|
|||||||
|
|
||||||
if (fRuns.empty()) {
|
if (fRuns.empty()) {
|
||||||
fClusters.reset();
|
fClusters.reset();
|
||||||
|
|
||||||
if (!this->shapeTextIntoEndlessLine()) {
|
if (!this->shapeTextIntoEndlessLine()) {
|
||||||
// Apply the last style to the empty text
|
// Apply the last style to the empty text
|
||||||
FontIterator font(SkMakeSpan(" "),
|
FontIterator font(SkMakeSpan(" "), &fFontResolver);
|
||||||
SkSpan<TextBlock>(&fTextStyles.back(), 1),
|
|
||||||
fFontCollection);
|
|
||||||
// Get the font metrics
|
// Get the font metrics
|
||||||
font.consume();
|
font.consume();
|
||||||
LineMetrics lineMetrics(font.currentFont());
|
LineMetrics lineMetrics(font.currentFont());
|
||||||
@ -311,7 +328,7 @@ bool ParagraphImpl::shapeTextIntoEndlessLine() {
|
|||||||
TRACE_EVENT0("skia", TRACE_FUNC);
|
TRACE_EVENT0("skia", TRACE_FUNC);
|
||||||
auto& run = fParagraph->fRuns.emplace_back(fParagraph->text(),
|
auto& run = fParagraph->fRuns.emplace_back(fParagraph->text(),
|
||||||
info,
|
info,
|
||||||
fFontIterator->lineHeight(),
|
fFontIterator->currentLineHeight(),
|
||||||
fParagraph->fRuns.count(),
|
fParagraph->fRuns.count(),
|
||||||
fAdvance.fX);
|
fAdvance.fX);
|
||||||
return run.newRunBuffer();
|
return run.newRunBuffer();
|
||||||
@ -340,8 +357,11 @@ bool ParagraphImpl::shapeTextIntoEndlessLine() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkSpan<TextBlock> styles(fTextStyles.begin(), fTextStyles.size());
|
// This is a pretty big step - resolving all characters against all given fonts
|
||||||
FontIterator font(fTextSpan, styles, fFontCollection);
|
fFontResolver.findAllFontsForAllStyledBlocks(fTextSpan, styles(), fFontCollection);
|
||||||
|
|
||||||
|
LangIterator lang(fTextSpan, styles(), paragraphStyle().getTextStyle());
|
||||||
|
FontIterator font(fTextSpan, &fFontResolver);
|
||||||
ShapeHandler handler(*this, &font);
|
ShapeHandler handler(*this, &font);
|
||||||
std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder();
|
std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder();
|
||||||
SkASSERT_RELEASE(shaper != nullptr);
|
SkASSERT_RELEASE(shaper != nullptr);
|
||||||
@ -352,9 +372,8 @@ bool ParagraphImpl::shapeTextIntoEndlessLine() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto script = SkShaper::MakeHbIcuScriptRunIterator(fTextSpan.begin(), fTextSpan.size());
|
auto script = SkShaper::MakeHbIcuScriptRunIterator(fTextSpan.begin(), fTextSpan.size());
|
||||||
auto lang = SkShaper::MakeStdLanguageRunIterator(fTextSpan.begin(), fTextSpan.size());
|
|
||||||
|
|
||||||
shaper->shape(fTextSpan.begin(), fTextSpan.size(), font, *bidi, *script, *lang,
|
shaper->shape(fTextSpan.begin(), fTextSpan.size(), font, *bidi, *script, lang,
|
||||||
std::numeric_limits<SkScalar>::max(), &handler);
|
std::numeric_limits<SkScalar>::max(), &handler);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#ifndef ParagraphImpl_DEFINED
|
#ifndef ParagraphImpl_DEFINED
|
||||||
#define ParagraphImpl_DEFINED
|
#define ParagraphImpl_DEFINED
|
||||||
|
|
||||||
|
#include "FontResolver.h"
|
||||||
#include "include/core/SkPicture.h"
|
#include "include/core/SkPicture.h"
|
||||||
#include "include/private/SkTHash.h"
|
#include "include/private/SkTHash.h"
|
||||||
#include "modules/skparagraph/include/Paragraph.h"
|
#include "modules/skparagraph/include/Paragraph.h"
|
||||||
@ -28,20 +29,7 @@ public:
|
|||||||
ParagraphImpl(const SkString& text,
|
ParagraphImpl(const SkString& text,
|
||||||
ParagraphStyle style,
|
ParagraphStyle style,
|
||||||
std::vector<Block> blocks,
|
std::vector<Block> blocks,
|
||||||
sk_sp<FontCollection> fonts)
|
sk_sp<FontCollection> fonts);
|
||||||
: Paragraph(std::move(style), std::move(fonts))
|
|
||||||
, fText(text)
|
|
||||||
, fTextSpan(fText.c_str(), fText.size())
|
|
||||||
, fDirtyLayout(true)
|
|
||||||
, fOldWidth(0)
|
|
||||||
, fPicture(nullptr) {
|
|
||||||
fTextStyles.reserve(blocks.size());
|
|
||||||
for (auto& block : blocks) {
|
|
||||||
fTextStyles.emplace_back(
|
|
||||||
SkSpan<const char>(fTextSpan.begin() + block.fStart, block.fEnd - block.fStart),
|
|
||||||
block.fStyle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParagraphImpl(const std::u16string& utf16text,
|
ParagraphImpl(const std::u16string& utf16text,
|
||||||
ParagraphStyle style,
|
ParagraphStyle style,
|
||||||
@ -107,6 +95,7 @@ private:
|
|||||||
SkTArray<Cluster, true> fClusters;
|
SkTArray<Cluster, true> fClusters;
|
||||||
SkTArray<TextLine> fLines;
|
SkTArray<TextLine> fLines;
|
||||||
LineMetrics fStrutMetrics;
|
LineMetrics fStrutMetrics;
|
||||||
|
FontResolver fFontResolver;
|
||||||
|
|
||||||
bool fDirtyLayout;
|
bool fDirtyLayout;
|
||||||
SkScalar fOldWidth;
|
SkScalar fOldWidth;
|
||||||
|
@ -23,6 +23,7 @@ TextStyle::TextStyle() : fFontStyle() {
|
|||||||
fHasBackground = false;
|
fHasBackground = false;
|
||||||
fHasForeground = false;
|
fHasForeground = false;
|
||||||
fTextBaseline = TextBaseline::kAlphabetic;
|
fTextBaseline = TextBaseline::kAlphabetic;
|
||||||
|
fLocale = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextStyle::equals(const TextStyle& other) const {
|
bool TextStyle::equals(const TextStyle& other) const {
|
||||||
|
@ -1220,7 +1220,6 @@ protected:
|
|||||||
|
|
||||||
void onDrawContent(SkCanvas* canvas) override {
|
void onDrawContent(SkCanvas* canvas) override {
|
||||||
canvas->drawColor(SK_ColorWHITE);
|
canvas->drawColor(SK_ColorWHITE);
|
||||||
/*
|
|
||||||
const char* text =
|
const char* text =
|
||||||
"// Create a raised button.\n"
|
"// Create a raised button.\n"
|
||||||
"RaisedButton(\n"
|
"RaisedButton(\n"
|
||||||
@ -1254,7 +1253,7 @@ protected:
|
|||||||
TextStyle text_style;
|
TextStyle text_style;
|
||||||
text_style.setFontFamilies({});
|
text_style.setFontFamilies({});
|
||||||
text_style.setColor(SK_ColorBLACK);
|
text_style.setColor(SK_ColorBLACK);
|
||||||
text_style.setFontSize(20);
|
text_style.setFontSize(50);
|
||||||
builder.pushStyle(text_style);
|
builder.pushStyle(text_style);
|
||||||
builder.addText(text);
|
builder.addText(text);
|
||||||
builder.pop();
|
builder.pop();
|
||||||
@ -1268,31 +1267,7 @@ protected:
|
|||||||
paint.setColor(SK_ColorLTGRAY);
|
paint.setColor(SK_ColorLTGRAY);
|
||||||
canvas->drawRect(result[0].rect, paint);
|
canvas->drawRect(result[0].rect, paint);
|
||||||
paragraph->paint(canvas, 0, 0);
|
paragraph->paint(canvas, 0, 0);
|
||||||
*/
|
|
||||||
std::vector<uint16_t> text;
|
|
||||||
for (uint16_t i = 0; i < 64; ++i) {
|
|
||||||
text.push_back(i % 5 == 0 ? ' ' : i);
|
|
||||||
}
|
|
||||||
std::u16string u16_text(text.data(), text.data() + text.size());
|
|
||||||
TextStyle default_style;
|
|
||||||
default_style.setFontFamilies({SkString("Roboto")});
|
|
||||||
ParagraphStyle paragraph_style;
|
|
||||||
paragraph_style.setTextStyle(default_style);
|
|
||||||
TextStyle text_style;
|
|
||||||
text_style.setFontFamilies({SkString("Roboto")});
|
|
||||||
text_style.setColor(SK_ColorBLACK);
|
|
||||||
auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str());
|
|
||||||
SkASSERT(fontCollection->fontsFound() != 0);
|
|
||||||
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
|
|
||||||
builder.pushStyle(text_style);
|
|
||||||
builder.addText(u16_text);
|
|
||||||
builder.pop();
|
|
||||||
auto paragraph = builder.Build();
|
|
||||||
size_t count = 10;
|
|
||||||
while (--count > 0) {
|
|
||||||
paragraph->layout(300);
|
|
||||||
paragraph->paint(canvas, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user