diff options
author | reed@google.com <reed@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-11 13:36:35 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-11 13:36:35 +0000 |
commit | c7f723c82709ca3b09d4711be191ca762550eab4 (patch) | |
tree | a8d8bc2772f7b39be15349e722931f95f720acbd /skia | |
parent | a5fda2a512b1f0f56185b2e9426e41b0db6d2e4d (diff) | |
download | chromium_src-c7f723c82709ca3b09d4711be191ca762550eab4.zip chromium_src-c7f723c82709ca3b09d4711be191ca762550eab4.tar.gz chromium_src-c7f723c82709ca3b09d4711be191ca762550eab4.tar.bz2 |
Revert 187283
memcheck reported errors which need to be investigated
> Call version of SkFontHost_fontconfig in Skia (cloned from here).
> Retool the direct/remove plumbing to use SkFontConfigInterface.
>
> This change allows Skia to interate on the details of SkFontHost w/o having
> to synchromize with chrome on each change. It also means Skia's internal testing
> can exercise exactly the same config that Chrome does.
> Review URL: https://codereview.chromium.org/12391070
TBR=reed@google.com
Review URL: https://codereview.chromium.org/12771003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187287 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r-- | skia/ext/SkFontHost_fontconfig.cpp | 369 | ||||
-rw-r--r-- | skia/ext/SkFontHost_fontconfig_control.h | 38 | ||||
-rw-r--r-- | skia/ext/SkFontHost_fontconfig_direct.cpp | 504 | ||||
-rw-r--r-- | skia/ext/SkFontHost_fontconfig_direct.h | 59 | ||||
-rw-r--r-- | skia/ext/SkFontHost_fontconfig_impl.h | 73 | ||||
-rw-r--r-- | skia/ext/skia_utils_base.cc | 53 | ||||
-rw-r--r-- | skia/ext/skia_utils_base.h | 33 | ||||
-rw-r--r-- | skia/skia.gyp | 9 |
8 files changed, 1045 insertions, 93 deletions
diff --git a/skia/ext/SkFontHost_fontconfig.cpp b/skia/ext/SkFontHost_fontconfig.cpp new file mode 100644 index 0000000..a209869 --- /dev/null +++ b/skia/ext/SkFontHost_fontconfig.cpp @@ -0,0 +1,369 @@ +/* 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 <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "base/compiler_specific.h" +#include "third_party/skia/src/core/SkFontDescriptor.h" +#include "SkFontHost.h" +#include "SkStream.h" +#include "SkFontHost_fontconfig_control.h" +#include "SkFontHost_fontconfig_impl.h" +#include "SkFontHost_fontconfig_direct.h" + +static FontConfigInterface* global_fc_impl = NULL; + +void SkiaFontConfigUseDirectImplementation() { + if (global_fc_impl) + delete global_fc_impl; + global_fc_impl = new FontConfigDirect; +} + +void SkiaFontConfigSetImplementation(FontConfigInterface* font_config) { + if (global_fc_impl) + delete global_fc_impl; + global_fc_impl = font_config; +} + +static FontConfigInterface* GetFcImpl() { + if (!global_fc_impl) + global_fc_impl = new FontConfigDirect; + return global_fc_impl; +} + +SK_DECLARE_STATIC_MUTEX(global_remote_font_map_lock); +static std::map<uint32_t, std::pair<uint8_t*, size_t> >* global_remote_fonts; + +// Initialize the map declared above. Note that its corresponding mutex must be +// locked before calling this function. +static void AllocateGlobalRemoteFontsMapOnce() { + if (!global_remote_fonts) { + global_remote_fonts = + new std::map<uint32_t, std::pair<uint8_t*, size_t> >(); + } +} + +static unsigned global_next_remote_font_id; + +// This is the maximum size of the font cache. +static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB + +// UniqueIds are encoded as (filefaceid << 8) | style +// For system fonts, filefaceid = (fileid << 4) | face_index. +// For remote fonts, filefaceid = fileid. + +static unsigned UniqueIdToFileFaceId(unsigned uniqueid) +{ + return uniqueid >> 8; +} + +static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid) +{ + return static_cast<SkTypeface::Style>(uniqueid & 0xff); +} + +static unsigned FileFaceIdAndStyleToUniqueId(unsigned filefaceid, + SkTypeface::Style style) +{ + SkASSERT((style & 0xff) == style); + return (filefaceid << 8) | static_cast<int>(style); +} + +static const unsigned kRemoteFontMask = 0x00800000u; + +static bool IsRemoteFont(unsigned filefaceid) +{ + return filefaceid & kRemoteFontMask; +} + +class FontConfigTypeface : public SkTypeface { +public: + FontConfigTypeface(Style style, uint32_t id) + : SkTypeface(style, id) + { } + + virtual ~FontConfigTypeface() + { + const uint32_t id = uniqueID(); + if (IsRemoteFont(UniqueIdToFileFaceId(id))) { + SkAutoMutexAcquire ac(global_remote_font_map_lock); + AllocateGlobalRemoteFontsMapOnce(); + std::map<uint32_t, std::pair<uint8_t*, size_t> >::iterator iter + = global_remote_fonts->find(id); + if (iter != global_remote_fonts->end()) { + sk_free(iter->second.first); // remove the font on memory. + global_remote_fonts->erase(iter); + } + } + } +}; + +// 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 filefaceid = UniqueIdToFileFaceId(familyFace->uniqueID()); + if (!GetFcImpl()->Match(&resolved_family_name, NULL, + true /* filefaceid valid */, filefaceid, "", + NULL, 0, NULL, NULL)) { + return NULL; + } + } else if (familyName) { + resolved_family_name = familyName; + } + + bool bold = style & SkTypeface::kBold; + bool italic = style & SkTypeface::kItalic; + unsigned filefaceid; + if (!GetFcImpl()->Match(NULL, &filefaceid, + false, -1, /* no filefaceid */ + resolved_family_name, NULL, 0, + &bold, &italic)) { + return NULL; + } + const SkTypeface::Style resulting_style = static_cast<SkTypeface::Style>( + (bold ? SkTypeface::kBold : 0) | + (italic ? SkTypeface::kItalic : 0)); + + const unsigned id = FileFaceIdAndStyleToUniqueId(filefaceid, + resulting_style); + SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (resulting_style, id)); + return typeface; +} + +// static +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) +{ + if (!stream) + return NULL; + + const size_t length = stream->read(0, 0); + if (!length) + return NULL; + if (length >= 1024 * 1024 * 1024) + return NULL; // don't accept too large fonts (>= 1GB) for safety. + + uint8_t* font = (uint8_t*)sk_malloc_throw(length); + if (stream->read(font, length) != length) { + sk_free(font); + return NULL; + } + + SkTypeface::Style style = static_cast<SkTypeface::Style>(0); + unsigned id = 0; + { + SkAutoMutexAcquire ac(global_remote_font_map_lock); + AllocateGlobalRemoteFontsMapOnce(); + id = FileFaceIdAndStyleToUniqueId( + global_next_remote_font_id | kRemoteFontMask, style); + + if (++global_next_remote_font_id >= kRemoteFontMask) + global_next_remote_font_id = 0; + + if (!global_remote_fonts->insert( + std::make_pair(id, std::make_pair(font, length))).second) { + sk_free(font); + return NULL; + } + } + + SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id)); + return typeface; +} + +// static +SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) +{ + SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented"); + return NULL; +} + +uint32_t SkFontHost::NextLogicalFont(SkFontID curr, SkFontID orig) { + // We don't handle font fallback, WebKit does. + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +// Serialize, Deserialize need to be compatible across platforms, hence the use +// of SkFontDescriptor. + +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { + SkFontDescriptor desc(face->style()); + + std::string resolved_family_name; + + const unsigned filefaceid = UniqueIdToFileFaceId(face->uniqueID()); + if (GetFcImpl()->Match(&resolved_family_name, NULL, + true /* filefaceid valid */, filefaceid, "", NULL, 0, NULL, NULL)) + desc.setFamilyName(resolved_family_name.c_str()); + else + desc.setFamilyName("sans-serif"); + + // would also like other names (see SkFontDescriptor.h) + + desc.serialize(stream); + + // by convention, we also write out the actual sfnt data, preceeded by + // a packed-length. For now we skip that, so we just write the zero. + stream->writePackedUInt(0); +} + +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { + SkFontDescriptor desc(stream); + + // by convention, Serialize will have also written the actual sfnt data. + // for now, we just want to skip it. + size_t size = stream->readPackedUInt(); + stream->skip(size); + + return SkFontHost::CreateTypeface(NULL, desc.getFamilyName(), + desc.getStyle()); +} + +/////////////////////////////////////////////////////////////////////////////// + +class SkFileDescriptorStream : public SkStream { + public: + SkFileDescriptorStream(int fd) { + memory_ = NULL; + offset_ = 0; + + // this ensures that if we fail in the constructor, we will safely + // ignore all subsequent calls to read() because we will always trim + // the requested size down to 0 + length_ = 0; + + struct stat st; + if (fstat(fd, &st)) + return; + + void* memory = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + if (memory == MAP_FAILED) + return; + + memory_ = reinterpret_cast<uint8_t*>(memory); + length_ = st.st_size; + } + + virtual ~SkFileDescriptorStream() { + munmap(const_cast<uint8_t*>(memory_), length_); + } + + virtual bool rewind() OVERRIDE { + offset_ = 0; + return true; + } + + // SkStream implementation. + virtual size_t read(void* buffer, size_t size) OVERRIDE { + if (!buffer && !size) { + // This is request for the length of the stream. + return length_; + } + + size_t remaining = length_ - offset_; + if (size > remaining) + size = remaining; + if (buffer) + memcpy(buffer, memory_ + offset_, size); + + offset_ += size; + return size; + } + + virtual const void* getMemoryBase() OVERRIDE { + return memory_; + } + + private: + const uint8_t* memory_; + size_t offset_, length_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +// static +SkStream* SkFontHost::OpenStream(uint32_t id) +{ + const unsigned filefaceid = UniqueIdToFileFaceId(id); + + if (IsRemoteFont(filefaceid)) { + // remote font + SkAutoMutexAcquire ac(global_remote_font_map_lock); + AllocateGlobalRemoteFontsMapOnce(); + std::map<uint32_t, std::pair<uint8_t*, size_t> >::const_iterator iter + = global_remote_fonts->find(id); + if (iter == global_remote_fonts->end()) + return NULL; + return SkNEW_ARGS( + SkMemoryStream, (iter->second.first, iter->second.second)); + } + + // system font + const int fd = GetFcImpl()->Open(filefaceid); + if (fd < 0) + return NULL; + + return SkNEW_ARGS(SkFileDescriptorStream, (fd)); +} + +// static +size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, + int32_t* index) { + const unsigned filefaceid = UniqueIdToFileFaceId(fontID); + + if (IsRemoteFont(filefaceid)) + return 0; + + if (index) { + *index = filefaceid & 0xfu; + // 1 is a bogus return value. + // We had better change the signature of this function in Skia + // to return bool to indicate success/failure and have another + // out param for fileName length. + if (!path) + return 1; + } + + if (path) + SkASSERT(!"SkFontHost::GetFileName does not support the font path " + "retrieval."); + + return 0; +} diff --git a/skia/ext/SkFontHost_fontconfig_control.h b/skia/ext/SkFontHost_fontconfig_control.h new file mode 100644 index 0000000..336634b --- /dev/null +++ b/skia/ext/SkFontHost_fontconfig_control.h @@ -0,0 +1,38 @@ +/* libs/graphics/ports/SkFontHost_fontconfig_control.h +** +** Copyright 2009, 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. +*/ + +#ifndef FontConfigControl_DEFINED +#define FontConfigControl_DEFINED + +#include "SkPreConfig.h" + +class FontConfigInterface; + +// Sets the Skia FontHost to use the direct (non-IPC, requires filesystem +// access) FontConfig implementation. Any previously-set FontConfigInterface +// will be freed. +SK_API void SkiaFontConfigUseDirectImplementation(); + +// Sets the Skia FontHost to use the given implementation of FontConfig. This +// is normally used to configure the IPC-based implementation to get out of +// the sandbox. +// +// Ownership of the given pointer is transferred, and any previously-set +// FontConfigInterface will be freed. +SK_API void SkiaFontConfigSetImplementation(FontConfigInterface* font_config); + +#endif // FontConfigControl_DEFINED diff --git a/skia/ext/SkFontHost_fontconfig_direct.cpp b/skia/ext/SkFontHost_fontconfig_direct.cpp new file mode 100644 index 0000000..fb22106 --- /dev/null +++ b/skia/ext/SkFontHost_fontconfig_direct.cpp @@ -0,0 +1,504 @@ +/* libs/graphics/ports/SkFontHost_fontconfig_direct.cpp +** +** Copyright 2009, 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. +*/ + +#include "skia/ext/SkFontHost_fontconfig_direct.h" + +#include <unistd.h> +#include <fcntl.h> + +#include <fontconfig/fontconfig.h> + +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/core/SkUtils.h" + +namespace { + +// Equivalence classes, used to match the Liberation and other fonts +// with their metric-compatible replacements. See the discussion in +// GetFontEquivClass(). +enum FontEquivClass +{ + OTHER, + SANS, + SERIF, + MONO, + SYMBOL, + PGOTHIC, + GOTHIC, + PMINCHO, + MINCHO, + SIMSUN, + NSIMSUN, + SIMHEI, + PMINGLIU, + MINGLIU, + PMINGLIUHK, + MINGLIUHK, +}; + +// Match the font name against a whilelist of fonts, returning the equivalence +// class. +FontEquivClass GetFontEquivClass(const char* fontname) +{ + // It would be nice for fontconfig to tell us whether a given suggested + // replacement is a "strong" match (that is, an equivalent font) or + // a "weak" match (that is, fontconfig's next-best attempt at finding a + // substitute). However, I played around with the fontconfig API for + // a good few hours and could not make it reveal this information. + // + // So instead, we hardcode. Initially this function emulated + // /etc/fonts/conf.d/30-metric-aliases.conf + // from my Ubuntu system, but we're better off being very conservative. + + // Arimo, Tinos and Cousine are a set of fonts metric-compatible with + // Arial, Times New Roman and Courier New with a character repertoire + // much larger than Liberation. Note that Cousine is metrically + // compatible with Courier New, but the former is sans-serif while + // the latter is serif. + + + struct FontEquivMap { + FontEquivClass clazz; + const char name[40]; + }; + + static const FontEquivMap kFontEquivMap[] = { + { SANS, "Arial" }, + { SANS, "Arimo" }, + { SANS, "Liberation Sans" }, + + { SERIF, "Times New Roman" }, + { SERIF, "Tinos" }, + { SERIF, "Liberation Serif" }, + + { MONO, "Courier New" }, + { MONO, "Cousine" }, + { MONO, "Liberation Mono" }, + + { SYMBOL, "Symbol" }, + { SYMBOL, "Symbol Neu" }, + + // MS Pゴシック + { PGOTHIC, "MS PGothic" }, + { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" + "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, + { PGOTHIC, "IPAPGothic" }, + { PGOTHIC, "MotoyaG04Gothic" }, + + // MS ゴシック + { GOTHIC, "MS Gothic" }, + { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 " + "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, + { GOTHIC, "IPAGothic" }, + { GOTHIC, "MotoyaG04GothicMono" }, + + // MS P明朝 + { PMINCHO, "MS PMincho" }, + { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" + "\xe6\x98\x8e\xe6\x9c\x9d"}, + { PMINCHO, "IPAPMincho" }, + { PMINCHO, "MotoyaG04Mincho" }, + + // MS 明朝 + { MINCHO, "MS Mincho" }, + { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" }, + { MINCHO, "IPAMincho" }, + { MINCHO, "MotoyaG04MinchoMono" }, + + // 宋体 + { SIMSUN, "Simsun" }, + { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" }, + { SIMSUN, "MSung GB18030" }, + { SIMSUN, "Song ASC" }, + + // 新宋体 + { NSIMSUN, "NSimsun" }, + { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" }, + { NSIMSUN, "MSung GB18030" }, + { NSIMSUN, "N Song ASC" }, + + // 黑体 + { SIMHEI, "Simhei" }, + { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" }, + { SIMHEI, "MYingHeiGB18030" }, + { SIMHEI, "MYingHeiB5HK" }, + + // 新細明體 + { PMINGLIU, "PMingLiU"}, + { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, + { PMINGLIU, "MSung B5HK"}, + + // 細明體 + { MINGLIU, "MingLiU"}, + { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, + { MINGLIU, "MSung B5HK"}, + + // 新細明體 + { PMINGLIUHK, "PMingLiU_HKSCS"}, + { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, + { PMINGLIUHK, "MSung B5HK"}, + + // 細明體 + { MINGLIUHK, "MingLiU_HKSCS"}, + { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, + { MINGLIUHK, "MSung B5HK"}, + }; + + static const size_t kFontCount = + sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]); + + // TODO(jungshik): If this loop turns out to be hot, turn + // the array to a static (hash)map to speed it up. + for (size_t i = 0; i < kFontCount; ++i) { + if (strcasecmp(kFontEquivMap[i].name, fontname) == 0) + return kFontEquivMap[i].clazz; + } + return OTHER; +} + + +// Return true if |font_a| and |font_b| are visually and at the metrics +// level interchangeable. +bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b) +{ + FontEquivClass class_a = GetFontEquivClass(font_a); + FontEquivClass class_b = GetFontEquivClass(font_b); + + return class_a != OTHER && class_a == class_b; +} + +inline unsigned FileFaceIdToFileId(unsigned filefaceid) +{ + return filefaceid >> 4; +} + +inline unsigned FileIdAndFaceIndexToFileFaceId(unsigned fileid, int face_index) +{ + SkASSERT((face_index & 0xfu) == face_index); + return (fileid << 4) | face_index; +} + +// Normally we only return exactly the font asked for. In last-resort +// cases, the request either doesn't specify a font or is one of the +// basic font names like "Sans", "Serif" or "Monospace". This function +// tells you whether a given request is for such a fallback. +bool IsFallbackFontAllowed(const std::string& family) { + const char* family_cstr = family.c_str(); + return family.empty() || + strcasecmp(family_cstr, "sans") == 0 || + strcasecmp(family_cstr, "serif") == 0 || + strcasecmp(family_cstr, "monospace") == 0; +} + +// Find matching font from |font_set| for the given font family. +FcPattern* MatchFont(FcFontSet* font_set, + FcChar8* post_config_family, + const std::string& family) { + // Older versions of fontconfig have a bug where they cannot select + // only scalable fonts so we have to manually filter the results. + FcPattern* match = NULL; + for (int i = 0; i < font_set->nfont; ++i) { + FcPattern* current = font_set->fonts[i]; + FcBool is_scalable; + + if (FcPatternGetBool(current, FC_SCALABLE, 0, + &is_scalable) != FcResultMatch || + !is_scalable) { + continue; + } + + // fontconfig can also return fonts which are unreadable + FcChar8* c_filename; + if (FcPatternGetString(current, FC_FILE, 0, &c_filename) != FcResultMatch) + continue; + + if (access(reinterpret_cast<char*>(c_filename), R_OK) != 0) + continue; + + match = current; + break; + } + + if (match && !IsFallbackFontAllowed(family)) { + bool acceptable_substitute = false; + for (int id = 0; id < 255; ++id) { + FcChar8* post_match_family; + if (FcPatternGetString(match, FC_FAMILY, id, &post_match_family) != + FcResultMatch) + break; + acceptable_substitute = + (strcasecmp(reinterpret_cast<char*>(post_config_family), + reinterpret_cast<char*>(post_match_family)) == 0 || + // Workaround for Issue 12530: + // requested family: "Bitstream Vera Sans" + // post_config_family: "Arial" + // post_match_family: "Bitstream Vera Sans" + // -> We should treat this case as a good match. + strcasecmp(family.c_str(), + reinterpret_cast<char*>(post_match_family)) == 0) || + IsMetricCompatibleReplacement(family.c_str(), + reinterpret_cast<char*>(post_match_family)); + if (acceptable_substitute) + break; + } + if (!acceptable_substitute) + return NULL; + } + + return match; +} + +// Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|. +bool GetFontProperties(FcPattern* font, + std::string* font_family, + bool* is_bold, + bool* is_italic) { + FcChar8* c_family; + if (FcPatternGetString(font, FC_FAMILY, 0, &c_family)) + return false; + + int resulting_bold; + if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold)) + resulting_bold = FC_WEIGHT_NORMAL; + + int resulting_italic; + if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic)) + resulting_italic = FC_SLANT_ROMAN; + + // If we ask for an italic font, fontconfig might take a roman font and set + // the undocumented property FC_MATRIX to a skew matrix. It'll then say + // that the font is italic or oblique. So, if we see a matrix, we don't + // believe that it's italic. + FcValue matrix; + const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0; + + // If we ask for an italic font, fontconfig might take a roman font and set + // FC_EMBOLDEN. + FcValue embolden; + const bool have_embolden = + FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0; + + *is_bold = resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden; + *is_italic = resulting_italic > FC_SLANT_ROMAN && !have_matrix; + *font_family = reinterpret_cast<char*>(c_family); + + return true; +} + +} // anonymous namespace + +FontConfigDirect::FontConfigDirect() + : next_file_id_(0) { + FcInit(); +} + +FontConfigDirect::~FontConfigDirect() { +} + +bool FontConfigDirect::Match(std::string* result_family, + unsigned* result_filefaceid, + bool filefaceid_valid, unsigned filefaceid, + const std::string& family, + const void* data, size_t characters_bytes, + bool* is_bold, bool* is_italic) { + if (family.length() > kMaxFontFamilyLength) + return false; + + SkAutoMutexAcquire ac(mutex_); + + // Given |family|, |is_bold| and |is_italic| but not |data|, the result will + // be a function of these three parameters, and thus eligible for caching. + // This is the fast path for |SkTypeface::CreateFromName()|. + bool eligible_for_cache = !family.empty() && is_bold && is_italic && !data; + if (eligible_for_cache) { + int style = (*is_bold ? SkTypeface::kBold : 0 ) | + (*is_italic ? SkTypeface::kItalic : 0); + FontMatchKey key = FontMatchKey(family, style); + const std::map<FontMatchKey, FontMatch>::const_iterator i = + font_match_cache_.find(key); + if (i != font_match_cache_.end()) { + *is_bold = i->second.is_bold; + *is_italic = i->second.is_italic; + if (result_family) + *result_family = i->second.family; + if (result_filefaceid) + *result_filefaceid = i->second.filefaceid; + return true; + } + } + + FcPattern* pattern = FcPatternCreate(); + + if (filefaceid_valid) { + const std::map<unsigned, std::string>::const_iterator + i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid)); + if (i == fileid_to_filename_.end()) { + FcPatternDestroy(pattern); + return false; + } + int face_index = filefaceid & 0xfu; + FcPatternAddString(pattern, FC_FILE, + reinterpret_cast<const FcChar8*>(i->second.c_str())); + // face_index is added only when family is empty because it is not + // necessary to uniquiely identify a font if both file and + // family are given. + if (family.empty()) + FcPatternAddInteger(pattern, FC_INDEX, face_index); + } + if (!family.empty()) { + FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) family.c_str()); + } + + FcCharSet* charset = NULL; + if (data) { + charset = FcCharSetCreate(); + const uint16_t* chars = (const uint16_t*)data; + const uint16_t* stop = chars + characters_bytes/2; + while (chars < stop) { + FcCharSetAddChar(charset, SkUTF16_NextUnichar(&chars)); + } + FcPatternAddCharSet(pattern, FC_CHARSET, charset); + FcCharSetDestroy(charset); // pattern now owns it. + } + + FcPatternAddInteger(pattern, FC_WEIGHT, + is_bold && *is_bold ? FC_WEIGHT_BOLD + : FC_WEIGHT_NORMAL); + FcPatternAddInteger(pattern, FC_SLANT, + is_italic && *is_italic ? FC_SLANT_ITALIC + : FC_SLANT_ROMAN); + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); + + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + // Font matching: + // CSS often specifies a fallback list of families: + // font-family: a, b, c, serif; + // However, fontconfig will always do its best to find *a* font when asked + // for something so we need a way to tell if the match which it has found is + // "good enough" for us. Otherwise, we can return NULL which gets piped up + // and lets WebKit know to try the next CSS family name. However, fontconfig + // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we + // wish to support that. + // + // Thus, if a specific family is requested we set @family_requested. Then we + // record two strings: the family name after config processing and the + // family name after resolving. If the two are equal, it's a good match. + // + // So consider the case where a user has mapped Arial to Helvetica in their + // config. + // requested family: "Arial" + // post_config_family: "Helvetica" + // post_match_family: "Helvetica" + // -> good match + // + // and for a missing font: + // requested family: "Monaco" + // post_config_family: "Monaco" + // post_match_family: "Times New Roman" + // -> BAD match + // + // However, we special-case fallback fonts; see IsFallbackFontAllowed(). + FcChar8* post_config_family; + FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family); + + FcResult result; + FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); + if (!font_set) { + FcPatternDestroy(pattern); + return false; + } + + FcPattern* match = MatchFont(font_set, post_config_family, family); + if (!match) { + FcPatternDestroy(pattern); + FcFontSetDestroy(font_set); + return false; + } + + FcPatternDestroy(pattern); + + FcChar8* c_filename; + if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { + FcFontSetDestroy(font_set); + return false; + } + int face_index; + if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { + FcFontSetDestroy(font_set); + return false; + } + + FontMatch font_match; + if (filefaceid_valid) { + font_match.filefaceid = filefaceid; + } else { + unsigned out_fileid; + const std::string filename(reinterpret_cast<char*>(c_filename)); + const std::map<std::string, unsigned>::const_iterator + i = filename_to_fileid_.find(filename); + if (i == filename_to_fileid_.end()) { + out_fileid = next_file_id_++; + filename_to_fileid_[filename] = out_fileid; + fileid_to_filename_[out_fileid] = filename; + } else { + out_fileid = i->second; + } + // fileid stored in filename_to_fileid_ and fileid_to_filename_ is + // unique only up to the font file. We have to encode face_index for + // the out param. + font_match.filefaceid = + FileIdAndFaceIndexToFileFaceId(out_fileid, face_index); + } + + bool success = GetFontProperties(match, + &font_match.family, + &font_match.is_bold, + &font_match.is_italic); + FcFontSetDestroy(font_set); + + if (success) { + // If eligible, cache the result of the matching. + if (eligible_for_cache) { + int style = (*is_bold ? SkTypeface::kBold : 0 ) | + (*is_italic ? SkTypeface::kItalic : 0); + font_match_cache_[FontMatchKey(family, style)] = font_match; + } + + if (result_family) + *result_family = font_match.family; + if (result_filefaceid) + *result_filefaceid = font_match.filefaceid; + if (is_bold) + *is_bold = font_match.is_bold; + if (is_italic) + *is_italic = font_match.is_italic; + } + + return success; +} + +int FontConfigDirect::Open(unsigned filefaceid) { + SkAutoMutexAcquire ac(mutex_); + const std::map<unsigned, std::string>::const_iterator + i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid)); + if (i == fileid_to_filename_.end()) + return -1; + + return open(i->second.c_str(), O_RDONLY); +} diff --git a/skia/ext/SkFontHost_fontconfig_direct.h b/skia/ext/SkFontHost_fontconfig_direct.h new file mode 100644 index 0000000..ae97f3d --- /dev/null +++ b/skia/ext/SkFontHost_fontconfig_direct.h @@ -0,0 +1,59 @@ +/* libs/graphics/ports/SkFontHost_fontconfig_direct.h +** +** Copyright 2009, 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. +*/ + +#ifndef FontConfigDirect_DEFINED +#define FontConfigDirect_DEFINED + +#include <map> +#include <string> + +#include "SkThread.h" +#include "SkFontHost_fontconfig_impl.h" + +class SK_API FontConfigDirect : public FontConfigInterface { + public: + FontConfigDirect(); + virtual ~FontConfigDirect(); + + // FontConfigInterface implementation. Thread safe. + virtual bool Match(std::string* result_family, unsigned* result_filefaceid, + bool filefaceid_valid, unsigned filefaceid, + const std::string& family, + const void* characters, size_t characters_bytes, + bool* is_bold, bool* is_italic) SK_OVERRIDE; + virtual int Open(unsigned filefaceid) SK_OVERRIDE; + + private: + SkMutex mutex_; + // fileid stored in two maps below are unique per font file. + std::map<unsigned, std::string> fileid_to_filename_; + std::map<std::string, unsigned> filename_to_fileid_; + + // Cache of |family,style| to |FontMatch| to minimize querying FontConfig. + typedef std::pair<std::string, int> FontMatchKey; + struct FontMatch { + std::string family; + bool is_bold; + bool is_italic; + unsigned filefaceid; + }; + std::map<FontMatchKey, FontMatch> font_match_cache_; + + unsigned next_file_id_; +}; + +#endif // FontConfigDirect_DEFINED diff --git a/skia/ext/SkFontHost_fontconfig_impl.h b/skia/ext/SkFontHost_fontconfig_impl.h new file mode 100644 index 0000000..d6f81796 --- /dev/null +++ b/skia/ext/SkFontHost_fontconfig_impl.h @@ -0,0 +1,73 @@ +/* libs/graphics/ports/SkFontHost_fontconfig_impl.h +** +** Copyright 2009, 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. +*/ + +/* The SkFontHost_fontconfig code requires an implementation of an abstact + * fontconfig interface. We do this because sometimes fontconfig is not + * directly availible and this provides an ability to change the fontconfig + * implementation at run-time. + */ + +#ifndef FontConfigInterface_DEFINED +#define FontConfigInterface_DEFINED + +#include <string> + +class FontConfigInterface { + public: + virtual ~FontConfigInterface() { } + + /** Performs config match + * + * @param result_family (optional, set to NULL to ignore, output) + * on success, set to the resulting family name. + * @param result_filefaceid (optional, set to NULL to ignore, output) + * on success, set to the resulting fileface id. + * @param filefaceid_valid if true, then |filefaceid| is valid + * @param filefaceid the filefaceid (as returned by this function) + * which we are trying to match. + * @param family (optional) the family of the font that we are trying to + * match. If the length of the |family| is greater then + * kMaxFontFamilyLength, this function should immediately return false. + * @param characters (optional) UTF-16 characters the font must cover. + * @param characters_bytes (optional) number of bytes in |characters| + * @param is_bold (optional, set to NULL to ignore, in/out) + * @param is_italic (optional, set to NULL to ignore, in/out) + * @return true iff successful. + * Note that |filefaceid| uniquely identifies <font file, face_index) : + * system font: filefaceid = + * (fileid(unique per font file) << 4 | face_index) + * remote font: filefaceid = fileid + */ + virtual bool Match( + std::string* result_family, + unsigned* result_filefaceid, + bool filefaceid_valid, + unsigned filefaceid, + const std::string& family, + const void* characters, + size_t characters_bytes, + bool* is_bold, + bool* is_italic) = 0; + + /** Open a font file given the filefaceid as returned by Match. + */ + virtual int Open(unsigned filefaceid) = 0; + + static const unsigned kMaxFontFamilyLength = 2048; +}; + +#endif // FontConfigInterface_DEFINED diff --git a/skia/ext/skia_utils_base.cc b/skia/ext/skia_utils_base.cc deleted file mode 100644 index 07c06bb..0000000 --- a/skia/ext/skia_utils_base.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/ext/skia_utils_base.h" - -namespace skia { - -bool ReadSkString(const Pickle& pickle, PickleIterator* iter, SkString* str) { - int reply_length; - const char* reply_text; - - if (!pickle.ReadData(iter, &reply_text, &reply_length)) - return false; - - if (str) - str->set(reply_text, reply_length); - return true; -} - -bool ReadSkFontIdentity(const Pickle& pickle, PickleIterator* iter, - SkFontConfigInterface::FontIdentity* identity) { - uint32_t reply_id; - uint32_t reply_ttcIndex; - int reply_length; - const char* reply_text; - - if (!pickle.ReadUInt32(iter, &reply_id) || - !pickle.ReadUInt32(iter, &reply_ttcIndex) || - !pickle.ReadData(iter, &reply_text, &reply_length)) - return false; - - if (identity) { - identity->fID = reply_id; - identity->fTTCIndex = reply_ttcIndex; - identity->fString.set(reply_text, reply_length); - } - return true; -} - -bool WriteSkString(Pickle* pickle, const SkString& str) { - return pickle->WriteData(str.c_str(), str.size()); -} - -bool WriteSkFontIdentity(Pickle* pickle, - const SkFontConfigInterface::FontIdentity& identity) { - return pickle->WriteUInt32(identity.fID) && - pickle->WriteUInt32(identity.fTTCIndex) && - WriteSkString(pickle, identity.fString); -} - -} // namespace skia - diff --git a/skia/ext/skia_utils_base.h b/skia/ext/skia_utils_base.h deleted file mode 100644 index 2f94e40..0000000 --- a/skia/ext/skia_utils_base.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_SKIA_UTILS_BASE_H_ -#define SKIA_EXT_SKIA_UTILS_BASE_H_ - -#include "base/pickle.h" -#include "third_party/skia/include/ports/SkFontConfigInterface.h" - -namespace skia { - -// Return true if the pickle/iterator contains a string. If so, and if str -// is not null, copy that string into str. -SK_API bool ReadSkString(const Pickle& pickle, PickleIterator* iter, - SkString* str); - -// Return true if the pickle/iterator contains a FontIdentity. If so, and if -// identity is not null, copy it into identity. -SK_API bool ReadSkFontIdentity(const Pickle& pickle, PickleIterator* iter, - SkFontConfigInterface::FontIdentity* identity); - -// Return true if str can be written into the request pickle. -SK_API bool WriteSkString(Pickle* pickle, const SkString& str); - -// Return true if identity can be written into the request pickle. -SK_API bool WriteSkFontIdentity(Pickle* pickle, - const SkFontConfigInterface::FontIdentity& identity); - -} // namespace skia - -#endif // SKIA_EXT_SKIA_UTILS_WIN_H_ - diff --git a/skia/skia.gyp b/skia/skia.gyp index 71b34f2..340e64e0 100644 --- a/skia/skia.gyp +++ b/skia/skia.gyp @@ -182,8 +182,6 @@ 'ext/skia_sandbox_support_win.h', 'ext/skia_sandbox_support_win.cc', 'ext/skia_trace_shim.h', - 'ext/skia_utils_base.cc', - 'ext/skia_utils_base.h', 'ext/skia_utils_ios.mm', 'ext/skia_utils_ios.h', 'ext/skia_utils_mac.mm', @@ -376,11 +374,8 @@ '-Wno-unused-function', ], 'sources': [ - '../third_party/skia/src/ports/SkFontHost_fontconfig.cpp', - '../third_party/skia/src/ports/SkFontConfigInterface_direct.cpp', - ], - 'sources!': [ - '../third_party/skia/src/ports/SkFontHost_tables.cpp', + 'ext/SkFontHost_fontconfig.cpp', + 'ext/SkFontHost_fontconfig_direct.cpp', ], 'defines': [ # 'SK_USE_COLOR_LUMINANCE', |