diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-21 22:48:32 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-21 22:48:32 +0000 |
commit | 72cf4fcafa54cfa04c5ec7cb8eaa3acb144712dd (patch) | |
tree | f6d0aff66805377067c2345deefcb6a832f29ef4 /src/fonts | |
parent | 34ce63ca6b853724c152a116e1467c0eead87003 (diff) |
A remotable font management interface and DirectWrite implementation.
The introduced SkRemotableFontMgr is a font management interface designed for simple and fast proxy support. SkFontMgr_Indirect bridges a SkRemotableFontMgr and a local SkFontMgr to present a SkFontMgr interface.
This change is to be followed by https://codereview.chromium.org/132113015/ and https://codereview.chromium.org/206693003 .
R=reed@google.com
Review URL: https://codereview.chromium.org/206683002
git-svn-id: http://skia.googlecode.com/svn/trunk@13897 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/fonts')
-rw-r--r-- | src/fonts/SkFontMgr_indirect.cpp | 297 | ||||
-rw-r--r-- | src/fonts/SkRemotableFontMgr.cpp | 32 |
2 files changed, 329 insertions, 0 deletions
diff --git a/src/fonts/SkFontMgr_indirect.cpp b/src/fonts/SkFontMgr_indirect.cpp new file mode 100644 index 0000000000..bc8dce1e8f --- /dev/null +++ b/src/fonts/SkFontMgr_indirect.cpp @@ -0,0 +1,297 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkFontMgr_indirect.h" + +#include "SkDataTable.h" +#include "SkFontStyle.h" +#include "SkOnce.h" +#include "SkStream.h" +#include "SkTSearch.h" +#include "SkTypeface.h" + +class SkData; +class SkString; + +class SkStyleSet_Indirect : public SkFontStyleSet { +public: + /** Takes ownership of the SkRemotableFontIdentitySet. */ + SkStyleSet_Indirect(const SkFontMgr_Indirect* owner, int familyIndex, + SkRemotableFontIdentitySet* data) + : fOwner(SkRef(owner)), fFamilyIndex(familyIndex), fData(data) + { } + + virtual int count() SK_OVERRIDE { return fData->count(); } + + virtual void getStyle(int index, SkFontStyle* fs, SkString* style) SK_OVERRIDE { + if (fs) { + *fs = fData->at(index).fFontStyle; + } + if (style) { + // TODO: is this useful? Current locale? + style->reset(); + } + } + + virtual SkTypeface* createTypeface(int index) SK_OVERRIDE { + return fOwner->createTypefaceFromFontId(fData->at(index)); + } + + virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { + if (fFamilyIndex >= 0) { + SkFontIdentity id = fOwner->fProxy->matchIndexStyle(fFamilyIndex, pattern); + return fOwner->createTypefaceFromFontId(id); + } + + // If this SkStyleSet was created via onMatchFamily we would need a call like + // fOwner->fProxy->matchNameStyle(fFamilyName, pattern); + // but would not activate fonts (only consider fonts which would come back from matchName). + + // CSS policy sounds good. + struct Score { + int score; + int index; + }; + + // Width has the greatest priority. + // If the value of pattern.width is 5 (normal) or less, + // narrower width values are checked first, then wider values. + // If the value of pattern.width is greater than 5 (normal), + // wider values are checked first, followed by narrower values. + + // Italic/Oblique has the next highest priority. + // If italic requested and there is some italic font, use it. + // If oblique requested and there is some oblique font, use it. + // If italic requested and there is some oblique font, use it. + // If oblique requested and there is some italic font, use it. + + // Exact match. + // If pattern.weight < 400, weights below pattern.weight are checked + // in descending order followed by weights above pattern.weight + // in ascending order until a match is found. + // If pattern.weight > 500, weights above pattern.weight are checked + // in ascending order followed by weights below pattern.weight + // in descending order until a match is found. + // If pattern.weight is 400, 500 is checked first + // and then the rule for pattern.weight < 400 is used. + // If pattern.weight is 500, 400 is checked first + // and then the rule for pattern.weight < 400 is used + + Score maxScore = { 0, 0 }; + for (int i = 0; i < fData->count(); ++i) { + const SkFontStyle& current = fData->at(i).fFontStyle; + Score currentScore = { 0, i }; + + // CSS stretch. (This is the width.) + // This has the highest priority. + if (pattern.width() <= SkFontStyle::kNormal_Width) { + if (current.width() <= pattern.width()) { + currentScore.score += 10 - pattern.width() + current.width(); + } else { + currentScore.score += 10 - current.width(); + } + } else { + if (current.width() > pattern.width()) { + currentScore.score += 10 + pattern.width() - current.width(); + } else { + currentScore.score += current.width(); + } + } + currentScore.score *= 1002; + + // CSS style (italic/oblique) + // Being italic trumps all valid weights which are not italic. + // Note that newer specs differentiate between italic and oblique. + if (pattern.isItalic() && current.isItalic()) { + currentScore.score += 1001; + } + + // Synthetics (weight/style) [no stretch synthetic?] + + // The 'closer' to the target weight, the higher the score. + // 1000 is the 'heaviest' recognized weight + if (pattern.weight() == current.weight()) { + currentScore.score += 1000; + } else if (pattern.weight() <= 500) { + if (pattern.weight() >= 400 && pattern.weight() < 450) { + if (current.weight() >= 450 && current.weight() <= 500) { + // Artificially boost the 500 weight. + // TODO: determine correct number to use. + currentScore.score += 500; + } + } + if (current.weight() <= pattern.weight()) { + currentScore.score += 1000 - pattern.weight() + current.weight(); + } else { + currentScore.score += 1000 - current.weight(); + } + } else if (pattern.weight() > 500) { + if (current.weight() > pattern.weight()) { + currentScore.score += 1000 + pattern.weight() - current.weight(); + } else { + currentScore.score += current.weight(); + } + } + + if (currentScore.score > maxScore.score) { + maxScore = currentScore; + } + } + + return this->createTypeface(maxScore.index); + } +private: + SkAutoTUnref<const SkFontMgr_Indirect> fOwner; + int fFamilyIndex; + SkAutoTUnref<SkRemotableFontIdentitySet> fData; +}; + +void SkFontMgr_Indirect::set_up_family_names(const SkFontMgr_Indirect* self) { + self->fFamilyNames.reset(self->fProxy->getFamilyNames()); +} + +int SkFontMgr_Indirect::onCountFamilies() const { + SkOnce(&fOnce, SkFontMgr_Indirect::set_up_family_names, this); + return fFamilyNames->count(); +} + +void SkFontMgr_Indirect::onGetFamilyName(int index, SkString* familyName) const { + SkOnce(&fOnce, SkFontMgr_Indirect::set_up_family_names, this); + if (index >= fFamilyNames->count()) { + familyName->reset(); + return; + } + familyName->set(fFamilyNames->atStr(index)); +} + +SkFontStyleSet* SkFontMgr_Indirect::onCreateStyleSet(int index) const { + SkRemotableFontIdentitySet* set = fProxy->getIndex(index); + if (NULL == set) { + return NULL; + } + return SkNEW_ARGS(SkStyleSet_Indirect, (this, index, set)); +} + +SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const { + return SkNEW_ARGS(SkStyleSet_Indirect, (this, -1, fProxy->matchName(familyName))); +} + +SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& id) const { + if (id.fDataId == SkFontIdentity::kInvalidDataId) { + return NULL; + } + + SkAutoMutexAcquire ama(fDataCacheMutex); + + SkAutoTUnref<SkTypeface> dataTypeface; + int dataTypefaceIndex = 0; + for (int i = 0; i < fDataCache.count(); ++i) { + const DataEntry& entry = fDataCache[i]; + if (entry.fDataId == id.fDataId) { + if (entry.fTtcIndex == id.fTtcIndex && + !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref()) + { + return entry.fTypeface; + } + if (dataTypeface.get() == NULL && + !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref()) + { + dataTypeface.reset(entry.fTypeface); + dataTypefaceIndex = entry.fTtcIndex; + } + } + + if (entry.fTypeface->weak_expired()) { + fDataCache.removeShuffle(i); + --i; + } + } + + // No exact match, but did find a data match. + if (dataTypeface.get() != NULL) { + SkAutoTUnref<SkStream> stream(dataTypeface->openStream(NULL)); + if (stream.get() != NULL) { + return fImpl->createFromStream(stream.get(), dataTypefaceIndex); + } + } + + // No data match, request data and add entry. + SkAutoTUnref<SkStreamAsset> stream(fProxy->getData(id.fDataId)); + if (stream.get() == NULL) { + return NULL; + } + + SkAutoTUnref<SkTypeface> typeface(fImpl->createFromStream(stream, id.fTtcIndex)); + if (typeface.get() == NULL) { + return NULL; + } + + DataEntry& newEntry = fDataCache.push_back(); + typeface->weak_ref(); + newEntry.fDataId = id.fDataId; + newEntry.fTtcIndex = id.fTtcIndex; + newEntry.fTypeface = typeface.get(); // weak reference passed to new entry. + + return typeface.detach(); +} + +SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const { + SkFontIdentity id = fProxy->matchNameStyle(familyName, fontStyle); + return this->createTypefaceFromFontId(id); +} + +SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle& style, + const char bpc47[], + uint32_t character) const { + SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bpc47, character); + return this->createTypefaceFromFontId(id); +} + +SkTypeface* SkFontMgr_Indirect::onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle& fontStyle) const { + SkString familyName; + familyMember->getFamilyName(&familyName); + return this->matchFamilyStyle(familyName.c_str(), fontStyle); +} + +SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStream* stream, int ttcIndex) const { + return fImpl->createFromStream(stream, ttcIndex); +} + +SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const { + return fImpl->createFromFile(path, ttcIndex); +} + +SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const { + return fImpl->createFromData(data, ttcIndex); +} + +SkTypeface* SkFontMgr_Indirect::onLegacyCreateTypeface(const char familyName[], + unsigned styleBits) const { + bool bold = SkToBool(styleBits & SkTypeface::kBold); + bool italic = SkToBool(styleBits & SkTypeface::kItalic); + SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight + : SkFontStyle::kNormal_Weight, + SkFontStyle::kNormal_Width, + italic ? SkFontStyle::kItalic_Slant + : SkFontStyle::kUpright_Slant); + + SkAutoTUnref<SkTypeface> face(this->matchFamilyStyle(familyName, style)); + + if (NULL == face.get()) { + face.reset(this->matchFamilyStyle(NULL, style)); + } + + if (NULL == face.get()) { + SkFontIdentity fontId = this->fProxy->matchIndexStyle(0, style); + face.reset(this->createTypefaceFromFontId(fontId)); + } + + return face.detach(); +} diff --git a/src/fonts/SkRemotableFontMgr.cpp b/src/fonts/SkRemotableFontMgr.cpp new file mode 100644 index 0000000000..1139972848 --- /dev/null +++ b/src/fonts/SkRemotableFontMgr.cpp @@ -0,0 +1,32 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkRemotableFontMgr.h" + +#include "SkOnce.h" + +SkRemotableFontIdentitySet::SkRemotableFontIdentitySet(int count, SkFontIdentity** data) + : fCount(count), fData(count) +{ + SkASSERT(data); + *data = fData; +} + +static SkRemotableFontIdentitySet* gEmptyRemotableFontIdentitySet = NULL; +static void cleanup_gEmptyRemotableFontIdentitySet() { gEmptyRemotableFontIdentitySet->unref(); } + +void SkRemotableFontIdentitySet::NewEmptyImpl(int) { + gEmptyRemotableFontIdentitySet = new SkRemotableFontIdentitySet(); +} + +SkRemotableFontIdentitySet* SkRemotableFontIdentitySet::NewEmpty() { + SK_DECLARE_STATIC_ONCE(once); + SkOnce(&once, SkRemotableFontIdentitySet::NewEmptyImpl, 0, + cleanup_gEmptyRemotableFontIdentitySet); + gEmptyRemotableFontIdentitySet->ref(); + return gEmptyRemotableFontIdentitySet; +} |