WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-69826-20120301123646.patch (text/plain), 60.99 KB, created by
Kenichi Ishibashi
on 2012-02-29 19:36:48 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Kenichi Ishibashi
Created:
2012-02-29 19:36:48 PST
Size:
60.99 KB
patch
obsolete
>Subversion Revision: 109293 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 63351bd62c5c6a902c9487b6dbecb5c97b8862c3..8ba4b071b1460a684ef6147b706d75c94655e72c 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,84 @@ >+2012-02-29 Kenichi Ishibashi <bashi@chromium.org> >+ >+ [Chromium] Implement font shaping with font-feature-settings on Mac >+ https://bugs.webkit.org/show_bug.cgi?id=69826 >+ >+ Add HarfBuzz-ng text shaper. >+ Chromium mac port uses it as secondary text shaper to support OpenType features. >+ HarfBuzz-ng is only used when -webkit-font-feature-settings is specified and >+ corresponding font is not an AAT font. >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ No new tests. css3/font-feature-settings-rendering.html should pass on Chromium mac port. >+ >+ * WebCore.gyp/WebCore.gyp: Added harfbuzz-ng dependencies. >+ * WebCore.gypi: Added harfbuzz-ng files. >+ * platform/graphics/FontPlatformData.h: >+ (FontPlatformData): Added m_harfbuzzFace. >+ * platform/graphics/cocoa/FontPlatformDataCocoa.mm: >+ (WebCore::FontPlatformData::platformDataInit): Copy m_harfbuzzFace. >+ (WebCore::FontPlatformData::platformDataAssign): Ditto. >+ (WebCore): >+ (WebCore::isAATFont): >+ (WebCore::FontPlatformData::harfbuzzFace): >+ * platform/graphics/harfbuzz/ng/HarfBuzzFace.cpp: Added. >+ (WebCore): >+ (WebCore::harfbuzzFaceCache): >+ (WebCore::HarfBuzzFace::HarfBuzzFace): >+ (WebCore::HarfBuzzFace::~HarfBuzzFace): >+ * platform/graphics/harfbuzz/ng/HarfBuzzFace.h: Added. >+ (WebCore): >+ (HarfBuzzFace): >+ (WebCore::HarfBuzzFace::create): >+ * platform/graphics/harfbuzz/ng/HarfBuzzFaceCoreText.cpp: Added. >+ (WebCore): >+ (WebCore::floatToHarfBuzzPosition): >+ (WebCore::getGlyph): >+ (WebCore::getGlyphHorizontalAdvance): >+ (WebCore::getGlyphHorizontalOrigin): >+ (WebCore::getGlyphExtents): >+ (WebCore::harfbuzzCoreTextGetFontFuncs): >+ (WebCore::releaseTableData): >+ (WebCore::harfbuzzCoreTextGetTable): >+ (WebCore::HarfBuzzFace::createFace): >+ (WebCore::HarfBuzzFace::createFont): >+ (WebCore::HarfBuzzShaper::createGlyphBufferAdvance): >+ * platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp: Added. >+ (WebCore): >+ (WebCore::harfbuzzPositionToFloat): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::xPositionForOffset): >+ (WebCore::HarfBuzzShaper::HarfBuzzShaper): >+ (WebCore::HarfBuzzShaper::~HarfBuzzShaper): >+ (WebCore::HarfBuzzShaper::setFontFeatures): >+ (WebCore::HarfBuzzShaper::shape): >+ (WebCore::HarfBuzzShaper::setupHarfBuzzRun): >+ (WebCore::HarfBuzzShaper::shapeHarfBuzzRun): >+ (WebCore::HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun): >+ (WebCore::HarfBuzzShaper::offsetForPosition): >+ (WebCore::HarfBuzzShaper::selectionRect): >+ * platform/graphics/harfbuzz/ng/HarfBuzzShaper.h: Added. >+ (WebCore): >+ (HarfBuzzShaper): >+ (WebCore::HarfBuzzShaper::totalWidth): >+ (HarfBuzzRun): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::create): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::setWidth): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::numCharacters): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::numGlyphs): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::width): >+ (WebCore::HarfBuzzShaper::HarfBuzzRun::rtl): >+ * platform/graphics/mac/FontComplexTextMac.cpp: >+ (WebCore): >+ (WebCore::preferHarfBuzz): Added. >+ (WebCore::Font::selectionRectForComplexText): Use HarfBuzzShaper if font-feature-settings exists. >+ (WebCore::Font::drawComplexText): Ditto. >+ (WebCore::Font::floatWidthForComplexText): Ditto. >+ (WebCore::Font::offsetForPositionForComplexText): Ditto. >+ > 2012-02-29 Shinya Kawanaka <shinyak@chromium.org> > > Methods in ShadowTree and TreeScopeAdopter should be multiple shadow roots aware. >diff --git a/Source/WebCore/WebCore.gyp/WebCore.gyp b/Source/WebCore/WebCore.gyp/WebCore.gyp >index b777fe067362e9ffd2e8da9ff133aa35e4207906..9538e72f7e948ee394679674fa90f110cbeb12fc 100644 >--- a/Source/WebCore/WebCore.gyp/WebCore.gyp >+++ b/Source/WebCore/WebCore.gyp/WebCore.gyp >@@ -214,6 +214,8 @@ > '../platform/graphics/mac', > '../platform/mac', > '../platform/text/mac', >+ '../platform/graphics/harfbuzz', >+ '../platform/graphics/harfbuzz/ng', > ], > }], > ['OS=="mac" and use_skia==1', { >@@ -1528,6 +1530,7 @@ > ], > 'dependencies': [ > 'webkit_system_interface', >+ '<(chromium_src_dir)/third_party/harfbuzz-ng/harfbuzz.gyp:harfbuzz-ng', > ], > 'actions': [ > { >@@ -1608,6 +1611,12 @@ > ['exclude', 'platform/ScrollAnimatorNone\\.cpp$'], > ['exclude', 'platform/ScrollAnimatorNone\\.h$'], > >+ # Mac uses HarfBuzz-ng. >+ ['include', 'platform/graphics/harfbuzz/HarfBuzzShaperBase\\.(cpp|h)$'], >+ ['include', 'platform/graphics/harfbuzz/ng/HarfBuzzFaceCoreText\\.cpp$'], >+ ['include', 'platform/graphics/harfbuzz/ng/HarfBuzzFace\\.(cpp|h)$'], >+ ['include', 'platform/graphics/harfbuzz/ng/HarfBuzzShaper\\.(cpp|h)$'], >+ > ['include', '/chrome/junk\\.txt$'], > ], > },{ # OS!="mac" >diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi >index ae1eac77df3a81d1fa175fc3bd68362138d9702e..d8f625f7ff95fff82565d8ad588da320347fdb1c 100644 >--- a/Source/WebCore/WebCore.gypi >+++ b/Source/WebCore/WebCore.gypi >@@ -3509,6 +3509,11 @@ > 'platform/graphics/harfbuzz/HarfBuzzSkia.h', > 'platform/graphics/harfbuzz/HarfBuzzShaperBase.cpp', > 'platform/graphics/harfbuzz/HarfBuzzShaperBase.h', >+ 'platform/graphics/harfbuzz/ng/HarfBuzzFaceCoreText.cpp', >+ 'platform/graphics/harfbuzz/ng/HarfBuzzFace.cpp', >+ 'platform/graphics/harfbuzz/ng/HarfBuzzFace.h', >+ 'platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp', >+ 'platform/graphics/harfbuzz/ng/HarfBuzzShaper.h', > 'platform/graphics/mac/ColorMac.mm', > 'platform/graphics/mac/ComplexTextController.cpp', > 'platform/graphics/mac/ComplexTextController.h', >diff --git a/Source/WebCore/platform/graphics/FontPlatformData.h b/Source/WebCore/platform/graphics/FontPlatformData.h >index 705c58897145df8b2c2fa44277011f890e36e7fc..504b313a4134f987e549e35978d531286a781b63 100644 >--- a/Source/WebCore/platform/graphics/FontPlatformData.h >+++ b/Source/WebCore/platform/graphics/FontPlatformData.h >@@ -72,6 +72,7 @@ typedef const struct __CTFont* CTFontRef; > > #if PLATFORM(CHROMIUM) && OS(DARWIN) > #include "CrossProcessFontLoading.h" >+#include "HarfBuzzFace.h" > #endif > > #if PLATFORM(WIN) >@@ -236,6 +237,10 @@ public: > cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } > #endif > >+#if PLATFORM(CHROMIUM) && OS(DARWIN) >+ HarfBuzzFace* harfbuzzFace(); >+#endif >+ > unsigned hash() const > { > #if PLATFORM(WIN) && !USE(CAIRO) >@@ -332,6 +337,7 @@ private: > > #if PLATFORM(CHROMIUM) && OS(DARWIN) > RefPtr<MemoryActivatedFont> m_inMemoryFont; >+ RefPtr<HarfBuzzFace> m_harfbuzzFace; > #endif > > bool m_isColorBitmapFont; >diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm >index 7b136088343ae084e2e4ae407bbe089ad867c474..88d3f5201ba56193b15bcc393ba5ddca996295f9 100644 >--- a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm >+++ b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm >@@ -84,6 +84,7 @@ void FontPlatformData::platformDataInit(const FontPlatformData& f) > > #if PLATFORM(CHROMIUM) && OS(DARWIN) > m_inMemoryFont = f.m_inMemoryFont; >+ m_harfbuzzFace = f.m_harfbuzzFace; > #endif > } > >@@ -100,6 +101,7 @@ const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformD > m_CTFont = f.m_CTFont; > #if PLATFORM(CHROMIUM) && OS(DARWIN) > m_inMemoryFont = f.m_inMemoryFont; >+ m_harfbuzzFace = f.m_harfbuzzFace; > #endif > return *this; > } >@@ -276,6 +278,37 @@ CTFontRef FontPlatformData::ctFont() const > return m_CTFont.get(); > } > >+#if PLATFORM(CHROMIUM) && OS(DARWIN) >+static bool isAATFont(CTFontRef ctFont) >+{ >+ CFDataRef table = CTFontCopyTable(ctFont, kCTFontTableMort, kCTFontOptionsDefault); >+ if (table) { >+ CFRelease(table); >+ return true; >+ } >+ table = CTFontCopyTable(ctFont, kCTFontTableMorx, kCTFontOptionsDefault); >+ if (table) { >+ CFRelease(table); >+ return true; >+ } >+ return false; >+} >+ >+HarfBuzzFace* FontPlatformData::harfbuzzFace() >+{ >+ CTFontRef font = ctFont(); >+ // HarfBuzz can't handle AAT font >+ if (isAATFont(font)) >+ return 0; >+ >+ if (!m_harfbuzzFace) { >+ uint64_t uniqueID = reinterpret_cast<uintptr_t>(font); >+ m_harfbuzzFace = HarfBuzzFace::create(const_cast<FontPlatformData*>(this), uniqueID); >+ } >+ return m_harfbuzzFace.get(); >+} >+#endif >+ > #ifndef NDEBUG > String FontPlatformData::description() const > { >diff --git a/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFace.cpp b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFace.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..49ddbabb22bda9677a558710a51792fb5baa141e >--- /dev/null >+++ b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFace.cpp >@@ -0,0 +1,80 @@ >+/* >+ * Copyright (c) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "HarfBuzzFace.h" >+ >+#include "FontPlatformData.h" >+#include "hb.h" >+#include <wtf/HashMap.h> >+ >+namespace WebCore { >+ >+// Though we have FontCache class, which provides the cache mechanism for >+// WebKit's font objects, we also need additional caching layer for HarfBuzz >+// to reduce the memory consumption because hb_face_t should be associated with >+// underling font data (e.g. CTFontRef, FTFace). >+typedef pair<hb_face_t*, unsigned> FaceCacheEntry; >+typedef HashMap<uint64_t, FaceCacheEntry, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t> > HarfBuzzFaceCache; >+ >+static HarfBuzzFaceCache* harfbuzzFaceCache() >+{ >+ DEFINE_STATIC_LOCAL(HarfBuzzFaceCache, s_harfbuzzFaceCache, ()); >+ return &s_harfbuzzFaceCache; >+} >+ >+HarfBuzzFace::HarfBuzzFace(FontPlatformData* platformData, uint64_t uniqueID) >+ : m_platformData(platformData) >+ , m_uniqueID(uniqueID) >+{ >+ HarfBuzzFaceCache::iterator result = harfbuzzFaceCache()->find(m_uniqueID); >+ if (result == harfbuzzFaceCache()->end()) { >+ m_face = createFace(); >+ ASSERT(m_face); >+ harfbuzzFaceCache()->set(m_uniqueID, FaceCacheEntry(m_face, 1)); >+ } else { >+ ++(result.get()->second.second); >+ m_face = result.get()->second.first; >+ } >+} >+ >+HarfBuzzFace::~HarfBuzzFace() >+{ >+ HarfBuzzFaceCache::iterator result = harfbuzzFaceCache()->find(m_uniqueID); >+ ASSERT(result != harfbuzzFaceCache()->end()); >+ ASSERT(result.get()->second.second > 0); >+ --(result.get()->second.second); >+ if (!(result.get()->second.second)) { >+ hb_face_destroy(result.get()->second.first); >+ harfbuzzFaceCache()->remove(m_uniqueID); >+ } >+} >+ >+} // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFace.h b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFace.h >new file mode 100644 >index 0000000000000000000000000000000000000000..afc26b1b1f20c3ffa79b88fb68d99cad792f484b >--- /dev/null >+++ b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFace.h >@@ -0,0 +1,69 @@ >+/* >+ * Copyright (c) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef HarfBuzzFace_h >+#define HarfBuzzFace_h >+ >+#include <wtf/PassRefPtr.h> >+#include <wtf/RefCounted.h> >+#include <wtf/RefPtr.h> >+ >+struct _hb_face_t; >+typedef _hb_face_t hb_face_t; >+struct _hb_font_t; >+typedef _hb_font_t hb_font_t; >+ >+namespace WebCore { >+ >+class FontPlatformData; >+ >+class HarfBuzzFace : public RefCounted<HarfBuzzFace> { >+public: >+ static PassRefPtr<HarfBuzzFace> create(FontPlatformData* platformData, uint64_t uniqueID) >+ { >+ return adoptRef(new HarfBuzzFace(platformData, uniqueID)); >+ } >+ ~HarfBuzzFace(); >+ >+ hb_font_t* createFont(); >+ >+private: >+ HarfBuzzFace(FontPlatformData*, uint64_t); >+ >+ hb_face_t* createFace(); >+ >+ FontPlatformData* m_platformData; >+ uint64_t m_uniqueID; >+ hb_face_t* m_face; >+}; >+ >+} >+ >+#endif // HarfBuzzFace_h >diff --git a/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFaceCoreText.cpp b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFaceCoreText.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..96ceb451796c772cd717c19d7ad43daa9c380759 >--- /dev/null >+++ b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzFaceCoreText.cpp >@@ -0,0 +1,148 @@ >+/* >+ * Copyright (c) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "HarfBuzzFace.h" >+ >+#include "CoreText/CoreText.h" >+#include "FontPlatformData.h" >+#include "HarfBuzzShaper.h" >+#include "SimpleFontData.h" >+ >+#include "hb.h" >+ >+namespace WebCore { >+ >+static hb_position_t floatToHarfBuzzPosition(CGFloat value) >+{ >+ return static_cast<hb_position_t>(value * (1 << 16)); >+} >+ >+static hb_bool_t getGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData) >+{ >+ CTFontRef ctFont = reinterpret_cast<FontPlatformData*>(fontData)->ctFont(); >+ UniChar characters[4]; >+ CGGlyph cgGlyphs[4]; >+ size_t length = 0; >+ U16_APPEND_UNSAFE(characters, length, unicode); >+ if (!CTFontGetGlyphsForCharacters(ctFont, characters, cgGlyphs, length)) >+ return false; >+ *glyph = cgGlyphs[0]; >+ return true; >+} >+ >+static hb_position_t getGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData) >+{ >+ CTFontRef ctFont = reinterpret_cast<FontPlatformData*>(fontData)->ctFont(); >+ CGGlyph cgGlyph = glyph; >+ CGFloat advance = CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &cgGlyph, 0, 1); >+ return floatToHarfBuzzPosition(advance); >+} >+ >+static hb_bool_t getGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData) >+{ >+ return true; >+} >+ >+static hb_bool_t getGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) >+{ >+ CTFontRef ctFont = reinterpret_cast<FontPlatformData*>(fontData)->ctFont(); >+ CGRect cgRect; >+ CGGlyph cgGlyph = glyph; >+ if (CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontDefaultOrientation, &cgGlyph, &cgRect, 1) == CGRectNull) >+ return false; >+ extents->x_bearing = floatToHarfBuzzPosition(cgRect.origin.x); >+ extents->y_bearing = -floatToHarfBuzzPosition(cgRect.origin.y); >+ extents->width = floatToHarfBuzzPosition(cgRect.size.width); >+ extents->height = floatToHarfBuzzPosition(cgRect.size.height); >+ return true; >+} >+ >+static hb_font_funcs_t* harfbuzzCoreTextGetFontFuncs() >+{ >+ static hb_font_funcs_t* harfbuzzCoreTextFontFuncs = 0; >+ >+ if (!harfbuzzCoreTextFontFuncs) { >+ harfbuzzCoreTextFontFuncs = hb_font_funcs_create(); >+ hb_font_funcs_set_glyph_func(harfbuzzCoreTextFontFuncs, getGlyph, 0, 0); >+ hb_font_funcs_set_glyph_h_advance_func(harfbuzzCoreTextFontFuncs, getGlyphHorizontalAdvance, 0, 0); >+ hb_font_funcs_set_glyph_h_origin_func(harfbuzzCoreTextFontFuncs, getGlyphHorizontalOrigin, 0, 0); >+ hb_font_funcs_set_glyph_extents_func(harfbuzzCoreTextFontFuncs, getGlyphExtents, 0, 0); >+ hb_font_funcs_make_immutable(harfbuzzCoreTextFontFuncs); >+ } >+ return harfbuzzCoreTextFontFuncs; >+} >+ >+static void releaseTableData(void* userData) >+{ >+ CFDataRef cfData = reinterpret_cast<CFDataRef>(userData); >+ CFRelease(cfData); >+} >+ >+static hb_blob_t* harfbuzzCoreTextGetTable(hb_face_t* face, hb_tag_t tag, void* userData) >+{ >+ FontPlatformData* platformData = reinterpret_cast<FontPlatformData*>(userData); >+ CTFontRef ctFont = platformData->ctFont(); >+ CFDataRef cfData = CTFontCopyTable(ctFont, tag, kCTFontTableOptionNoOptions); >+ if (!cfData) >+ return 0; >+ >+ const char* data = reinterpret_cast<const char*>(CFDataGetBytePtr(cfData)); >+ const size_t length = CFDataGetLength(cfData); >+ if (!data || !length) >+ return 0; >+ return hb_blob_create(data, length, HB_MEMORY_MODE_READONLY, reinterpret_cast<void*>(const_cast<__CFData*>(cfData)), releaseTableData); >+} >+ >+hb_face_t* HarfBuzzFace::createFace() >+{ >+ hb_face_t* face = hb_face_create_for_tables(harfbuzzCoreTextGetTable, m_platformData, 0); >+ ASSERT(face); >+ return face; >+} >+ >+hb_font_t* HarfBuzzFace::createFont() >+{ >+ hb_font_t* font = hb_font_create(m_face); >+ hb_font_set_funcs(font, harfbuzzCoreTextGetFontFuncs(), m_platformData, 0); >+ const float size = m_platformData->m_size; >+ hb_font_set_ppem(font, size, size); >+ const int scale = (1 << 16) * static_cast<int>(size); >+ hb_font_set_scale(font, scale, scale); >+ hb_font_make_immutable(font); >+ return font; >+} >+ >+GlyphBufferAdvance HarfBuzzShaper::createGlyphBufferAdvance(float width, float height) >+{ >+ return CGSizeMake(width, height); >+} >+ >+} // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..3eed897ba6a11a70f064729bd8923c5d79257736 >--- /dev/null >+++ b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp >@@ -0,0 +1,360 @@ >+/* >+ * Copyright (c) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "HarfBuzzShaper.h" >+ >+#include "Font.h" >+#include "SurrogatePairAwareTextIterator.h" >+#include "TextRun.h" >+#include "hb-icu.h" >+#include <unicode/normlzr.h> >+#include <unicode/uchar.h> >+#include <wtf/MathExtras.h> >+#include <wtf/Vector.h> >+#include <wtf/unicode/Unicode.h> >+ >+namespace WebCore { >+ >+static inline float harfbuzzPositionToFloat(hb_position_t value) >+{ >+ return static_cast<float>(value) / (1 << 16); >+} >+ >+HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(unsigned numCharacters, TextDirection direction, hb_buffer_t* harfbuzzBuffer) >+ : m_numCharacters(numCharacters) >+ , m_direction(direction) >+{ >+ m_numGlyphs = hb_buffer_get_length(harfbuzzBuffer); >+ m_glyphs.resize(m_numGlyphs); >+ m_advances.resize(m_numGlyphs); >+ m_offsets.resize(m_numGlyphs); >+ m_glyphToCharacterIndex.resize(m_numGlyphs); >+ m_logClusters.resize(m_numCharacters); >+ >+ hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(harfbuzzBuffer, 0); >+ for (unsigned i = 0; i < m_numGlyphs; ++i) >+ m_glyphToCharacterIndex[i] = infos[i].cluster; >+ >+ // Fill logical clusters >+ unsigned index = 0; >+ while (index < m_numGlyphs) { >+ unsigned nextIndex = index + 1; >+ while (nextIndex < m_numGlyphs && infos[index].cluster == infos[nextIndex].cluster) >+ ++nextIndex; >+ if (rtl()) { >+ int nextCluster = nextIndex < m_numGlyphs ? infos[nextIndex].cluster : -1; >+ for (int j = infos[index].cluster; j > nextCluster; --j) >+ m_logClusters[j] = index; >+ } else { >+ unsigned nextCluster = nextIndex < m_numGlyphs ? infos[nextIndex].cluster : m_numCharacters; >+ for (unsigned j = infos[index].cluster; j < nextCluster; ++j) >+ m_logClusters[j] = index; >+ } >+ index = nextIndex; >+ } >+} >+ >+void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float x, float y, float advance) >+{ >+ m_glyphs[index] = glyphId; >+ m_offsets[index].set(x, y); >+ m_advances[index] = advance; >+} >+ >+int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(int targetX) >+{ >+ ASSERT(static_cast<unsigned>(targetX) <= m_width); >+ int currentX = 0; >+ float prevAdvance = 0; >+ for (unsigned i = 0; i < m_numGlyphs; ++i) { >+ float currentAdvance = m_advances[i] / 2.0; >+ int nextX = currentX + roundf(prevAdvance + currentAdvance); >+ if (currentX <= targetX && targetX <= nextX) >+ return m_glyphToCharacterIndex[i] + (rtl() ? 1 : 0); >+ currentX = nextX; >+ prevAdvance = currentAdvance; >+ } >+ >+ return rtl() ? 0 : m_numCharacters; >+} >+ >+int HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset) >+{ >+ ASSERT(offset < m_numCharacters); >+ unsigned glyphIndex = m_logClusters[offset]; >+ ASSERT(glyphIndex < m_numGlyphs); >+ float position = m_offsets[glyphIndex].x(); >+ if (rtl()) >+ position += m_advances[glyphIndex]; >+ return roundf(position); >+} >+ >+HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run) >+ : HarfBuzzShaperBase(font, run) >+ , m_startIndexOfCurrentRun(0) >+ , m_numCharactersOfCurrentRun(0) >+ , m_harfbuzzBuffer(0) >+{ >+ setNormalizedBuffer(); >+ setFontFeatures(); >+} >+ >+HarfBuzzShaper::~HarfBuzzShaper() >+{ >+ if (m_harfbuzzBuffer) >+ hb_buffer_destroy(m_harfbuzzBuffer); >+} >+ >+void HarfBuzzShaper::setFontFeatures() >+{ >+ FontFeatureSettings* settings = m_font->fontDescription().featureSettings(); >+ if (!settings) >+ return; >+ >+ unsigned numFeatures = settings->size(); >+ m_features.resize(numFeatures); >+ for (unsigned i = 0; i < numFeatures; ++i) { >+ const UChar* tag = settings->at(i).tag().characters(); >+ m_features[i].tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); >+ m_features[i].value = settings->at(i).value(); >+ m_features[i].start = 0; >+ m_features[i].end = static_cast<unsigned>(-1); >+ } >+} >+ >+bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) >+{ >+ m_totalWidth = 0; >+ while (setupHarfBuzzRun()) { >+ if (!shapeHarfBuzzRun()) >+ return false; >+ setGlyphPositionsForHarfBuzzRun(glyphBuffer); >+ } >+ >+ if (!m_harfbuzzRuns.size()) >+ return false; >+ >+ return true; >+} >+ >+bool HarfBuzzShaper::setupHarfBuzzRun() >+{ >+ m_startIndexOfCurrentRun += m_numCharactersOfCurrentRun; >+ >+ // Iterate through the text to take the largest range that stays within >+ // a single font. >+ int endOfRunIndex = m_normalizedBufferLength - m_startIndexOfCurrentRun; >+ SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get() + m_startIndexOfCurrentRun, 0, endOfRunIndex, endOfRunIndex); >+ UChar32 character; >+ unsigned clusterLength = 0; >+ if (!iterator.consume(character, clusterLength)) >+ return false; >+ >+ m_currentFontData = m_font->glyphDataForCharacter(character, false).fontData; >+ UErrorCode errorCode = U_ZERO_ERROR; >+ UScriptCode currentScript = uscript_getScript(character, &errorCode); >+ if (U_FAILURE(errorCode)) >+ return false; >+ if (currentScript == USCRIPT_INHERITED) >+ currentScript = USCRIPT_COMMON; >+ for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) { >+ const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData; >+ if (nextFontData != m_currentFontData) >+ break; >+ UScriptCode nextScript = uscript_getScript(character, &errorCode); >+ if (U_FAILURE(errorCode)) >+ return false; >+ if (currentScript == nextScript || nextScript == USCRIPT_INHERITED || nextScript == USCRIPT_COMMON) >+ continue; >+ if (currentScript == USCRIPT_COMMON) >+ currentScript = nextScript; >+ else >+ break; >+ } >+ m_numCharactersOfCurrentRun = iterator.currentCharacter(); >+ >+ if (!m_harfbuzzBuffer) { >+ m_harfbuzzBuffer = hb_buffer_create(); >+ hb_buffer_set_unicode_funcs(m_harfbuzzBuffer, hb_icu_get_unicode_funcs()); >+ } else >+ hb_buffer_reset(m_harfbuzzBuffer); >+ hb_buffer_set_script(m_harfbuzzBuffer, hb_icu_script_to_script(currentScript)); >+ >+ // WebKit always sets direction to LTR during width calculation. >+ // We only set direction when direction is explicitly set to RTL so that >+ // preventng wrong width calculation. >+ if (m_run.rtl()) >+ hb_buffer_set_direction(m_harfbuzzBuffer, HB_DIRECTION_RTL); >+ >+ // Determine whether this run needs to be converted to small caps. >+ // nextScriptRun() will always send us a run of the same case, because a >+ // case change while in small-caps mode always results in different >+ // FontData, so we only need to check the first character's case. >+ if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[m_startIndexOfCurrentRun])) { >+ String upperText = String(m_normalizedBuffer.get() + m_startIndexOfCurrentRun, m_numCharactersOfCurrentRun); >+ upperText.makeUpper(); >+ m_currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData; >+ hb_buffer_add_utf16(m_harfbuzzBuffer, upperText.characters(), m_numCharactersOfCurrentRun, 0, m_numCharactersOfCurrentRun); >+ } else >+ hb_buffer_add_utf16(m_harfbuzzBuffer, m_normalizedBuffer.get() + m_startIndexOfCurrentRun, m_numCharactersOfCurrentRun, 0, m_numCharactersOfCurrentRun); >+ >+ return true; >+} >+ >+bool HarfBuzzShaper::shapeHarfBuzzRun() >+{ >+ FontPlatformData* platformData = const_cast<FontPlatformData*>(&m_currentFontData->platformData()); >+ HarfBuzzFace* face = platformData->harfbuzzFace(); >+ if (!face) >+ return false; >+ hb_font_t* harfbuzzFont = face->createFont(); >+ hb_shape(harfbuzzFont, m_harfbuzzBuffer, m_features.size() > 0 ? m_features.data() : 0, m_features.size()); >+ hb_font_destroy(harfbuzzFont); >+ m_harfbuzzRuns.append(HarfBuzzRun::create(m_numCharactersOfCurrentRun, m_run.direction(), m_harfbuzzBuffer)); >+ return true; >+} >+ >+void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(GlyphBuffer* glyphBuffer) >+{ >+ hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(m_harfbuzzBuffer, 0); >+ hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(m_harfbuzzBuffer, 0); >+ HarfBuzzRun* currentRun = m_harfbuzzRuns.last().get(); >+ >+ unsigned numGlyphs = currentRun->numGlyphs(); >+ float totalAdvance = 0; >+ float nextOffsetX = harfbuzzPositionToFloat(glyphPositions[0].x_offset); >+ float nextOffsetY = -harfbuzzPositionToFloat(glyphPositions[0].y_offset); >+ // HarfBuzz returns the shaping result in visual order. We need not to flip them for RTL. >+ for (size_t i = 0; i < numGlyphs; ++i) { >+ bool runEnd = i + 1 == numGlyphs; >+ uint16_t glyph = glyphInfos[i].codepoint; >+ float offsetX = nextOffsetX; >+ float offsetY = nextOffsetY; >+ float advance = harfbuzzPositionToFloat(glyphPositions[i].x_advance); >+ nextOffsetX = runEnd ? 0 : harfbuzzPositionToFloat(glyphPositions[i + 1].x_offset); >+ nextOffsetY = runEnd ? 0 : -harfbuzzPositionToFloat(glyphPositions[i + 1].y_offset); >+ >+ unsigned currentCharacterIndex = m_startIndexOfCurrentRun + glyphInfos[i].cluster; >+ bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster; >+ float spacing = isClusterEnd ? m_letterSpacing : 0; >+ >+ if (isClusterEnd && isWordEnd(currentCharacterIndex)) >+ spacing += determineWordBreakSpacing(); >+ >+ if (m_currentFontData->isZeroWidthSpaceGlyph(glyph)) { >+ currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); >+ if (glyphBuffer) >+ glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(0, 0)); >+ continue; >+ } >+ >+ advance += spacing; >+ currentRun->setGlyphAndPositions(i, glyph, totalAdvance + offsetX, offsetY, advance); >+ if (glyphBuffer) { >+ float glyphAdvanceX = advance + nextOffsetX - offsetX; >+ float glyphAdvanceY = nextOffsetY - offsetY; >+ glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); >+ } >+ >+ totalAdvance += advance; >+ } >+ currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); >+ m_totalWidth += currentRun->width(); >+} >+ >+int HarfBuzzShaper::offsetForPosition(float targetX) >+{ >+ int charactersSoFar = 0; >+ int currentX = 0; >+ >+ if (m_run.rtl()) { >+ charactersSoFar = m_normalizedBufferLength; >+ for (int i = m_harfbuzzRuns.size() - 1; i >= 0; --i) { >+ charactersSoFar -= m_harfbuzzRuns[i]->numCharacters(); >+ int nextX = currentX + m_harfbuzzRuns[i]->width(); >+ if (currentX <= targetX && targetX <= nextX) { >+ // The x value in question is within this script run. >+ const unsigned index = m_harfbuzzRuns[i]->characterIndexForXPosition(targetX - currentX); >+ return charactersSoFar + index; >+ } >+ currentX = nextX; >+ } >+ } else { >+ for (unsigned i = 0; i < m_harfbuzzRuns.size(); ++i) { >+ int nextX = currentX + m_harfbuzzRuns[i]->width(); >+ if (currentX <= targetX && targetX <= nextX) { >+ const unsigned index = m_harfbuzzRuns[i]->characterIndexForXPosition(targetX - currentX); >+ return charactersSoFar + index; >+ } >+ charactersSoFar += m_harfbuzzRuns[i]->numCharacters(); >+ currentX = nextX; >+ } >+ } >+ >+ return charactersSoFar; >+} >+ >+FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to) >+{ >+ int fromX = -1, toX = -1; >+ int currentX = 0; >+ // Iterate through the script runs in logical order, searching for the run covering the positions of interest. >+ for (unsigned i = 0; i < m_harfbuzzRuns.size(); ++i) { >+ int numCharacters = m_harfbuzzRuns[i]->numCharacters(); >+ if (fromX == -1 && from >= 0 && from < numCharacters) >+ fromX = m_harfbuzzRuns[i]->xPositionForOffset(from) + currentX; >+ else >+ from -= numCharacters; >+ >+ if (toX == -1 && to >= 0 && to < numCharacters) >+ toX = m_harfbuzzRuns[i]->xPositionForOffset(to) + currentX; >+ else >+ to -= numCharacters; >+ >+ if (fromX != -1 && toX != -1) >+ break; >+ currentX += m_harfbuzzRuns[i]->width(); >+ } >+ >+ // The position in question might be just after the text. >+ if (fromX == -1) >+ fromX = 0; >+ if (toX == -1) >+ toX = m_run.rtl() ? 0 : m_totalWidth; >+ >+ ASSERT(fromX != -1 && toX != -1); >+ >+ if (fromX < toX) >+ return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); >+ return FloatRect(point.x() + toX, point.y(), fromX - toX, height); >+} >+ >+} // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h >new file mode 100644 >index 0000000000000000000000000000000000000000..7beff5d72cdc54f8888d6c20aca1d6edb033231c >--- /dev/null >+++ b/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h >@@ -0,0 +1,112 @@ >+/* >+ * Copyright (C) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef HarfBuzzShaper_h >+#define HarfBuzzShaper_h >+ >+#include "FloatPoint.h" >+#include "GlyphBuffer.h" >+#include "HarfBuzzShaperBase.h" >+#include "TextRun.h" >+#include "hb.h" >+#include <wtf/HashSet.h> >+#include <wtf/OwnPtr.h> >+#include <wtf/PassOwnPtr.h> >+#include <wtf/Vector.h> >+ >+namespace WebCore { >+ >+class Font; >+class SimpleFontData; >+ >+class HarfBuzzShaper : public HarfBuzzShaperBase { >+public: >+ HarfBuzzShaper(const Font*, const TextRun&); >+ virtual ~HarfBuzzShaper(); >+ >+ bool shape(GlyphBuffer* = 0); >+ float totalWidth() { return m_totalWidth; } >+ int offsetForPosition(float targetX); >+ FloatRect selectionRect(const FloatPoint&, int height, int from, int to); >+ >+private: >+ class HarfBuzzRun { >+ public: >+ static PassOwnPtr<HarfBuzzRun> create(unsigned numCharacters, TextDirection direction, hb_buffer_t* buffer) >+ { >+ return adoptPtr(new HarfBuzzRun(numCharacters, direction, buffer)); >+ } >+ >+ void setGlyphAndPositions(unsigned index, uint16_t glyphId, float x, float y, float); >+ void setWidth(float width) { m_width = width; } >+ >+ int characterIndexForXPosition(int targetX); >+ int xPositionForOffset(unsigned offset); >+ >+ unsigned numCharacters() const { return m_numCharacters; } >+ unsigned numGlyphs() const { return m_numGlyphs; } >+ float width() { return m_width; } >+ >+ private: >+ HarfBuzzRun(unsigned numCharacters, TextDirection, hb_buffer_t*); >+ bool rtl() { return m_direction == RTL; } >+ >+ size_t m_numCharacters; >+ unsigned m_numGlyphs; >+ TextDirection m_direction; >+ Vector<uint16_t, 256> m_glyphs; >+ Vector<float, 256> m_advances; >+ Vector<FloatPoint, 256> m_offsets; >+ Vector<uint16_t, 256> m_logClusters; >+ Vector<uint16_t, 256> m_glyphToCharacterIndex; >+ float m_width; >+ }; >+ >+ void setFontFeatures(); >+ >+ bool setupHarfBuzzRun(); >+ bool shapeHarfBuzzRun(); >+ void setGlyphPositionsForHarfBuzzRun(GlyphBuffer*); >+ >+ GlyphBufferAdvance createGlyphBufferAdvance(float, float); >+ >+ Vector<hb_feature_t, 4> m_features; >+ unsigned m_startIndexOfCurrentRun; >+ unsigned m_numCharactersOfCurrentRun; >+ const SimpleFontData* m_currentFontData; >+ hb_buffer_t* m_harfbuzzBuffer; >+ Vector<OwnPtr<HarfBuzzRun>, 16> m_harfbuzzRuns; >+ >+ float m_totalWidth; >+}; >+ >+} // namespace WebCore >+ >+#endif // HarfBuzzShaper_h >diff --git a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp >index c3dda155a4f7fa5359d27d61ab5150fcc5a89fb8..a726dc34c2fae2df5fb6e3b4d26ae112145e3b12 100644 >--- a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp >+++ b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp >@@ -34,13 +34,32 @@ > #include "TextRun.h" > #include <wtf/MathExtras.h> > >+#if PLATFORM(CHROMIUM) >+#include "HarfBuzzShaper.h" >+#endif >+ > using namespace std; > > namespace WebCore { > >+#if PLATFORM(CHROMIUM) >+static bool preferHarfBuzz(const Font* font) >+{ >+ const FontDescription& description = font->fontDescription(); >+ return description.featureSettings() && description.featureSettings()->size() > 0; >+} >+#endif >+ > FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, > int from, int to) const > { >+#if PLATFORM(CHROMIUM) >+ if (preferHarfBuzz(this)) { >+ HarfBuzzShaper shaper(this, run); >+ if (shaper.shape()) >+ return shaper.selectionRect(point, h, from, to); >+ } >+#endif > ComplexTextController controller(this, run); > controller.advance(from); > float beforeWidth = controller.runWidthSoFar(); >@@ -82,6 +101,16 @@ float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int > > void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const > { >+#if PLATFORM(CHROMIUM) >+ if (preferHarfBuzz(this)) { >+ GlyphBuffer glyphBuffer; >+ HarfBuzzShaper shaper(this, run); >+ if (shaper.shape(&glyphBuffer)) { >+ drawGlyphBuffer(context, run, glyphBuffer, point); >+ return; >+ } >+ } >+#endif > // This glyph buffer holds our glyphs + advances + font data for each glyph. > GlyphBuffer glyphBuffer; > >@@ -109,6 +138,13 @@ void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextR > > float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const > { >+#if PLATFORM(CHROMIUM) >+ if (preferHarfBuzz(this)) { >+ HarfBuzzShaper shaper(this, run); >+ if (shaper.shape()) >+ return shaper.totalWidth(); >+ } >+#endif > ComplexTextController controller(this, run, true, fallbackFonts); > if (glyphOverflow) { > glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); >@@ -121,6 +157,13 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon > > int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool includePartialGlyphs) const > { >+#if PLATFORM(CHROMIUM) >+ if (preferHarfBuzz(this)) { >+ HarfBuzzShaper shaper(this, run); >+ if (shaper.shape()) >+ return shaper.offsetForPosition(x); >+ } >+#endif > ComplexTextController controller(this, run); > return controller.offsetForPosition(x, includePartialGlyphs); > } >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 7f1dd47ea10efa99e385348c10739a1110db1ab0..c5828b41cb09d3fceb390b789e1309fa2bb02d44 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2012-02-29 Kenichi Ishibashi <bashi@chromium.org> >+ >+ [Chromium] Implement font shaping with font-feature-settings on Mac >+ https://bugs.webkit.org/show_bug.cgi?id=69826 >+ >+ Added the expectation for sss3/font-feature-settings-rendering.html. >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * platform/chromium-mac/css3/font-feature-settings-rendering-expected.png: Added. >+ * platform/chromium-mac/css3/font-feature-settings-rendering-expected.txt: Added. >+ * platform/chromium/test_expectations.txt: Removed css3/font-feature-settings-rendering.html. >+ > 2012-02-29 Kentaro Hara <haraken@chromium.org> > > Unreviewed gardening. >diff --git a/LayoutTests/platform/chromium-mac/css3/font-feature-settings-rendering-expected.png b/LayoutTests/platform/chromium-mac/css3/font-feature-settings-rendering-expected.png >new file mode 100644 >index 0000000000000000000000000000000000000000..1482fb95439a18a5aa8bb243cac0ebacdb8f63eb >GIT binary patch >literal 14981 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 >Y+5L0h`+kK37K|}DYhgtC+xI{IFK5%EGynhq > >literal 0 >HcmV?d00001 > >diff --git a/LayoutTests/platform/chromium-mac/css3/font-feature-settings-rendering-expected.txt b/LayoutTests/platform/chromium-mac/css3/font-feature-settings-rendering-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..c7be0dfee84031e4ec87a57b52b24e415815055b >--- /dev/null >+++ b/LayoutTests/platform/chromium-mac/css3/font-feature-settings-rendering-expected.txt >@@ -0,0 +1,19 @@ >+layer at (0,0) size 800x600 >+ RenderView at (0,0) size 800x600 >+layer at (0,0) size 800x600 >+ RenderBlock {HTML} at (0,0) size 800x600 >+ RenderBody {BODY} at (8,8) size 784x584 >+ RenderBlock {P} at (0,0) size 784x36 >+ RenderText {#text} at (0,0) size 783x36 >+ text run at (0,0) width 243: "Test for font-feature-settings property. " >+ text run at (243,0) width 540: "The first word of the following three words should be displayed like \"WebKit\", while" >+ text run at (0,18) width 267: "others should be displayed as black boxes." >+ RenderBlock {DIV} at (0,52) size 784x17 >+ RenderText {#text} at (0,0) size 31x16 >+ text run at (0,0) width 31: "WebKit" >+ RenderBlock {DIV} at (0,69) size 784x17 >+ RenderText {#text} at (0,0) size 96x16 >+ text run at (0,0) width 96: "WebKit" >+ RenderBlock {DIV} at (0,86) size 784x17 >+ RenderText {#text} at (0,0) size 96x16 >+ text run at (0,0) width 96: "WebKit" >diff --git a/LayoutTests/platform/chromium/test_expectations.txt b/LayoutTests/platform/chromium/test_expectations.txt >index 5a21c07eeb0b4218f1019474a4a877237a4f39d9..4dec80f7fc4fdfc3c52f8ce116e39bd570297c6b 100644 >--- a/LayoutTests/platform/chromium/test_expectations.txt >+++ b/LayoutTests/platform/chromium/test_expectations.txt >@@ -3172,8 +3172,6 @@ BUGCR97716 : fast/clip/overflow-border-radius-combinations.html = IMAGE > // Caused by r92618 > BUGWK65874 : fast/js/preventExtensions.html = TEXT > >-BUGWK63796 MAC : css3/font-feature-settings-rendering.html = MISSING FAIL >- > BUGWK66417 WIN : fast/text/midword-break-before-surrogate-pair-2.html = IMAGE+TEXT > BUGWK66417 MAC : fast/text/midword-break-before-surrogate-pair-2.html = IMAGE > BUGWK66417 LINUX : fast/text/midword-break-before-surrogate-pair-2.html = IMAGE+TEXT TIMEOUT
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 69826
:
124271
|
124480
|
129617
|
130756
|
137568
|
145674
|
147183