06b27dfbd23602cf2f8bb1c82f89423d049ca427
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / SVGGlyph.cpp
1 /*
2  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(SVG_FONTS)
24 #include "platform/fonts/SVGGlyph.h"
25
26 #include "wtf/unicode/Unicode.h"
27
28 using namespace WTF::Unicode;
29
30 namespace WebCore {
31
32 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated)
33 enum ArabicCharShapingMode {
34     SNone = 0,
35     SRight = 1,
36     SDual = 2
37 };
38
39 static const ArabicCharShapingMode s_arabicCharShapingMode[222] = {
40     SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, SDual , SDual , SDual , SDual , SDual , SRight,                 /* 0x0622 - 0x062F */
41     SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */
42     SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */
43     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */
44     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */
45     SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */
46     SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */
47     SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */
48     SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */
49     SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */
50     SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */
51     SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */
52     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */
53     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone   /* 0x06F0 - 0x06FF */
54 };
55
56 static inline SVGGlyph::ArabicForm processArabicFormDetection(const UChar& curChar, bool& lastCharShapesRight, SVGGlyph::ArabicForm* prevForm)
57 {
58     SVGGlyph::ArabicForm curForm;
59
60     ArabicCharShapingMode shapingMode = SNone;
61     if (curChar >= 0x0622 && curChar <= 0x06FF)
62         shapingMode = s_arabicCharShapingMode[curChar - 0x0622];
63
64     // Use a simple state machine to identify the actual arabic form
65     // It depends on the order of the arabic form enum:
66     // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial };
67
68     if (lastCharShapesRight && shapingMode == SDual) {
69         if (prevForm) {
70             int correctedForm = (int) *prevForm + 1;
71             ASSERT(correctedForm >= SVGGlyph::None && correctedForm <= SVGGlyph::Medial);
72             *prevForm = static_cast<SVGGlyph::ArabicForm>(correctedForm);
73         }
74
75         curForm = SVGGlyph::Initial;
76     } else
77         curForm = shapingMode == SNone ? SVGGlyph::None : SVGGlyph::Isolated;
78
79     lastCharShapesRight = shapingMode != SNone;
80     return curForm;
81 }
82
83 Vector<SVGGlyph::ArabicForm> charactersWithArabicForm(const String& input, bool rtl)
84 {
85     Vector<SVGGlyph::ArabicForm> forms;
86     unsigned length = input.length();
87
88     bool containsArabic = false;
89     for (unsigned i = 0; i < length; ++i) {
90         if (isArabicChar(input[i])) {
91             containsArabic = true;
92             break;
93         }
94     }
95
96     if (!containsArabic)
97         return forms;
98
99     bool lastCharShapesRight = false;
100
101     // Start identifying arabic forms
102     if (rtl) {
103         for (int i = length - 1; i >= 0; --i)
104             forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first()));
105     } else {
106         for (unsigned i = 0; i < length; ++i)
107             forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last()));
108     }
109
110     return forms;
111 }
112
113 static inline bool isCompatibleArabicForm(const SVGGlyph& identifier, const Vector<SVGGlyph::ArabicForm>& chars, unsigned startPosition, unsigned endPosition)
114 {
115     if (chars.isEmpty())
116         return true;
117
118     Vector<SVGGlyph::ArabicForm>::const_iterator realEnd = chars.end();
119     Vector<SVGGlyph::ArabicForm>::const_iterator it = chars.begin() + startPosition;
120     if (it >= realEnd)
121         return true;
122
123     Vector<SVGGlyph::ArabicForm>::const_iterator end = chars.begin() + endPosition;
124     if (end >= realEnd)
125         end = realEnd;
126
127     for (; it != end; ++it) {
128         if (*it != static_cast<SVGGlyph::ArabicForm>(identifier.arabicForm) && *it != SVGGlyph::None)
129             return false;
130     }
131
132     return true;
133 }
134
135 bool isCompatibleGlyph(const SVGGlyph& identifier, bool isVerticalText, const String& language,
136                        const Vector<SVGGlyph::ArabicForm>& chars, unsigned startPosition, unsigned endPosition)
137 {
138     bool valid = true;
139
140     // Check wheter orientation if glyph fits within the request
141     switch (identifier.orientation) {
142     case SVGGlyph::Vertical:
143         valid = isVerticalText;
144         break;
145     case SVGGlyph::Horizontal:
146         valid = !isVerticalText;
147         break;
148     case SVGGlyph::Both:
149         break;
150     }
151
152     if (!valid)
153         return false;
154
155     // Check wheter languages are compatible
156     if (!identifier.languages.isEmpty()) {
157         // This glyph exists only in certain languages, if we're not specifying a
158         // language on the referencing element we're unable to use this glyph.
159         if (language.isEmpty())
160             return false;
161
162         // Split subcode from language, if existant.
163         String languagePrefix;
164
165         size_t subCodeSeparator = language.find('-');
166         if (subCodeSeparator != kNotFound)
167             languagePrefix = language.left(subCodeSeparator);
168
169         Vector<String>::const_iterator it = identifier.languages.begin();
170         Vector<String>::const_iterator end = identifier.languages.end();
171
172         bool found = false;
173         for (; it != end; ++it) {
174             const String& cur = *it;
175             if (cur == language || cur == languagePrefix) {
176                 found = true;
177                 break;
178             }
179         }
180
181         if (!found)
182             return false;
183     }
184
185     // Check wheter arabic form is compatible
186     return isCompatibleArabicForm(identifier, chars, startPosition, endPosition);
187 }
188
189 }
190
191 #endif