Vertical flow support for OpenType fonts with the least platform dependencies
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Mar 2012 03:44:14 +0000 (03:44 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Mar 2012 03:44:14 +0000 (03:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=81326

Patch by Koji Ishii <kojiishi@gmail.com> on 2012-03-29
Reviewed by Dan Bernstein.

This patch introduces a new class OpenTypeVerticalData to read
vertical font metrics from OpenType fonts.

Currently, WebKit relies on platform APIs to do the work. However,
some platforms such as Windows lack support for all the capabilities
WebKit requires for vertical flow and the text-orientation property
to work correctly. Reading OpenType tables directly also gives
benefits in consistent behavior among the WebKit platforms.

This patch is for any platforms that want to parse OpenType tables
directly, but it's currently included only in CGWin and isn't on any
code path even on CGWin yet. Caller's side change for CGWin and
support for other platforms will be in separate bugs.

No new tests are required. No behavior changes.

* WebCore.vcproj/WebCore.vcproj: Added OpenTypeTypes.h and OpenTypeVerticalData.h/cpp.
* platform/SharedBuffer.cpp: Add create(size_t)
(WebCore::SharedBuffer::SharedBuffer):
(WebCore):
* platform/SharedBuffer.h: Add create(size_t)
(WebCore::SharedBuffer::create):
(SharedBuffer):
* platform/graphics/FontPlatformData.h: Added openTypeTable().
(WebCore):
(FontPlatformData):
* platform/graphics/SimpleFontData.h: Added sizePerUnit().
(WebCore::SimpleFontData::sizePerUnit): size() / unitsPerEm() for less multiplication.
* platform/graphics/opentype/OpenTypeTypes.h: Added OpenType basic type definitions.
(OpenType):
(WebCore::OpenType::BigEndianShort::operator short):
(WebCore::OpenType::BigEndianShort::BigEndianShort):
(BigEndianShort):
(WebCore::OpenType::BigEndianUShort::operator unsigned short):
(WebCore::OpenType::BigEndianUShort::BigEndianUShort):
(BigEndianUShort):
(WebCore::OpenType::BigEndianLong::operator int):
(WebCore::OpenType::BigEndianLong::BigEndianLong):
(BigEndianLong):
(WebCore::OpenType::BigEndianULong::operator unsigned):
(WebCore::OpenType::BigEndianULong::BigEndianULong):
(BigEndianULong):
* platform/graphics/opentype/OpenTypeVerticalData.cpp: Added.
(OpenType):
(HheaTable):
(VheaTable):
(Entry):
(VORGTable):
(VertOriginYMetrics):
(WebCore::OpenType::VORGTable::requiredSize):
(WebCore):
(WebCore::validatedPtr):
(WebCore::OpenTypeVerticalData::OpenTypeVerticalData):
(WebCore::OpenTypeVerticalData::advanceHeight): Advance height for a glyph.
(WebCore::OpenTypeVerticalData::getVerticalTranslationsForGlyphs): Vertical origin.
* platform/graphics/opentype/OpenTypeVerticalData.h: Added.
(WebCore):
(OpenTypeVerticalData): A new class to handle vertical flow data in OpenType.
(WebCore::OpenTypeVerticalData::isOpenType):
(WebCore::OpenTypeVerticalData::hasVerticalMetrics):
(WebCore::OpenTypeVerticalData::hasVORG):
* platform/graphics/win/FontPlatformDataWin.cpp:
(WebCore):
(WebCore::FontPlatformData::openTypeTable): Implemented openTypeTable() for Win32.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@112642 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/platform/SharedBuffer.cpp
Source/WebCore/platform/SharedBuffer.h
Source/WebCore/platform/graphics/FontPlatformData.h
Source/WebCore/platform/graphics/SimpleFontData.h
Source/WebCore/platform/graphics/opentype/OpenTypeTypes.h [new file with mode: 0644]
Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.h [new file with mode: 0644]
Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp

index abe2332..b9405d2 100644 (file)
@@ -1,3 +1,76 @@
+2012-03-29  Koji Ishii  <kojiishi@gmail.com>
+
+
+        Vertical flow support for OpenType fonts with the least platform dependencies
+        https://bugs.webkit.org/show_bug.cgi?id=81326
+
+        Reviewed by Dan Bernstein.
+
+        This patch introduces a new class OpenTypeVerticalData to read
+        vertical font metrics from OpenType fonts.
+
+        Currently, WebKit relies on platform APIs to do the work. However,
+        some platforms such as Windows lack support for all the capabilities
+        WebKit requires for vertical flow and the text-orientation property
+        to work correctly. Reading OpenType tables directly also gives
+        benefits in consistent behavior among the WebKit platforms.
+
+        This patch is for any platforms that want to parse OpenType tables
+        directly, but it's currently included only in CGWin and isn't on any
+        code path even on CGWin yet. Caller's side change for CGWin and
+        support for other platforms will be in separate bugs.
+
+        No new tests are required. No behavior changes.
+
+        * WebCore.vcproj/WebCore.vcproj: Added OpenTypeTypes.h and OpenTypeVerticalData.h/cpp.
+        * platform/SharedBuffer.cpp: Add create(size_t)
+        (WebCore::SharedBuffer::SharedBuffer):
+        (WebCore):
+        * platform/SharedBuffer.h: Add create(size_t)
+        (WebCore::SharedBuffer::create):
+        (SharedBuffer):
+        * platform/graphics/FontPlatformData.h: Added openTypeTable().
+        (WebCore):
+        (FontPlatformData):
+        * platform/graphics/SimpleFontData.h: Added sizePerUnit().
+        (WebCore::SimpleFontData::sizePerUnit): size() / unitsPerEm() for less multiplication.
+        * platform/graphics/opentype/OpenTypeTypes.h: Added OpenType basic type definitions.
+        (OpenType):
+        (WebCore::OpenType::BigEndianShort::operator short):
+        (WebCore::OpenType::BigEndianShort::BigEndianShort):
+        (BigEndianShort):
+        (WebCore::OpenType::BigEndianUShort::operator unsigned short):
+        (WebCore::OpenType::BigEndianUShort::BigEndianUShort):
+        (BigEndianUShort):
+        (WebCore::OpenType::BigEndianLong::operator int):
+        (WebCore::OpenType::BigEndianLong::BigEndianLong):
+        (BigEndianLong):
+        (WebCore::OpenType::BigEndianULong::operator unsigned):
+        (WebCore::OpenType::BigEndianULong::BigEndianULong):
+        (BigEndianULong):
+        * platform/graphics/opentype/OpenTypeVerticalData.cpp: Added.
+        (OpenType):
+        (HheaTable):
+        (VheaTable):
+        (Entry):
+        (VORGTable):
+        (VertOriginYMetrics):
+        (WebCore::OpenType::VORGTable::requiredSize):
+        (WebCore):
+        (WebCore::validatedPtr):
+        (WebCore::OpenTypeVerticalData::OpenTypeVerticalData):
+        (WebCore::OpenTypeVerticalData::advanceHeight): Advance height for a glyph.
+        (WebCore::OpenTypeVerticalData::getVerticalTranslationsForGlyphs): Vertical origin.
+        * platform/graphics/opentype/OpenTypeVerticalData.h: Added.
+        (WebCore):
+        (OpenTypeVerticalData): A new class to handle vertical flow data in OpenType.
+        (WebCore::OpenTypeVerticalData::isOpenType):
+        (WebCore::OpenTypeVerticalData::hasVerticalMetrics):
+        (WebCore::OpenTypeVerticalData::hasVORG):
+        * platform/graphics/win/FontPlatformDataWin.cpp:
+        (WebCore):
+        (WebCore::FontPlatformData::openTypeTable): Implemented openTypeTable() for Win32.
+
 2012-03-29  Leo Yang  <leo.yang@torchmobile.com.cn>
 
         [BlackBerry] Sync up PlatformMouseEvent
index 5e1ddfa..88d88cc 100755 (executable)
                                                >
                                        </File>
                                        <File
+                                               RelativePath="..\platform\graphics\opentype\OpenTypeTypes.h"
+                                               >
+                                       </File>
+                                       <File
                                                RelativePath="..\platform\graphics\opentype\OpenTypeUtilities.cpp"
                                                >
                                        </File>
                                                >
                                        </File>
                                        <File
+                                               RelativePath="..\platform\graphics\opentype\OpenTypeVerticalData.cpp"
+                                               >
+                                       </File>
+                                       <File
+                                               RelativePath="..\platform\graphics\opentype\OpenTypeVerticalData.h"
+                                               >
+                                       </File>
+                                       <File
                                                RelativePath="..\platform\graphics\win\RefCountedGDIHandle.h"
                                                >
                                        </File>
index ee6a29f..82efab7 100644 (file)
@@ -62,6 +62,12 @@ SharedBuffer::SharedBuffer()
 {
 }
 
+SharedBuffer::SharedBuffer(size_t size)
+    : m_size(size)
+    , m_buffer(size)
+{
+}
+
 SharedBuffer::SharedBuffer(const char* data, int size)
     : m_size(0)
 {
index fe3e4b6..b66a033 100644 (file)
@@ -48,6 +48,7 @@ class PurgeableBuffer;
 class SharedBuffer : public RefCounted<SharedBuffer> {
 public:
     static PassRefPtr<SharedBuffer> create() { return adoptRef(new SharedBuffer); }
+    static PassRefPtr<SharedBuffer> create(size_t size) { return adoptRef(new SharedBuffer(size)); }
     static PassRefPtr<SharedBuffer> create(const char* c, int i) { return adoptRef(new SharedBuffer(c, i)); }
     static PassRefPtr<SharedBuffer> create(const unsigned char* c, int i) { return adoptRef(new SharedBuffer(c, i)); }
 
@@ -115,6 +116,7 @@ public:
 
 private:
     SharedBuffer();
+    SharedBuffer(size_t);
     SharedBuffer(const char*, int);
     SharedBuffer(const unsigned char*, int);
     
index c730c74..ea54307 100644 (file)
@@ -91,6 +91,7 @@ typedef UInt32 ATSFontRef;
 namespace WebCore {
 
 class FontDescription;
+class SharedBuffer;
 
 #if OS(DARWIN)
 inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); }
@@ -276,6 +277,9 @@ public:
 #endif
     }
 
+#if PLATFORM(WIN) && USE(CG)
+    PassRefPtr<SharedBuffer> openTypeTable(uint32_t table) const;
+#endif
 
 #ifndef NDEBUG
     String description() const;
index dd86f00..fd2ffcb 100644 (file)
@@ -118,6 +118,7 @@ public:
 
     FontMetrics& fontMetrics() { return m_fontMetrics; }
     const FontMetrics& fontMetrics() const { return m_fontMetrics; }
+    float sizePerUnit() const { return platformData().size() / (fontMetrics().unitsPerEm() ? fontMetrics().unitsPerEm() : 1); }
     
     float maxCharWidth() const { return m_maxCharWidth; }
     void setMaxCharWidth(float maxCharWidth) { m_maxCharWidth = maxCharWidth; }
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeTypes.h b/Source/WebCore/platform/graphics/opentype/OpenTypeTypes.h
new file mode 100644 (file)
index 0000000..9fc7659
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Koji Ishii <kojiishi@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 OpenTypeTypes_h
+#define OpenTypeTypes_h
+
+namespace WebCore {
+namespace OpenType {
+
+struct BigEndianShort {
+    operator short() const { return (v & 0x00ff) << 8 | v >> 8; }
+    BigEndianShort(short u) : v((u & 0x00ff) << 8 | u >> 8) { }
+    unsigned short v;
+};
+
+struct BigEndianUShort {
+    operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
+    BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
+    unsigned short v;
+};
+
+struct BigEndianLong {
+    operator int() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
+    BigEndianLong(int u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
+    unsigned v;
+};
+
+struct BigEndianULong {
+    operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
+    BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
+    unsigned v;
+};
+
+typedef BigEndianShort Int16;
+typedef BigEndianUShort UInt16;
+typedef BigEndianLong Int32;
+typedef BigEndianULong UInt32;
+
+typedef UInt32 Fixed;
+typedef UInt16 Offset;
+typedef UInt16 GlyphID;
+
+// OTTag is native because it's only compared against constants, so we don't
+// do endian conversion here but make sure constants are in big-endian order.
+// Note that multi-character literal is implementation-defined in C++0x.
+typedef uint32_t Tag;
+#define OT_MAKE_TAG(ch1, ch2, ch3, ch4) ((((uint32_t)(ch4)) << 24) | (((uint32_t)(ch3)) << 16) | (((uint32_t)(ch2)) << 8) | ((uint32_t)(ch1)))
+
+} // namespace OpenType
+} // namespace WebCore
+
+#endif // OpenTypeTypes_h
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp b/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp
new file mode 100644 (file)
index 0000000..78ebcf8
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2012 Koji Ishii <kojiishi@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "OpenTypeVerticalData.h"
+
+#include "FloatRect.h"
+#include "GlyphPage.h"
+#include "OpenTypeTypes.h"
+#include "SharedBuffer.h"
+#include "SimpleFontData.h"
+#include <wtf/RefPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+namespace OpenType {
+
+enum {
+    HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a'),
+    HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x'),
+    VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a'),
+    VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x'),
+    VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G'),
+};
+
+#pragma pack(1)
+
+struct HheaTable {
+    OpenType::Fixed version;
+    OpenType::Int16 ascender;
+    OpenType::Int16 descender;
+    OpenType::Int16 lineGap;
+    OpenType::Int16 advanceWidthMax;
+    OpenType::Int16 minLeftSideBearing;
+    OpenType::Int16 minRightSideBearing;
+    OpenType::Int16 xMaxExtent;
+    OpenType::Int16 caretSlopeRise;
+    OpenType::Int16 caretSlopeRun;
+    OpenType::Int16 caretOffset;
+    OpenType::Int16 reserved[4];
+    OpenType::Int16 metricDataFormat;
+    OpenType::UInt16 numberOfHMetrics;
+};
+
+struct VheaTable {
+    OpenType::Fixed version;
+    OpenType::Int16 ascent;
+    OpenType::Int16 descent;
+    OpenType::Int16 lineGap;
+    OpenType::Int16 advanceHeightMax;
+    OpenType::Int16 minTopSideBearing;
+    OpenType::Int16 minBottomSideBearing;
+    OpenType::Int16 yMaxExtent;
+    OpenType::Int16 caretSlopeRise;
+    OpenType::Int16 caretSlopeRun;
+    OpenType::Int16 caretOffset;
+    OpenType::Int16 reserved[4];
+    OpenType::Int16 metricDataFormat;
+    OpenType::UInt16 numOfLongVerMetrics;
+};
+
+struct HmtxTable {
+    struct Entry {
+        OpenType::UInt16 advanceWidth;
+        OpenType::Int16 lsb;
+    } entries[1];
+};
+
+struct VmtxTable {
+    struct Entry {
+        OpenType::UInt16 advanceHeight;
+        OpenType::Int16 topSideBearing;
+    } entries[1];
+};
+
+struct VORGTable {
+    OpenType::UInt16 majorVersion;
+    OpenType::UInt16 minorVersion;
+    OpenType::Int16 defaultVertOriginY;
+    OpenType::UInt16 numVertOriginYMetrics;
+    struct VertOriginYMetrics {
+        OpenType::UInt16 glyphIndex;
+        OpenType::Int16 vertOriginY;
+    } vertOriginYMetrics[1];
+
+    size_t requiredSize() const { return sizeof(*this) + sizeof(VertOriginYMetrics) * (numVertOriginYMetrics - 1); }
+};
+
+#pragma pack()
+
+} // namespace OpenType
+
+template <typename T> const T* validatedPtr(const RefPtr<SharedBuffer>& buffer, size_t count = 1)
+{
+    if (!buffer || buffer->size() < sizeof(T) * count)
+        return 0;
+    return reinterpret_cast<const T*>(buffer->data());
+}
+
+OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
+    : m_defaultVertOriginY(0)
+{
+    // Load hhea and hmtx to get x-component of vertical origins.
+    // If these tables are missing, it's not an OpenType font.
+    RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag);
+    const OpenType::HheaTable* hhea = validatedPtr<OpenType::HheaTable>(buffer);
+    if (!hhea)
+        return;
+    uint16_t countHmtxEntries = hhea->numberOfHMetrics;
+    if (!countHmtxEntries) {
+        LOG_ERROR("Invalid numberOfHMetrics");
+        return;
+    }
+
+    buffer = platformData.openTypeTable(OpenType::HmtxTag);
+    const OpenType::HmtxTable* hmtx = validatedPtr<OpenType::HmtxTable>(buffer, countHmtxEntries);
+    if (!hmtx) {
+        LOG_ERROR("hhea exists but hmtx does not (or broken)");
+        return;
+    }
+    m_advanceWidths.resize(countHmtxEntries);
+    for (uint16_t i = 0; i < countHmtxEntries; ++i)
+        m_advanceWidths[i] = hmtx->entries[i].advanceWidth;
+
+    // Load vhea first. This table is required for fonts that support vertical flow.
+    buffer = platformData.openTypeTable(OpenType::VheaTag);
+    const OpenType::VheaTable* vhea = validatedPtr<OpenType::VheaTable>(buffer);
+    if (!vhea)
+        return;
+    uint16_t countVmtxEntries = vhea->numOfLongVerMetrics;
+    if (!countVmtxEntries) {
+        LOG_ERROR("Invalid numOfLongVerMetrics");
+        return;
+    }
+
+    // Load VORG. This table is optional.
+    buffer = platformData.openTypeTable(OpenType::VORGTag);
+    const OpenType::VORGTable* vorg = validatedPtr<OpenType::VORGTable>(buffer);
+    if (vorg && buffer->size() >= vorg->requiredSize()) {
+        m_defaultVertOriginY = vorg->defaultVertOriginY;
+        uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics;
+        if (!countVertOriginYMetrics) {
+            // Add one entry so that hasVORG() becomes true
+            m_vertOriginY.set(0, m_defaultVertOriginY);
+        } else {
+            for (uint16_t i = 0; i < countVertOriginYMetrics; ++i) {
+                const OpenType::VORGTable::VertOriginYMetrics& metrics = vorg->vertOriginYMetrics[i];
+                m_vertOriginY.set(metrics.glyphIndex, metrics.vertOriginY);
+            }
+        }
+    }
+
+    // Load vmtx then. This table is required for fonts that support vertical flow.
+    buffer = platformData.openTypeTable(OpenType::VmtxTag);
+    const OpenType::VmtxTable* vmtx = validatedPtr<OpenType::VmtxTable>(buffer, countVmtxEntries);
+    if (!vmtx) {
+        LOG_ERROR("vhea exists but vmtx does not (or broken)");
+        return;
+    }
+    m_advanceHeights.resize(countVmtxEntries);
+    for (uint16_t i = 0; i < countVmtxEntries; ++i)
+        m_advanceHeights[i] = vmtx->entries[i].advanceHeight;
+
+    // VORG is preferred way to calculate vertical origin than vmtx,
+    // so load topSideBearing from vmtx only if VORG is missing.
+    if (hasVORG())
+        return;
+
+    size_t sizeExtra = buffer->size() - sizeof(OpenType::VmtxTable::Entry) * countVmtxEntries;
+    if (sizeExtra % sizeof(OpenType::Int16)) {
+        LOG_ERROR("vmtx has incorrect tsb count");
+        return;
+    }
+    size_t countTopSideBearings = countVmtxEntries + sizeExtra / sizeof(OpenType::Int16);
+    m_topSideBearings.resize(countTopSideBearings);
+    size_t i;
+    for (i = 0; i < countVmtxEntries; ++i)
+        m_topSideBearings[i] = vmtx->entries[i].topSideBearing;
+    if (i < countTopSideBearings) {
+        const OpenType::Int16* pTopSideBearingsExtra = reinterpret_cast<const OpenType::Int16*>(&vmtx->entries[countVmtxEntries]);
+        for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra)
+            m_topSideBearings[i] = *pTopSideBearingsExtra;
+    }
+}
+
+float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyph) const
+{
+    size_t countHeights = m_advanceHeights.size();
+    if (countHeights) {
+        uint16_t advanceFUnit = m_advanceHeights[glyph < countHeights ? glyph : countHeights - 1];
+        float advance = advanceFUnit * font->sizePerUnit();
+        return advance;
+    }
+
+    // No vertical info in the font file; use height as advance.
+    return font->fontMetrics().height();
+}
+
+void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(const SimpleFontData* font, const Glyph* glyphs, size_t count, float* outXYArray) const
+{
+    size_t countWidths = m_advanceWidths.size();
+    ASSERT(countWidths > 0);
+    const FontMetrics& metrics = font->fontMetrics();
+    float sizePerUnit = font->sizePerUnit();
+    float ascent = metrics.ascent();
+    bool useVORG = hasVORG();
+    size_t countTopSideBearings = m_topSideBearings.size();
+    float defaultVertOriginY = std::numeric_limits<float>::quiet_NaN();
+    for (float* end = &(outXYArray[count * 2]); outXYArray != end; ++glyphs, outXYArray += 2) {
+        Glyph glyph = *glyphs;
+        uint16_t widthFUnit = m_advanceWidths[glyph < countWidths ? glyph : countWidths - 1];
+        float width = widthFUnit * sizePerUnit;
+        outXYArray[0] = -width / 2;
+
+        // For Y, try VORG first.
+        if (useVORG) {
+            int16_t vertOriginYFUnit = m_vertOriginY.get(glyph);
+            if (vertOriginYFUnit) {
+                outXYArray[1] = -vertOriginYFUnit * sizePerUnit;
+                continue;
+            }
+            if (isnan(defaultVertOriginY))
+                defaultVertOriginY = -m_defaultVertOriginY * sizePerUnit;
+            outXYArray[1] = defaultVertOriginY;
+            continue;
+        }
+
+        // If no VORG, try vmtx next.
+        if (countTopSideBearings) {
+            int16_t topSideBearingFUnit = m_topSideBearings[glyph < countTopSideBearings ? glyph : countTopSideBearings - 1];
+            float topSideBearing = topSideBearingFUnit * sizePerUnit;
+            FloatRect bounds = font->boundsForGlyph(glyph);
+            outXYArray[1] = bounds.y() - topSideBearing;
+            continue;
+        }
+
+        // No vertical info in the font file; use ascent as vertical origin.
+        outXYArray[1] = -ascent;
+    }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.h b/Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.h
new file mode 100644 (file)
index 0000000..85e4ee7
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 Koji Ishii <kojiishi@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 OpenTypeVerticalData_h
+#define OpenTypeVerticalData_h
+
+#include "Glyph.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class GlyphPage;
+class SimpleFontData;
+
+class OpenTypeVerticalData {
+public:
+    OpenTypeVerticalData(const FontPlatformData&);
+
+    bool isOpenType() const { return !m_advanceWidths.isEmpty(); }
+    bool hasVerticalMetrics() const { return !m_advanceHeights.isEmpty(); }
+    float advanceHeight(const SimpleFontData*, Glyph) const;
+    void getVerticalTranslationsForGlyphs(const SimpleFontData*, const Glyph*, size_t, float* outXYArray) const;
+
+private:
+    bool hasVORG() const { return !m_vertOriginY.isEmpty(); }
+
+    Vector<uint16_t> m_advanceWidths;
+    Vector<uint16_t> m_advanceHeights;
+    Vector<int16_t> m_topSideBearings;
+    int16_t m_defaultVertOriginY;
+    HashMap<Glyph, int16_t> m_vertOriginY;
+};
+
+} // namespace WebCore
+
+#endif // OpenTypeVerticalData_h
index 9860df6..1081de9 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "HWndDC.h"
 #include "PlatformString.h"
+#include "SharedBuffer.h"
 #include <wtf/HashMap.h>
 #include <wtf/RetainPtr.h>
 #include <wtf/Vector.h>
@@ -74,6 +75,25 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
     RestoreDC(hdc, -1);
 }
 
+#if USE(CG)
+PassRefPtr<SharedBuffer> FontPlatformData::openTypeTable(uint32_t table) const
+{
+    HWndDC hdc(0);
+    HGDIOBJ oldFont = SelectObject(hdc, hfont());
+
+    DWORD size = GetFontData(hdc, table, 0, 0, 0);
+    RefPtr<SharedBuffer> buffer;
+    if (size != GDI_ERROR) {
+        buffer = SharedBuffer::create(size);
+        DWORD result = GetFontData(hdc, table, 0, (PVOID)buffer->data(), size);
+        ASSERT(result == size);
+    }
+
+    SelectObject(hdc, oldFont);
+    return buffer.release();
+}
+#endif
+
 #ifndef NDEBUG
 String FontPlatformData::description() const
 {