Home | History | Annotate | Download | only in fonts
      1 /*
      2  * Copyright 2009, The Android Open Source Project
      3  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 
     29 #include "EmojiFont.h"
     30 #include "Font.h"
     31 #include "GlyphPageTreeNode.h"
     32 #include "HarfbuzzSkia.h"
     33 #include "SimpleFontData.h"
     34 #include "SkFontHost.h"
     35 #include "SkPaint.h"
     36 #include "SkTemplates.h"
     37 #include "SkUtils.h"
     38 #include "VerticalTextMap.h"
     39 
     40 
     41 using namespace android;
     42 
     43 namespace WebCore {
     44 
     45 #define NO_BREAK_SPACE_UNICHAR 0xA0
     46 
     47 static HB_Error substituteWithVerticalGlyphs(const FontPlatformData& platformData, uint16_t* glyphs, unsigned bufferLength)
     48 {
     49     HB_FaceRec_* hbFace = platformData.harfbuzzFace();
     50     if (!hbFace->gsub) {
     51         // if there is no GSUB table, treat it as not covered
     52         return static_cast<HB_Error>(0Xffff);
     53     }
     54 
     55     HB_Buffer buffer;
     56     hb_buffer_new(&buffer);
     57     for (unsigned i = 0; i < bufferLength; ++i)
     58         hb_buffer_add_glyph(buffer, glyphs[i], 0, i);
     59 
     60     HB_UShort scriptIndex;
     61     HB_UShort featureIndex;
     62 
     63     HB_Error error = HB_GSUB_Select_Script(hbFace->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &scriptIndex);
     64     if (error) {
     65         if (error != HB_Err_Not_Covered)
     66             return error;
     67         scriptIndex = HB_Script_Common;  // Set script to common script.
     68     }
     69 
     70     HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'e', 'r', 't'), scriptIndex, 0xffff, &featureIndex);
     71     HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
     72     HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'r', 't', '2'), scriptIndex, 0xffff, &featureIndex);
     73     HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
     74 
     75     error = HB_GSUB_Apply_String(hbFace->gsub, buffer);
     76     if (!error) {
     77         for (unsigned i = 0; i < bufferLength; ++i)
     78             glyphs[i] = static_cast<Glyph>(buffer->out_string[i].gindex);
     79     }
     80     return error;
     81 }
     82 
     83 static void convertToVerticalForms(UChar* src, UChar* dest, unsigned bufferLength) {
     84     for (unsigned i = 0; i < bufferLength; ++i) {
     85         dest[i] = VerticalTextMap::getVerticalForm(src[i]);
     86         if (!dest[i])
     87             dest[i] = src[i];
     88     }
     89 }
     90 
     91 bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
     92 {
     93     if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
     94         SkDebugf("%s last char is high-surrogate", __FUNCTION__);
     95         return false;
     96     }
     97 
     98     SkPaint paint;
     99     fontData->platformData().setupPaint(&paint);
    100     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    101 
    102     SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
    103     uint16_t* glyphs = glyphStorage.get();
    104     UChar *textBuffer = buffer;
    105     UChar vTextBuffer[bufferLength];
    106 
    107     if (fontData->platformData().orientation() == Vertical && !fontData->hasVerticalGlyphs()) {
    108         // Convert to vertical form if there is no vertical glyphs.
    109         convertToVerticalForms(buffer, vTextBuffer, bufferLength);
    110         textBuffer = vTextBuffer;
    111     }
    112 
    113     unsigned count = paint.textToGlyphs(textBuffer, bufferLength << 1, glyphs);
    114     if (count != length) {
    115         SkDebugf("%s count != length\n", __FUNCTION__);
    116         return false;
    117     }
    118 
    119     if (fontData->hasVerticalGlyphs()) {
    120         bool lookVariants = false;
    121         for (unsigned i = 0; i < bufferLength; ++i) {
    122             if (!Font::isCJKIdeograph(textBuffer[i])) {
    123                 lookVariants = true;
    124                 break;
    125             }
    126         }
    127         if (lookVariants) {
    128             if (substituteWithVerticalGlyphs(fontData->platformData(), glyphs, bufferLength)) {
    129                 // Convert text to vertical forms if substituteWithVerticalGlyphs() fails to access vert tables.
    130                 convertToVerticalForms(buffer, vTextBuffer, bufferLength);
    131                 textBuffer = vTextBuffer;
    132 
    133                 unsigned count = paint.textToGlyphs(textBuffer, bufferLength << 1, glyphs);
    134                 if (count != length) {
    135                     SkDebugf("%s count != length\n", __FUNCTION__);
    136                     return false;
    137                 }
    138             }
    139         }
    140     }
    141 
    142     unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
    143 
    144     // search for emoji. If we knew for sure that buffer was a contiguous range
    145     // of chars, we could quick-reject the range to avoid this loop (usually)
    146     if (EmojiFont::IsAvailable()) {
    147         const UChar* curr = textBuffer;
    148         for (unsigned i = 0; i < length; i++) {
    149             SkUnichar uni = SkUTF16_NextUnichar(&curr);
    150             uint16_t glyphID = glyphs[i];
    151             // only sniff if the normal font failed to recognize it
    152             if (!glyphID)
    153                 glyphID = EmojiFont::UnicharToGlyph(uni);
    154             setGlyphDataForIndex(offset + i, glyphID, fontData);
    155             allGlyphs |= glyphID;
    156         }
    157     } else {
    158         for (unsigned i = 0; i < length; i++) {
    159             uint16_t glyphID = glyphs[i];
    160             setGlyphDataForIndex(offset + i, glyphID, fontData);
    161             allGlyphs |= glyphID;
    162         }
    163     }
    164     return allGlyphs != 0;
    165 }
    166 
    167 }
    168