OSDN Git Service

Fallback handle if vertical glyphs are missing.
authorclaireho <chinglanho@gmail.com>
Tue, 11 Oct 2011 20:28:10 +0000 (13:28 -0700)
committerclaireho <chinglanho@gmail.com>
Wed, 12 Oct 2011 00:17:36 +0000 (17:17 -0700)
Bug 5094208 : browser VerticalWritingMode support.
Some punctuation has to change its glyph in vertical writing mode.
For example, dash in vertical text is a vertical bar. In
current Android system fonts and fallback fonts, none of them have the
substitute tables for vertical writing mode.  We call a conversion
function that converts the punctuation to the Unicode Vertical Form
(0xFE10 - 0xFE19) or to the closest glyphs as alternative when
vertical substitute tables are absent in fonts. Otherwise, we use
Harfbuzz to do the vertical glyph shapping.

Change-Id: If1d31bb72aaaba45ed50bbb75d6246cfa30e3428

Source/WebCore/Android.mk
Source/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
Source/WebCore/platform/graphics/android/VerticalTextMap.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/android/VerticalTextMap.h [new file with mode: 0644]

index 075dd71..7d08cc7 100644 (file)
@@ -680,6 +680,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
        platform/graphics/android/TiledTexture.cpp \
        platform/graphics/android/TransferQueue.cpp \
        platform/graphics/android/UpdateManager.cpp \
+       platform/graphics/android/VerticalTextMap.cpp \
        platform/graphics/android/VideoLayerAndroid.cpp \
        platform/graphics/android/VideoLayerManager.cpp \
        platform/graphics/android/ZoomManager.cpp \
index da9d99a..c5193b7 100644 (file)
 #include "SkPaint.h"
 #include "SkUtils.h"
 #include "SimpleFontData.h"
+#include "Font.h"
+#include "SkFontHost.h"
+#include "HarfbuzzSkia.h"
+#include "VerticalTextMap.h"
+
 
 using namespace android;
 
@@ -39,6 +44,36 @@ namespace WebCore {
 
 #define NO_BREAK_SPACE_UNICHAR  0xA0
 
+static int substituteWithVerticalGlyphs(const FontPlatformData& platformData, uint16_t* glyphs, unsigned bufferLength)
+{
+    HB_FaceRec_* hbFace = platformData.harfbuzzFace();
+    if (!hbFace->gsub) {
+        // if there is no GSUB table, treat it as not covered
+        return 0Xffff;
+    }
+
+    HB_Buffer buffer;
+    hb_buffer_new(&buffer);
+    for (unsigned i = 0; i < bufferLength; ++i)
+        hb_buffer_add_glyph(buffer, glyphs[i], 0, i);
+
+    HB_UShort scriptIndex;
+    HB_UShort featureIndex;
+
+    HB_GSUB_Select_Script(hbFace->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &scriptIndex);
+    HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'e', 'r', 't'), scriptIndex, 0xffff, &featureIndex);
+    HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
+    HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'r', 't', '2'), scriptIndex, 0xffff, &featureIndex);
+    HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
+
+    int error = HB_GSUB_Apply_String(hbFace->gsub, buffer);
+    if (!error) {
+        for (unsigned i = 0; i < bufferLength; ++i)
+            glyphs[i] = static_cast<Glyph>(buffer->out_string[i].gindex);
+    }
+    return error;
+}
+
 bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
 {
     if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
@@ -49,21 +84,47 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b
     SkPaint paint;
     fontData->platformData().setupPaint(&paint);
     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
-    
+
     SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
     uint16_t* glyphs = glyphStorage.get();
-    unsigned count = paint.textToGlyphs(buffer, bufferLength << 1, glyphs);
+    UChar *textBuffer = buffer;
+    UChar vTextBuffer[bufferLength];
+
+    if (fontData->platformData().orientation() == Vertical &&
+        !fontData->hasVerticalGlyphs()) {
+        // Convert to vertical form if there is no vertical glyphs.
+        for (unsigned i = 0; i < bufferLength; ++i) {
+            vTextBuffer[i] = VerticalTextMap::getVerticalForm(buffer[i]);
+            if (!vTextBuffer[i])
+                vTextBuffer[i] = buffer[i];
+        }
+        textBuffer = vTextBuffer;
+    }
+
+    unsigned count = paint.textToGlyphs(textBuffer, bufferLength << 1, glyphs);
     if (count != length) {
         SkDebugf("%s count != length\n", __FUNCTION__);
         return false;
     }
 
+    if (fontData->hasVerticalGlyphs()) {
+        bool lookVariants = false;
+        for (unsigned i = 0; i < bufferLength; ++i) {
+            if (!Font::isCJKIdeograph(textBuffer[i])) {
+                lookVariants = true;
+                continue;
+            }
+        }
+        if (lookVariants)
+            substituteWithVerticalGlyphs(fontData->platformData(), glyphs, bufferLength);
+    }
+
     unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
 
     // search for emoji. If we knew for sure that buffer was a contiguous range
     // of chars, we could quick-reject the range to avoid this loop (usually)
     if (EmojiFont::IsAvailable()) {
-        const UChar* curr = buffer;
+        const UChar* curr = textBuffer;
         for (unsigned i = 0; i < length; i++) {
             SkUnichar uni = SkUTF16_NextUnichar(&curr);
             uint16_t glyphID = glyphs[i];
diff --git a/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp b/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp
new file mode 100644 (file)
index 0000000..2bb008f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * 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.
+ *
+ * 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 "VerticalTextMap.h"
+
+#include <wtf/Forward.h>
+#include <wtf/MessageQueue.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+static const UChar vTextCnvTable[][2] = {
+    // TODO: uncomment mappings once we add glyphs for vertical forms.
+    // {0x0021, 0xfe15},  // exclamation mark
+    {0x0028, 0xfe35},  // left paren
+    {0x0029, 0xfe36},  // right paren
+    // {0x002c, 0xfe10},  // comma
+    {0x003a, 0xfe30},  // colon
+    {0x003b, 0x007c},  // hyphen
+    // {0x003f, 0xfe16},  // question mark
+    // {0x005b, 0xfe14},  // semicolon
+    {0x005d, 0xfe47},  // left square bracket
+    {0x005f, 0xfe48},  // right square bracket
+    {0x007b, 0xfe37},  // left curly bracket
+    {0x007d, 0xfe38},  // right curly bracket
+    {0x007e, 0x007c},  // tilde to vertical line
+    {0x2013, 0xfe32},  // en dash
+    {0x2014, 0xfe31},  // em dash
+    {0x2015, 0xfe31},  // horizontal bar
+    {0x2025, 0xfe30},  // two dot leader
+    // TODO: change the mapping 0x2026 -> 0xFE19 once Android has the glyph for 0xFE19.
+    {0x2026, 0xfe30},  // three dot leader
+    // {0x3001, 0xfe11},  // Ideographic comma
+    // {0x3002, 0xfe12},  // Ideographic full stop
+    {0x3008, 0xfe3f},  // left angle bracket
+    {0x3009, 0xfe40},  // right angle bracket
+    {0x300a, 0xfe3d},  // left double angle bracket
+    {0x300b, 0xfe3e},  // right double angle bracket
+    {0x300c, 0xfe41},  // left corner bracket
+    {0x300d, 0xfe42},  // right corner bracket
+    {0x300e, 0xfe43},  // left white corner bracket
+    {0x300f, 0xfe44},  // right white corner bracket
+    {0x3010, 0xfe3b},  // left black lenticular bracket
+    {0x3011, 0xfe3c},  // right black lenticular bracket
+    {0x3014, 0xfe39},  // left black lenticular bracket
+    {0x3015, 0xfe3a},  // right tortise shell bracket
+    // {0x3016, 0xfe17},  // left white lenticular bracket
+    // {0x3017, 0xfe18},  // right white lenticular bracket
+    // {0x3019, 0xfe19},  // horizontal ellipses
+    {0x30fc, 0x3021},  // prolonged sound
+    {0xfe4f, 0xfe34},  // wavy low line
+    {0xff08, 0xfe35},  // full width left paren
+    {0xff09, 0xfe36},  // full width right paren
+    {0xff3b, 0xfe47},  // full width left square bracket
+    {0xff3d, 0xfe48},  // full width right square bracket
+    {0xff5b, 0xfe37},  // full width left curly bracket
+    {0xff5d, 0xfe38},  // full width right curly bracket
+    // {0xff64, 0xfe11},  // halfwidth ideo comma
+    // {0xff61, 0xfe12},  // halfwidth ideo full stop
+};
+
+using namespace android;
+
+namespace WebCore {
+
+static WTF::Mutex m_verticalTextHashMapMutex;
+static HashMap<UChar, UChar>* verticalTextHashMap = 0;
+
+UChar VerticalTextMap::getVerticalForm(UChar c) {
+    {
+        MutexLocker lock(m_verticalTextHashMapMutex);
+        if (!verticalTextHashMap) {
+            // Lazy initialization.
+            verticalTextHashMap = new HashMap<UChar, UChar>;
+            for (size_t i = 0; i < WTF_ARRAY_LENGTH(vTextCnvTable); ++i)
+               verticalTextHashMap->set(vTextCnvTable[i][0], vTextCnvTable[i][1]);
+        }
+    }
+    return verticalTextHashMap->get(c);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/android/VerticalTextMap.h b/Source/WebCore/platform/graphics/android/VerticalTextMap.h
new file mode 100644 (file)
index 0000000..f614633
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * 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.
+ *
+ * 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 android_VerticalTextMap_DEFINED
+#define android_VerticalTextMap_DEFINED
+
+#include "config.h"
+#include "WebViewCore.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/HashMap.h>
+#include <wtf/unicode/CharacterNames.h>
+
+using namespace android;
+
+namespace WebCore {
+    class VerticalTextMap {
+    public:
+        // This function converts given char to its corresponding vertical form.
+        // Rerturns 0 if there is no vertical form.
+        static UChar getVerticalForm(UChar c);
+    };
+}
+
+#endif