| Index: skia/ext/SkFontHost_fontconfig.cpp
|
| diff --git a/skia/ext/SkFontHost_fontconfig.cpp b/skia/ext/SkFontHost_fontconfig.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d92698c7bce254aa7eec4999b9730962ea723124
|
| --- /dev/null
|
| +++ b/skia/ext/SkFontHost_fontconfig.cpp
|
| @@ -0,0 +1,227 @@
|
| +/* libs/graphics/ports/SkFontHost_fontconfig.cpp
|
| +**
|
| +** Copyright 2008, Google Inc.
|
| +**
|
| +** Licensed under the Apache License, Version 2.0 (the "License");
|
| +** you may not use this file except in compliance with the License.
|
| +** You may obtain a copy of the License at
|
| +**
|
| +** http://www.apache.org/licenses/LICENSE-2.0
|
| +**
|
| +** Unless required by applicable law or agreed to in writing, software
|
| +** distributed under the License is distributed on an "AS IS" BASIS,
|
| +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +** See the License for the specific language governing permissions and
|
| +** limitations under the License.
|
| +*/
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// This file provides implementations of the font resolution members of
|
| +// SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
|
| +// on Linux systems and handles configuration, parsing and caching issues
|
| +// involved with enumerating and matching fonts.
|
| +//
|
| +// [1] http://fontconfig.org
|
| +// -----------------------------------------------------------------------------
|
| +
|
| +#include <map>
|
| +#include <string>
|
| +
|
| +#include <unistd.h>
|
| +#include <sys/stat.h>
|
| +
|
| +#include "SkFontHost.h"
|
| +#include "SkStream.h"
|
| +#include "SkFontHost_fontconfig_impl.h"
|
| +#include "SkFontHost_fontconfig_direct.h"
|
| +#include "SkFontHost_fontconfig_ipc.h"
|
| +
|
| +static FontConfigInterface* global_fc_impl = NULL;
|
| +
|
| +void SkiaFontConfigUseDirectImplementation() {
|
| + global_fc_impl = new FontConfigDirect;
|
| +}
|
| +
|
| +void SkiaFontConfigUseIPCImplementation(int fd) {
|
| + global_fc_impl = new FontConfigIPC(fd);
|
| +}
|
| +
|
| +static SkMutex global_fc_map_lock;
|
| +static std::map<uint32_t, SkTypeface *> global_fc_typefaces;
|
| +
|
| +// This is the maximum size of the font cache.
|
| +static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB
|
| +
|
| +// UniqueIds are encoded as (fileid << 8) | style
|
| +
|
| +static unsigned UniqueIdToFileId(unsigned uniqueid)
|
| +{
|
| + return uniqueid >> 8;
|
| +}
|
| +
|
| +static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
|
| +{
|
| + return static_cast<SkTypeface::Style>(uniqueid & 0xff);
|
| +}
|
| +
|
| +static unsigned FileIdAndStyleToUniqueId(unsigned fileid,
|
| + SkTypeface::Style style)
|
| +{
|
| + SkASSERT(style & 0xff == style);
|
| + return (fileid << 8) | static_cast<int>(style);
|
| +}
|
| +
|
| +class FontConfigTypeface : public SkTypeface {
|
| +public:
|
| + FontConfigTypeface(Style style, uint32_t id)
|
| + : SkTypeface(style, id)
|
| + { }
|
| +};
|
| +
|
| +// static
|
| +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
|
| + const char familyName[],
|
| + SkTypeface::Style style)
|
| +{
|
| + std::string resolved_family_name;
|
| +
|
| + if (familyFace) {
|
| + // Given the fileid we can ask fontconfig for the familyname of the
|
| + // font.
|
| + const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID());
|
| + if (!global_fc_impl->Match(
|
| + &resolved_family_name, NULL, true /* fileid valid */, fileid, "",
|
| + -1, -1)) {
|
| + return NULL;
|
| + }
|
| + } else if (familyName) {
|
| + resolved_family_name = familyName;
|
| + } else {
|
| + return NULL;
|
| + }
|
| +
|
| + const bool bold = style & SkTypeface::kBold;
|
| + const bool italic = style & SkTypeface::kItalic;
|
| + unsigned fileid;
|
| + if (!global_fc_impl->Match(NULL, &fileid, false, -1, /* no fileid */
|
| + resolved_family_name, bold, italic)) {
|
| + return NULL;
|
| + }
|
| +
|
| + const unsigned id = FileIdAndStyleToUniqueId(fileid, style);
|
| + SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
|
| +
|
| + {
|
| + SkAutoMutexAcquire ac(global_fc_map_lock);
|
| + global_fc_typefaces[id] = typeface;
|
| + }
|
| +
|
| + return typeface;
|
| +}
|
| +
|
| +// static
|
| +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
|
| +{
|
| + SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented");
|
| + return NULL;
|
| +}
|
| +
|
| +// static
|
| +SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
|
| +{
|
| + SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
|
| + return NULL;
|
| +}
|
| +
|
| +// static
|
| +bool SkFontHost::ValidFontID(SkFontID uniqueID) {
|
| + SkAutoMutexAcquire ac(global_fc_map_lock);
|
| + return global_fc_typefaces.find(uniqueID) != global_fc_typefaces.end();
|
| +}
|
| +
|
| +void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
|
| + SkASSERT(!"SkFontHost::Serialize unimplemented");
|
| +}
|
| +
|
| +SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
|
| + SkASSERT(!"SkFontHost::Deserialize unimplemented");
|
| + return NULL;
|
| +}
|
| +
|
| +// static
|
| +uint32_t SkFontHost::NextLogicalFont(SkFontID fontID) {
|
| + // We don't handle font fallback, WebKit does.
|
| + return 0;
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class SkFileDescriptorStream : public SkStream {
|
| + public:
|
| + SkFileDescriptorStream(int fd)
|
| + : fd_(fd) {
|
| + }
|
| +
|
| + ~SkFileDescriptorStream() {
|
| + close(fd_);
|
| + }
|
| +
|
| + virtual bool rewind() {
|
| + if (lseek(fd_, 0, SEEK_SET) == -1)
|
| + return false;
|
| + return true;
|
| + }
|
| +
|
| + // SkStream implementation.
|
| + virtual size_t read(void* buffer, size_t size) {
|
| + if (!buffer && !size) {
|
| + // This is request for the length of the stream.
|
| + struct stat st;
|
| + if (fstat(fd_, &st) == -1)
|
| + return 0;
|
| + return st.st_size;
|
| + }
|
| +
|
| + if (!buffer) {
|
| + // This is a request to skip bytes.
|
| + const off_t current_position = lseek(fd_, 0, SEEK_CUR);
|
| + if (current_position == -1)
|
| + return 0;
|
| + const off_t new_position = lseek(fd_, size, SEEK_CUR);
|
| + if (new_position == -1)
|
| + return 0;
|
| + if (new_position < current_position) {
|
| + lseek(fd_, current_position, SEEK_SET);
|
| + return 0;
|
| + }
|
| + return new_position;
|
| + }
|
| +
|
| + // This is a request to read bytes.
|
| + return ::read(fd_, buffer, size);
|
| + }
|
| +
|
| + private:
|
| + const int fd_;
|
| +};
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +// static
|
| +SkStream* SkFontHost::OpenStream(uint32_t id)
|
| +{
|
| + const unsigned fileid = UniqueIdToFileId(id);
|
| + const int fd = global_fc_impl->Open(fileid);
|
| + if (fd < 0)
|
| + return NULL;
|
| +
|
| + return SkNEW_ARGS(SkFileDescriptorStream, (fd));
|
| +}
|
| +
|
| +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
|
| +{
|
| + if (sizeAllocatedSoFar > kFontCacheMemoryBudget)
|
| + return sizeAllocatedSoFar - kFontCacheMemoryBudget;
|
| + else
|
| + return 0; // nothing to do
|
| +}
|
|
|