diff options
-rw-r--r-- | skia/SConscript | 10 | ||||
-rw-r--r-- | skia/ports/SkFontHost_FreeType.cpp | 8 | ||||
-rw-r--r-- | skia/ports/SkFontHost_fontconfig.cpp | 323 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/FontCacheLinux.cpp | 52 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/FontLinux.cpp | 94 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp | 175 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h | 73 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp | 47 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp | 130 |
9 files changed, 638 insertions, 274 deletions
diff --git a/skia/SConscript b/skia/SConscript index 283d371..8dfd26a 100644 --- a/skia/SConscript +++ b/skia/SConscript @@ -154,6 +154,16 @@ input_files = [ 'sgl/SkXfermode.cpp', ] +if env['PLATFORM'] == 'posix': + # On Linux we use Skia to render fonts with FreeType and fontconfig + input_files.remove('sgl/SkTypeface_fake.cpp') + input_files.remove('ports/SkFontHost_none.cpp') + input_files.append('sgl/SkTypeface.cpp') + input_files.append('ports/SkFontHost_FreeType.cpp') + input_files.append('ports/SkFontHost_gamma.cpp') + input_files.append('ports/SkFontHost_fontconfig.cpp') + input_files.append('images/SkMMapStream.cpp') + if env['PLATFORM'] in ('darwin', 'posix'): input_files.append('ports/SkThread_pthread.cpp') diff --git a/skia/ports/SkFontHost_FreeType.cpp b/skia/ports/SkFontHost_FreeType.cpp index 4866f88..6430d2d 100644 --- a/skia/ports/SkFontHost_FreeType.cpp +++ b/skia/ports/SkFontHost_FreeType.cpp @@ -717,14 +717,6 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path) path->close(); } -static void map_y_to_pt(const FT_Matrix& mat, SkFixed y, SkPoint* pt) -{ - SkFixed x = SkFixedMul(mat.xy, y); - y = SkFixedMul(mat.yy, y); - - pt->set(SkFixedToScalar(x), SkFixedToScalar(y)); -} - void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { if (NULL == mx && NULL == my) diff --git a/skia/ports/SkFontHost_fontconfig.cpp b/skia/ports/SkFontHost_fontconfig.cpp new file mode 100644 index 0000000..2836db3 --- /dev/null +++ b/skia/ports/SkFontHost_fontconfig.cpp @@ -0,0 +1,323 @@ +/* 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 <fontconfig/fontconfig.h> + +#include "SkDescriptor.h" +#include "SkFontHost.h" +#include "SkMMapStream.h" +#include "SkPaint.h" +#include "SkStream.h" +#include "SkString.h" +#include "SkThread.h" +#include "SkTSearch.h" + +// This is an extern from SkFontHost_FreeType +SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name); + +// ----------------------------------------------------------------------------- +// The rest of Skia requires that fonts be identified by a unique unsigned id +// and that we be able to load them given the id. What we actually get from +// fontconfig is the filename of the font so we keep a locked map from +// filenames to fileid numbers and back. +// +// Note that there's also a unique id in the SkTypeface. This is unique over +// both filename and style. Thus we encode that id as (fileid << 8) | style. +// Although truetype fonts can support multiple faces in a single file, at the +// moment Skia doesn't. +// ----------------------------------------------------------------------------- +static SkMutex global_fc_map_lock; +static std::map<std::string, unsigned> global_fc_map; +static std::map<unsigned, std::string> global_fc_map_inverted; +static unsigned global_fc_map_next_id = 0; + +// This is the maximum size of the font cache. +static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB + +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) + { } +}; + +// ----------------------------------------------------------------------------- +// Find a matching font where @type (one of FC_*) is equal to @value. For a +// list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27. +// The variable arguments are a list of triples, just like the first three +// arguments, and must be NULL terminated. +// +// For example, FontMatchString(FC_FILE, FcTypeString, +// "/usr/share/fonts/myfont.ttf", NULL); +// ----------------------------------------------------------------------------- +static FcPattern* FontMatch(const char* type, FcType vtype, const void* value, + ...) +{ + va_list ap; + va_start(ap, value); + + FcPattern* pattern = FcPatternCreate(); + + for (;;) { + FcValue fcvalue; + fcvalue.type = vtype; + switch (vtype) { + case FcTypeString: + fcvalue.u.s = (FcChar8*) value; + break; + case FcTypeInteger: + fcvalue.u.i = (int) value; + break; + default: + SkASSERT(!"FontMatch unhandled type"); + } + FcPatternAdd(pattern, type, fcvalue, 0); + + type = va_arg(ap, const char *); + if (!type) + break; + // FcType is promoted to int when passed through ... + vtype = static_cast<FcType>(va_arg(ap, int)); + value = va_arg(ap, const void *); + }; + va_end(ap); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern* match = FcFontMatch(0, pattern, &result); + FcPatternDestroy(pattern); + + return match; +} + +// ----------------------------------------------------------------------------- +// Check to see if the filename has already been assigned a fileid and, if so, +// use it. Otherwise, assign one. Return the resulting fileid. +// ----------------------------------------------------------------------------- +static unsigned FileIdFromFilename(const char* filename) +{ + SkAutoMutexAcquire ac(global_fc_map_lock); + + std::map<std::string, unsigned>::const_iterator i = + global_fc_map.find(filename); + if (i == global_fc_map.end()) { + const unsigned fileid = global_fc_map_next_id++; + global_fc_map[filename] = fileid; + global_fc_map_inverted[fileid] = filename; + return fileid; + } else { + return i->second; + } +} + +SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, + const char familyName[], + SkTypeface::Style style) +{ + const char* resolved_family_name = NULL; + FcPattern* face_match = NULL; + + if (familyFace) { + // Here we use the inverted global id map to find the filename from the + // SkTypeface object. Given the filename we can ask fontconfig for the + // familyname of the font. + SkAutoMutexAcquire ac(global_fc_map_lock); + + const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID()); + std::map<unsigned, std::string>::const_iterator i = + global_fc_map_inverted.find(fileid); + if (i == global_fc_map_inverted.end()) + return NULL; + + FcInit(); + face_match = FontMatch(FC_FILE, FcTypeString, i->second.c_str(), NULL); + + if (!face_match) + return NULL; + FcChar8* family; + if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) { + FcPatternDestroy(face_match); + return NULL; + } + // At this point, @family is pointing into the @face_match object so we + // cannot release it yet. + + resolved_family_name = reinterpret_cast<char*>(family); + } else if (familyName) { + resolved_family_name = familyName; + } else { + return NULL; + } + + { + SkAutoMutexAcquire ac(global_fc_map_lock); + FcInit(); + } + + // At this point, we have a resolved_family_name from somewhere + SkASSERT(resolved_family_name); + + const int bold = style & SkTypeface::kBold ? + FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL; + const int italic = style & SkTypeface::kItalic ? + FC_SLANT_ITALIC : FC_SLANT_ROMAN; + FcPattern* match = FontMatch(FC_FULLNAME, FcTypeString, resolved_family_name, + FC_WEIGHT, FcTypeInteger, bold, + FC_SLANT, FcTypeInteger, italic, + NULL); + if (face_match) + FcPatternDestroy(face_match); + + if (!match) + return NULL; + + FcChar8* filename; + if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) { + FcPatternDestroy(match); + return NULL; + } + // Now @filename is pointing into @match + + const unsigned fileid = FileIdFromFilename(reinterpret_cast<char*>(filename)); + const unsigned id = FileIdAndStyleToUniqueId(fileid, style); + SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id)); + FcPatternDestroy(match); + return typeface; +} + +SkTypeface* SkFontHost::ResolveTypeface(uint32_t id) +{ + SkAutoMutexAcquire ac(global_fc_map_lock); + const SkTypeface::Style style = UniqueIdToStyle(id); + const unsigned fileid = UniqueIdToFileId(id); + + std::map<unsigned, std::string>::const_iterator i = + global_fc_map_inverted.find(fileid); + if (i == global_fc_map_inverted.end()) + return NULL; + + return SkNEW_ARGS(FontConfigTypeface, (style, id)); +} + +SkStream* SkFontHost::OpenStream(uint32_t id) +{ + SkAutoMutexAcquire ac(global_fc_map_lock); + const unsigned fileid = UniqueIdToFileId(id); + + std::map<unsigned, std::string>::const_iterator i = + global_fc_map_inverted.find(fileid); + if (i == global_fc_map_inverted.end()) + return NULL; + + return SkNEW_ARGS(SkFILEStream, (i->second.c_str())); +} + +void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream) +{ +} + +SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) +{ + SkASSERT(!"SkFontHost::CreateTypeface unimplemented"); + return NULL; +} + +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { + SkASSERT(!"SkFontHost::Deserialize unimplemented"); + return NULL; +} + +void SkFontHost::Serialize(const SkTypeface*, SkWStream*) { + SkASSERT(!"SkFontHost::Serialize unimplemented"); +} + +SkScalerContext* SkFontHost::CreateFallbackScalerContext + (const SkScalerContext::Rec& rec) { + FcPattern* pattern = FcPatternCreate(); + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern* match = FcFontMatch(0, pattern, &result); + FcPatternDestroy(pattern); + + // This will fail when we have no fonts on the system. + SkASSERT(match); + + FcChar8* filename; + if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) { + FcPatternDestroy(match); + return NULL; + } + // Now @filename is pointing into @match + + const unsigned id = FileIdFromFilename(reinterpret_cast<char*>(filename)); + FcPatternDestroy(match); + + SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); + SkDescriptor* desc = ad.getDesc(); + + desc->init(); + SkScalerContext::Rec* newRec = + (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, + sizeof(rec), &rec); + newRec->fFontID = id; + desc->computeChecksum(); + + return SkFontHost::CreateScalerContext(desc); +} + +/////////////////////////////////////////////////////////////////////////////// + +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) +{ + if (sizeAllocatedSoFar > kFontCacheMemoryBudget) + return sizeAllocatedSoFar - kFontCacheMemoryBudget; + else + return 0; // nothing to do +} diff --git a/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp b/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp index 2163c45..7a0606c 100644 --- a/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp +++ b/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp @@ -6,17 +6,20 @@ #include "FontCache.h" #include "AtomicString.h" +#include "CString.h" #include "FontDescription.h" #include "FontPlatformData.h" #include "Logging.h" #include "NotImplemented.h" +#include "SkPaint.h" +#include "SkTypeface.h" +#include "SkUtils.h" + namespace WebCore { void FontCache::platformInit() { - if (!FontPlatformData::init()) - ASSERT_NOT_REACHED(); } const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, @@ -58,7 +61,50 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { - return new FontPlatformData(fontDescription, family); + const char* name = 0; + CString s; + + if (family.length() == 0) { + static const struct { + FontDescription::GenericFamilyType mType; + const char* mName; + } gNames[] = { + { FontDescription::SerifFamily, "serif" }, + { FontDescription::SansSerifFamily, "sans-serif" }, + { FontDescription::MonospaceFamily, "monospace" }, + { FontDescription::CursiveFamily, "cursive" }, + { FontDescription::FantasyFamily, "fantasy" } + }; + + FontDescription::GenericFamilyType type = fontDescription.genericFamily(); + for (unsigned i = 0; i < SK_ARRAY_COUNT(gNames); i++) { + if (type == gNames[i].mType) { + name = gNames[i].mName; + break; + } + } + // if we fall out of the loop, it's ok for name to still be 0 + } + else { // convert the name to utf8 + s = family.string().utf8(); + name = s.data(); + } + + int style = SkTypeface::kNormal; + if (fontDescription.weight() >= FontWeightBold) + style |= SkTypeface::kBold; + if (fontDescription.italic()) + style |= SkTypeface::kItalic; + + SkTypeface* tf = SkTypeface::Create(name, (SkTypeface::Style)style); + + FontPlatformData* result = + new FontPlatformData(tf, + fontDescription.computedSize(), + (style & SkTypeface::kBold) && !tf->isBold(), + (style & SkTypeface::kItalic) && !tf->isItalic()); + tf->unref(); + return result; } AtomicString FontCache::getGenericFontForScript(UScriptCode script, diff --git a/webkit/port/platform/graphics/chromium/FontLinux.cpp b/webkit/port/platform/graphics/chromium/FontLinux.cpp index 2c186d1..230e31a 100644 --- a/webkit/port/platform/graphics/chromium/FontLinux.cpp +++ b/webkit/port/platform/graphics/chromium/FontLinux.cpp @@ -5,64 +5,58 @@ #include "config.h" #include "Font.h" -#include <pango/pango.h> -#include <pango/pangoft2.h> - #include "FloatRect.h" +#include "GlyphBuffer.h" +#include "GraphicsContext.h" #include "NotImplemented.h" #include "PlatformContextSkia.h" -#include "GraphicsContext.h" #include "SimpleFontData.h" -#include "GlyphBuffer.h" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkTemplates.h" +#include "SkTypeface.h" +#include "SkUtils.h" namespace WebCore { -// ----------------------------------------------------------------------------- -// Bitblit a Freetype bitmap onto a canvas at the given location in the given -// colour. -// pgc: the Skia canvas -// bm: A freetype bitmap which is an 8-bit alpha bitmap -// ----------------------------------------------------------------------------- -static void bitBlitAlpha(PlatformGraphicsContext* pgc, FT_Bitmap* bm, - int x, int y, const Color& col) -{ +void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, int from, int numGlyphs, + const FloatPoint& point) const { + SkCanvas* canvas = gc->platformContext()->canvas(); SkPaint paint; - paint.setARGB(col.alpha(), col.red(), col.green(), col.blue()); - - // Here we are constructing an SkBitmap by pointing directly into the - // Freetype bitmap data - SkBitmap glyph; - glyph.setConfig(SkBitmap::kA8_Config, bm->width, bm->rows, bm->pitch); - glyph.setPixels(bm->buffer); - pgc->canvas()->drawBitmap(glyph, x, y, &paint); -} -void Font::drawGlyphs(GraphicsContext* ctx, const SimpleFontData* sfd, - const GlyphBuffer& glyphBuffer, int from, int to, - const FloatPoint& point) const -{ - // For now we draw text by getting the Freetype face from Pango and asking - // Freetype to render each glyph as an 8-bit alpha bitmap and drawing that - // to the canvas. This, obviously, ignores kerning, ligatures and other - // things that we should have in the real version. - GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); - PlatformGraphicsContext* pgc = ctx->platformContext(); - FT_Face face = pango_ft2_font_get_face(sfd->m_font.m_font); - FT_GlyphSlot slot = face->glyph; - - int x = point.x(), y = point.y(); - - for (int i = from; i < to; ++i) { - const FT_Error error = FT_Load_Glyph(face, glyphs[i], FT_LOAD_RENDER); - if (error) - continue; - - bitBlitAlpha(pgc, &slot->bitmap, x + slot->bitmap_left, - y - slot->bitmap_top, ctx->fillColor()); - // Freetype works in 1/64ths of a pixel, so we divide by 64 to get the - // number of pixels to advance. - x += slot->advance.x >> 6; + font->platformData().setupPaint(&paint); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setColor(gc->fillColor().rgb()); + + SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert + + const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); + SkScalar x = SkFloatToScalar(point.x()); + SkScalar y = SkFloatToScalar(point.y()); + + // TODO(port): Android WebCore has patches for PLATFORM(SGL) which involves + // this, however we don't have these patches and it's unclear when Android + // may upstream them. +#if 0 + if (glyphBuffer.hasAdjustedWidths()) { + const GlyphBufferAdvance* adv = glyphBuffer.advances(from); + SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); + SkPoint* pos = storage.get(); + + for (int i = 0; i < numGlyphs; i++) { + pos[i].set(x, y); + x += SkFloatToScalar(adv[i].width()); + y += SkFloatToScalar(adv[i].height()); + } + canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); + } else { + canvas->drawText(glyphs, numGlyphs << 1, x, y, paint); } +#endif + + canvas->drawText(glyphs, numGlyphs << 1, x, y, paint); } void Font::drawComplexText(GraphicsContext* context, const TextRun& run, @@ -78,7 +72,7 @@ float Font::floatWidthForComplexText(const TextRun& run) const } int Font::offsetForPositionForComplexText(const TextRun& run, int x, - bool includePartialGlyphs) const + bool includePartialGlyphs) const { notImplemented(); return 0; @@ -86,7 +80,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int x, FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, - int from, int to) const + int from, int to) const { notImplemented(); return FloatRect(); diff --git a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp index e14a023..be21351 100644 --- a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -5,133 +5,98 @@ #include "config.h" #include "FontPlatformData.h" -#include <gtk/gtk.h> -#include <pango/pango.h> -#include <pango/pangoft2.h> - -#include "CString.h" -#include "FontDescription.h" -#include "NotImplemented.h" -#include "PlatformString.h" +#include "SkPaint.h" +#include "SkTypeface.h" namespace WebCore { -PangoFontMap* FontPlatformData::m_fontMap = 0; -GHashTable* FontPlatformData::m_hashTable = 0; - -FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) - : m_context(0) - , m_font(0) - , m_size(fontDescription.computedSize()) - , m_syntheticBold(false) - , m_syntheticOblique(false) +FontPlatformData::FontPlatformData(const FontPlatformData& src) { - FontPlatformData::init(); - - CString stored_family = familyName.string().utf8(); - char const* families[] = { - stored_family.data(), - NULL - }; - - switch (fontDescription.genericFamily()) { - case FontDescription::SerifFamily: - families[1] = "serif"; - break; - case FontDescription::SansSerifFamily: - families[1] = "sans"; - break; - case FontDescription::MonospaceFamily: - families[1] = "monospace"; - break; - case FontDescription::NoFamily: - case FontDescription::StandardFamily: - default: - families[1] = "sans"; - break; - } - - PangoFontDescription* description = pango_font_description_new(); - pango_font_description_set_absolute_size(description, fontDescription.computedSize() * PANGO_SCALE); + src.m_typeface->safeRef(); + m_typeface = src.m_typeface; - // FIXME: Map all FontWeight values to Pango font weights. - if (fontDescription.weight() >= FontWeight600) - pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD); - if (fontDescription.italic()) - pango_font_description_set_style(description, PANGO_STYLE_ITALIC); - - m_context = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(m_fontMap)); - - for (unsigned int i = 0; !m_font && i < G_N_ELEMENTS(families); i++) { - pango_font_description_set_family(description, families[i]); - pango_context_set_font_description(m_context, description); - m_font = pango_font_map_load_font(m_fontMap, m_context, description); - } - - pango_font_description_free(description); + m_textSize = src.m_textSize; + m_fakeBold = src.m_fakeBold; + m_fakeItalic = src.m_fakeItalic; } -FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : m_context(0) - , m_font(0) - , m_size(size) - , m_syntheticBold(bold) - , m_syntheticOblique(oblique) +FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic) + : m_typeface(tf) + , m_textSize(textSize) + , m_fakeBold(fakeBold) + , m_fakeItalic(fakeItalic) { + m_typeface->safeRef(); } -bool FontPlatformData::init() +FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) + : m_typeface(src.m_typeface) + , m_textSize(textSize) + , m_fakeBold(src.m_fakeBold) + , m_fakeItalic(src.m_fakeItalic) { - static bool initialized = false; - if (initialized) - return true; - initialized = true; - - if (!m_fontMap) - m_fontMap = pango_ft2_font_map_new(); - if (!m_hashTable) { - PangoFontFamily** families = 0; - int n_families = 0; - - m_hashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref); - - pango_font_map_list_families(m_fontMap, &families, &n_families); + m_typeface->safeRef(); +} - for (int family = 0; family < n_families; family++) - g_hash_table_insert(m_hashTable, - g_strdup(pango_font_family_get_name(families[family])), - g_object_ref(families[family])); +FontPlatformData::~FontPlatformData() +{ + m_typeface->safeUnref(); +} - g_free(families); - } +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) +{ + SkRefCnt_SafeAssign(m_typeface, src.m_typeface); - return true; + m_textSize = src.m_textSize; + m_fakeBold = src.m_fakeBold; + m_fakeItalic = src.m_fakeItalic; + + return *this; +} + +void FontPlatformData::setupPaint(SkPaint* paint) const +{ + const float ts = m_textSize > 0 ? m_textSize : 12; + + paint->setAntiAlias(true); + paint->setSubpixelText(true); + paint->setTextSize(SkFloatToScalar(ts)); + paint->setTypeface(m_typeface); + paint->setFakeBoldText(m_fakeBold); + paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1/4 : 0); + paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); } -bool FontPlatformData::isFixedPitch() const +bool FontPlatformData::operator==(const FontPlatformData& a) const { - PangoFontDescription* description = pango_font_describe_with_absolute_size(m_font); - PangoFontFamily* family = reinterpret_cast<PangoFontFamily*>(g_hash_table_lookup(m_hashTable, pango_font_description_get_family(description))); - pango_font_description_free(description); - return pango_font_family_is_monospace(family); + // If either of the typeface pointers are invalid (either NULL or the + // special deleted value) then we test for pointer equality. Otherwise, we + // call SkTypeface::Equal on the valid pointers. + const bool typefaces_equal = + (m_typeface == hashTableDeletedFontValue() || + a.m_typeface == hashTableDeletedFontValue() || + !m_typeface || !a.m_typeface) ? + (m_typeface == a.m_typeface) : + SkTypeface::Equal(m_typeface, a.m_typeface); + return typefaces_equal && + m_textSize == a.m_textSize && + m_fakeBold == a.m_fakeBold && + m_fakeItalic == a.m_fakeItalic; } -FontPlatformData::~FontPlatformData() { +unsigned FontPlatformData::hash() const +{ + // This is taken from Android code. It is not our fault. + unsigned h = SkTypeface::UniqueID(m_typeface); + h ^= 0x01010101 * (((int)m_fakeBold << 1) | (int)m_fakeItalic); + h ^= *reinterpret_cast<const uint32_t *>(&m_textSize); + return h; } -bool FontPlatformData::operator==(const FontPlatformData& other) const +bool FontPlatformData::isFixedPitch() const { - if (m_font == other.m_font) - return true; - if (m_font == 0 || m_font == reinterpret_cast<PangoFont*>(-1) - || other.m_font == 0 || other.m_font == reinterpret_cast<PangoFont*>(-1)) - return false; - PangoFontDescription* thisDesc = pango_font_describe(m_font); - PangoFontDescription* otherDesc = pango_font_describe(other.m_font); - bool result = pango_font_description_equal(thisDesc, otherDesc); - pango_font_description_free(otherDesc); - pango_font_description_free(thisDesc); - return result; + notImplemented(); + return false; } } // namespace WebCore diff --git a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h index b8ae94f..0d67b24 100644 --- a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h @@ -8,17 +8,23 @@ #include "config.h" #include "build/build_config.h" -#include <pango/pango.h> - #include "StringImpl.h" #include "NotImplemented.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +class SkPaint; +class SkTypeface; + namespace WebCore { class FontDescription; +// ----------------------------------------------------------------------------- +// FontPlatformData is the handle which WebKit has on a specific face. A face +// is the tuple of (font, size, ...etc). Here we are just wrapping a Skia +// SkTypeface pointer and dealing with the reference counting etc. +// ----------------------------------------------------------------------------- class FontPlatformData { public: // Used for deleted values in the font cache's hash tables. The hash table @@ -27,47 +33,56 @@ public: // from the NULL one (created with the empty constructor), so we can't just // set everything to NULL. FontPlatformData(WTF::HashTableDeletedValueType) - : m_context(0) - , m_font(hashTableDeletedFontValue()) + : m_typeface(hashTableDeletedFontValue()) + , m_textSize(0) + , m_fakeBold(false) + , m_fakeItalic(false) { } FontPlatformData() - : m_context(0) - , m_font(0) + : m_typeface(0) + , m_textSize(0) + , m_fakeBold(false) + , m_fakeItalic(false) { } - FontPlatformData(const FontDescription&, const AtomicString& family); - - FontPlatformData(float size, bool bold, bool oblique); + FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) + : m_typeface(0) + , m_textSize(textSize) + , m_fakeBold(fakeBold) + , m_fakeItalic(fakeItalic) + { } + FontPlatformData(const FontPlatformData&); + FontPlatformData(SkTypeface *, float textSize, bool fakeBold, bool fakeItalic); + FontPlatformData(const FontPlatformData& src, float textSize); ~FontPlatformData(); - static bool init(); - + // ------------------------------------------------------------------------- + // Return true iff this font is monospaced (i.e. every glyph has an equal x + // advance) + // ------------------------------------------------------------------------- bool isFixedPitch() const; - float size() const { return m_size; } - unsigned hash() const - { - notImplemented(); - return 0; - } + // ------------------------------------------------------------------------- + // Setup a Skia painting context to use this font. + // ------------------------------------------------------------------------- + void setupPaint(SkPaint*) const; - bool operator==(const FontPlatformData& other) const; - bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); } - - static PangoFontMap* m_fontMap; - static GHashTable* m_hashTable; - - PangoContext* m_context; - PangoFont* m_font; + unsigned hash() const; + float size() const { return m_textSize; } - float m_size; - bool m_syntheticBold; - bool m_syntheticOblique; + bool operator==(const FontPlatformData& other) const; + FontPlatformData& operator=(const FontPlatformData& src); + bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); } private: - static PangoFont* hashTableDeletedFontValue() { return reinterpret_cast<PangoFont*>(-1); } + SkTypeface* m_typeface; + float m_textSize; + bool m_fakeBold; + bool m_fakeItalic; + + SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); } }; } // namespace WebCore diff --git a/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp b/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp index 1e7eb79..fd5aa4e 100644 --- a/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp +++ b/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp @@ -30,44 +30,43 @@ #include "config.h" #include "GlyphPageTreeNode.h" -// This PANGO_ENABLE_BACKEND define lets us get at some of the internal Pango -// call which we need. This include must be here otherwise we include pango.h -// via another route (without the define) and that sets the include guard. -// Then, when we try to include it in the future the guard stops us getting the -// functions that we need. -#define PANGO_ENABLE_BACKEND -#include <pango/pango.h> -#include <pango/pangofc-font.h> - #include "Font.h" #include "NotImplemented.h" #include "SimpleFontData.h" +#include "SkTemplates.h" +#include "SkPaint.h" +#include "SkUtils.h" + namespace WebCore { bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { - // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters. - // We won't support this for now. - if (bufferLength > GlyphPage::size) + if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { + SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; - - if (!fontData->m_font.m_font || fontData->m_font.m_font == reinterpret_cast<PangoFont*>(-1)) + } + + SkPaint paint; + fontData->platformData().setupPaint(&paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length); + uint16_t* glyphs = glyphStorage.get(); + // textToGlyphs takes a byte count, not a glyph count so we multiply by two. + unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs); + if (count != length) { + SkDebugf("%s count != length\n", __FUNCTION__); return false; + } - bool haveGlyphs = false; + unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero for (unsigned i = 0; i < length; i++) { - Glyph glyph = pango_fc_font_get_glyph(PANGO_FC_FONT(fontData->m_font.m_font), buffer[i]); - if (!glyph) - setGlyphDataForIndex(offset + i, 0, 0); - else { - setGlyphDataForIndex(offset + i, glyph, fontData); - haveGlyphs = true; - } + setGlyphDataForIndex(offset + i, glyphs[i], fontData); + allGlyphs |= glyphs[i]; } - - return haveGlyphs; + return allGlyphs != 0; } } // namespace WebCore diff --git a/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp b/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp index 26caef8..7371275 100644 --- a/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -2,15 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define PANGO_ENABLE_BACKEND - #include "config.h" #include "SimpleFontData.h" -#include <pango/pango.h> -#include <pango/pangoft2.h> -#include <pango/pangofc-font.h> - #include "Font.h" #include "FontCache.h" #include "FloatRect.h" @@ -18,66 +12,88 @@ #include "Logging.h" #include "NotImplemented.h" +#include "SkPaint.h" +#include "SkTypeface.h" +#include "SkTime.h" + namespace WebCore { -// TODO(agl): only stubs +// Smallcaps versions of fonts are 70% the size of the normal font. +static const float kSmallCapsFraction = 0.7f; void SimpleFontData::platformInit() { - PangoFont *const font = platformData().m_font; - - PangoFontMetrics *const metrics = pango_font_get_metrics(font, NULL); - m_ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; - m_descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE; - m_lineSpacing = m_ascent + m_descent; - m_avgCharWidth = pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE; - pango_font_metrics_unref(metrics); - - const guint xglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), 'x'); - const guint spaceglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), ' '); - PangoRectangle rect; - - pango_font_get_glyph_extents(font, xglyph, &rect, NULL); - m_xHeight = rect.height / PANGO_SCALE; - pango_font_get_glyph_extents(font, spaceglyph, NULL, &rect); - m_spaceWidth = rect.width / PANGO_SCALE; - m_lineGap = m_lineSpacing - m_ascent - m_descent; - - FT_Face face = pango_ft2_font_get_face(font); - m_unitsPerEm = face->units_per_EM / PANGO_SCALE; - - // TODO(agl): I'm not sure we have good data for this so it's 0 for now - m_maxCharWidth = 0; + SkPaint paint; + SkPaint::FontMetrics metrics; + + m_font.setupPaint(&paint); + paint.getFontMetrics(&metrics); + + // use ceil instead of round to favor descent, given a lot of accidental + // clipping of descenders (e.g. 14pt 'g') in textedit fields + const int descent = SkScalarCeil(metrics.fDescent); + const int span = SkScalarRound(metrics.fDescent - metrics.fAscent); + const int ascent = span - descent; + + m_ascent = ascent; + m_descent = descent; + m_xHeight = SkScalarToFloat(-metrics.fAscent) * 0.56f; // hack I stole from the Windows port + m_lineSpacing = ascent + descent; + m_lineGap = SkScalarRound(metrics.fLeading); + + // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is + // calculated for us, but we need to calculate m_maxCharWidth and + // m_avgCharWidth in order for text entry widgets to be sized correctly. + // Skia doesn't expose either of these so we calculate them ourselves + + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + if (!glyphPageZero) + return; + + static const UChar32 e_char = 'e'; + static const UChar32 M_char = 'M'; + m_avgCharWidth = widthForGlyph(glyphPageZero->glyphDataForCharacter(e_char).glyph); + m_maxCharWidth = widthForGlyph(glyphPageZero->glyphDataForCharacter(M_char).glyph); } -void SimpleFontData::platformDestroy() { } +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; +} SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - notImplemented(); - return NULL; + if (!m_smallCapsFontData) { + m_smallCapsFontData = + new SimpleFontData(FontPlatformData(m_font, fontDescription.computedSize() * kSmallCapsFraction)); + } + return m_smallCapsFontData; } -bool SimpleFontData::containsCharacters(const UChar* characters, - int length) const +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { - bool result = true; - - PangoCoverage* requested = pango_coverage_from_bytes((guchar*)characters, length); - PangoCoverage* available = pango_font_get_coverage(m_font.m_font, pango_language_get_default()); - pango_coverage_max(requested, available); - - for (int i = 0; i < length; i++) { - if (PANGO_COVERAGE_NONE == pango_coverage_get(requested, i)) { - result = false; - break; + SkPaint paint; + static const unsigned kMaxBufferCount = 64; + uint16_t glyphs[kMaxBufferCount]; + + m_font.setupPaint(&paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + while (length > 0) { + int n = SkMin32(length, SK_ARRAY_COUNT(glyphs)); + + // textToGlyphs takes a byte count so we double the character count. + int count = paint.textToGlyphs(characters, n * 2, glyphs); + for (int i = 0; i < count; i++) { + if (0 == glyphs[i]) { + return false; // missing glyph + } } - } - pango_coverage_unref(requested); - pango_coverage_unref(available); - - return result; + characters += n; + length -= n; + } + return true; } void SimpleFontData::determinePitch() @@ -87,12 +103,16 @@ void SimpleFontData::determinePitch() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - PangoFont *const font = platformData().m_font; - PangoRectangle rect; + SkASSERT(sizeof(glyph) == 2); // compile-time assert + + SkPaint paint; - pango_font_get_glyph_extents(font, glyph, NULL, &rect); + m_font.setupPaint(&paint); - return static_cast<float>(rect.width) / PANGO_SCALE; + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkScalar width = paint.measureText(&glyph, 2); + + return SkScalarToFloat(width); } } // namespace WebCore |