OLD | NEW |
| (Empty) |
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 blink { | |
31 | |
32 // Helper functions to determine the arabic character forms (initial, medial, te
rminal, 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 , SDua
l , SDual , SDual , SDual , SRight, /* 0x0622 - 0x062F */ | |
41 SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDua
l , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */ | |
42 SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDua
l , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */ | |
43 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNon
e , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */ | |
44 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNon
e , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */ | |
45 SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDua
l , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */ | |
46 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRig
ht, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */ | |
47 SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRig
ht, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */ | |
48 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDua
l , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */ | |
49 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDua
l , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */ | |
50 SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRig
ht, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */ | |
51 SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNon
e , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */ | |
52 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNon
e , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */ | |
53 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNon
e , SDual , SDual , SDual , SNone , SNone , SNone /* 0x06F0 - 0x06FF */ | |
54 }; | |
55 | |
56 static inline SVGGlyph::ArabicForm processArabicFormDetection(const UChar& curCh
ar, 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], lastCharShapesRig
ht, forms.isEmpty() ? 0 : &forms.first())); | |
105 } else { | |
106 for (unsigned i = 0; i < length; ++i) | |
107 forms.append(processArabicFormDetection(input[i], lastCharShapesRigh
t, forms.isEmpty() ? 0 : &forms.last())); | |
108 } | |
109 | |
110 return forms; | |
111 } | |
112 | |
113 static inline bool isCompatibleArabicForm(const SVGGlyph& identifier, const Vect
or<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() + startPosit
ion; | |
120 if (it >= realEnd) | |
121 return true; | |
122 | |
123 Vector<SVGGlyph::ArabicForm>::const_iterator end = chars.begin() + endPositi
on; | |
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 St
ring& language, | |
136 const Vector<SVGGlyph::ArabicForm>& chars, unsigned start
Position, 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 } // namespace blink | |
190 | |
191 #endif | |
OLD | NEW |