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
41using namespace android;
42
43namespace WebCore {
44
45#define NO_BREAK_SPACE_UNICHAR 0xA0
46
47static int 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 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_GSUB_Select_Script(hbFace->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &scriptIndex);
64    HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'e', 'r', 't'), scriptIndex, 0xffff, &featureIndex);
65    HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
66    HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'r', 't', '2'), scriptIndex, 0xffff, &featureIndex);
67    HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1);
68
69    int error = HB_GSUB_Apply_String(hbFace->gsub, buffer);
70    if (!error) {
71        for (unsigned i = 0; i < bufferLength; ++i)
72            glyphs[i] = static_cast<Glyph>(buffer->out_string[i].gindex);
73    }
74    return error;
75}
76
77bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
78{
79    if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
80        SkDebugf("%s last char is high-surrogate", __FUNCTION__);
81        return false;
82    }
83
84    SkPaint paint;
85    fontData->platformData().setupPaint(&paint);
86    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
87
88    SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
89    uint16_t* glyphs = glyphStorage.get();
90    UChar *textBuffer = buffer;
91    UChar vTextBuffer[bufferLength];
92
93    if (fontData->platformData().orientation() == Vertical && !fontData->hasVerticalGlyphs()) {
94        // Convert to vertical form if there is no vertical glyphs.
95        for (unsigned i = 0; i < bufferLength; ++i) {
96            vTextBuffer[i] = VerticalTextMap::getVerticalForm(buffer[i]);
97            if (!vTextBuffer[i])
98                vTextBuffer[i] = buffer[i];
99        }
100        textBuffer = vTextBuffer;
101    }
102
103    unsigned count = paint.textToGlyphs(textBuffer, bufferLength << 1, glyphs);
104    if (count != length) {
105        SkDebugf("%s count != length\n", __FUNCTION__);
106        return false;
107    }
108
109    if (fontData->hasVerticalGlyphs()) {
110        bool lookVariants = false;
111        for (unsigned i = 0; i < bufferLength; ++i) {
112            if (!Font::isCJKIdeograph(textBuffer[i])) {
113                lookVariants = true;
114                continue;
115            }
116        }
117        if (lookVariants)
118            substituteWithVerticalGlyphs(fontData->platformData(), glyphs, bufferLength);
119    }
120
121    unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
122
123    // search for emoji. If we knew for sure that buffer was a contiguous range
124    // of chars, we could quick-reject the range to avoid this loop (usually)
125    if (EmojiFont::IsAvailable()) {
126        const UChar* curr = textBuffer;
127        for (unsigned i = 0; i < length; i++) {
128            SkUnichar uni = SkUTF16_NextUnichar(&curr);
129            uint16_t glyphID = glyphs[i];
130            // only sniff if the normal font failed to recognize it
131            if (!glyphID)
132                glyphID = EmojiFont::UnicharToGlyph(uni);
133            setGlyphDataForIndex(offset + i, glyphID, fontData);
134            allGlyphs |= glyphID;
135        }
136    } else {
137        for (unsigned i = 0; i < length; i++) {
138            uint16_t glyphID = glyphs[i];
139            setGlyphDataForIndex(offset + i, glyphID, fontData);
140            allGlyphs |= glyphID;
141        }
142    }
143    return allGlyphs != 0;
144}
145
146}
147