| 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 |