OLD | NEW |
1 /** | 1 /** |
2 * Copyright (C) 2011 Nokia Inc. All rights reserved. | 2 * Copyright (C) 2011 Nokia Inc. All rights reserved. |
3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google Inc. All rights reserved. |
4 * | 4 * |
5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
9 * | 9 * |
10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 * Library General Public License for more details. | 13 * Library General Public License for more details. |
14 * | 14 * |
15 * You should have received a copy of the GNU Library General Public License | 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 | 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, | 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 * Boston, MA 02110-1301, USA. | 18 * Boston, MA 02110-1301, USA. |
19 * | 19 * |
20 */ | 20 */ |
21 | 21 |
22 #include "config.h" | 22 #include "config.h" |
23 #include "core/rendering/RenderQuote.h" | 23 #include "core/rendering/RenderQuote.h" |
24 | 24 |
25 #include "core/rendering/RenderView.h" | 25 #include "core/rendering/style/QuotesData.h" |
26 #include <wtf/text/AtomicString.h> | |
27 | 26 |
28 #define U(x) ((const UChar*)L##x) | 27 using namespace WTF::Unicode; |
29 | 28 |
30 namespace WebCore { | 29 namespace WebCore { |
31 | 30 |
32 RenderQuote::RenderQuote(Document* node, QuoteType quote) | 31 RenderQuote::RenderQuote(Document* node, QuoteType quote) |
33 : RenderText(node, StringImpl::empty()) | 32 : RenderText(node, StringImpl::empty()) |
34 , m_type(quote) | 33 , m_type(quote) |
35 , m_depth(0) | 34 , m_depth(0) |
36 , m_next(0) | 35 , m_next(0) |
37 , m_previous(0) | 36 , m_previous(0) |
38 , m_attached(false) | 37 , m_isAttached(false) |
39 { | 38 { |
40 } | 39 } |
41 | 40 |
42 RenderQuote::~RenderQuote() | 41 RenderQuote::~RenderQuote() |
43 { | 42 { |
44 ASSERT(!m_attached); | 43 ASSERT(!m_isAttached); |
45 ASSERT(!m_next && !m_previous); | 44 ASSERT(!m_next); |
| 45 ASSERT(!m_previous); |
46 } | 46 } |
47 | 47 |
48 void RenderQuote::willBeDestroyed() | 48 void RenderQuote::willBeDestroyed() |
49 { | 49 { |
50 detachQuote(); | 50 detachQuote(); |
51 RenderText::willBeDestroyed(); | 51 RenderText::willBeDestroyed(); |
52 } | 52 } |
53 | 53 |
54 void RenderQuote::willBeRemovedFromTree() | 54 void RenderQuote::willBeRemovedFromTree() |
55 { | 55 { |
56 RenderText::willBeRemovedFromTree(); | 56 RenderText::willBeRemovedFromTree(); |
57 detachQuote(); | 57 detachQuote(); |
58 } | 58 } |
59 | 59 |
60 void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
le) | 60 void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
le) |
61 { | 61 { |
62 RenderText::styleDidChange(diff, oldStyle); | 62 RenderText::styleDidChange(diff, oldStyle); |
63 setText(originalText()); | 63 setText(originalText()); |
64 } | 64 } |
65 | 65 |
66 typedef HashMap<AtomicString, const QuotesData*, CaseFoldingHash> QuotesMap; | 66 const unsigned maxDistinctQuoteCharacters = 16; |
67 | 67 |
68 static const QuotesMap& quotesDataLanguageMap() | 68 #if !ASSERT_DISABLED |
69 { | 69 |
70 DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ()); | 70 static void checkNumberOfDistinctQuoteCharacters(UChar character) |
71 if (staticQuotesMap.size()) | 71 { |
72 return staticQuotesMap; | 72 ASSERT(character); |
73 | 73 static UChar distinctQuoteCharacters[maxDistinctQuoteCharacters]; |
| 74 for (unsigned i = 0; i < maxDistinctQuoteCharacters; ++i) { |
| 75 if (distinctQuoteCharacters[i] == character) |
| 76 return; |
| 77 if (!distinctQuoteCharacters[i]) { |
| 78 distinctQuoteCharacters[i] = character; |
| 79 return; |
| 80 } |
| 81 } |
| 82 ASSERT_NOT_REACHED(); |
| 83 } |
| 84 |
| 85 #endif |
| 86 |
| 87 struct QuotesForLanguage { |
| 88 const char* language; |
| 89 UChar open1; |
| 90 UChar close1; |
| 91 UChar open2; |
| 92 UChar close2; |
| 93 }; |
| 94 |
| 95 static int quoteTableLanguageComparisonFunction(const void* a, const void* b) |
| 96 { |
| 97 return strcmp(static_cast<const QuotesForLanguage*>(a)->language, |
| 98 static_cast<const QuotesForLanguage*>(b)->language); |
| 99 } |
| 100 |
| 101 static const QuotesForLanguage* quotesForLanguage(const String& language) |
| 102 { |
74 // Table of quotes from http://www.whatwg.org/specs/web-apps/current-work/mu
ltipage/rendering.html#quotes | 103 // Table of quotes from http://www.whatwg.org/specs/web-apps/current-work/mu
ltipage/rendering.html#quotes |
75 #define QUOTES_LANG(lang, o1, c1, o2, c2) staticQuotesMap.set(lang, QuotesDa
ta::create(U(o1), U(c1), U(o2), U(c2)).leakRef()) | 104 static const QuotesForLanguage quoteTable[] = { |
76 QUOTES_LANG("af", "\x201c", "\x201d", "\x2018", "\x2019"); | 105 { "af", 0x201c, 0x201d, 0x2018, 0x2019 }, |
77 QUOTES_LANG("agq", "\x201e", "\x201d", "\x201a", "\x2019"); | 106 { "agq", 0x201e, 0x201d, 0x201a, 0x2019 }, |
78 QUOTES_LANG("ak", "\x201c", "\x201d", "\x2018", "\x2019"); | 107 { "ak", 0x201c, 0x201d, 0x2018, 0x2019 }, |
79 QUOTES_LANG("am", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 108 { "am", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
80 QUOTES_LANG("ar", "\x201d", "\x201c", "\x2019", "\x2018"); | 109 { "ar", 0x201d, 0x201c, 0x2019, 0x2018 }, |
81 QUOTES_LANG("asa", "\x201c", "\x201d", "\x2018", "\x2019"); | 110 { "asa", 0x201c, 0x201d, 0x2018, 0x2019 }, |
82 QUOTES_LANG("az-Cyrl", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 111 { "az-cyrl", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
83 QUOTES_LANG("bas", "\x00ab", "\x00bb", "\x201e", "\x201c"); | 112 { "bas", 0x00ab, 0x00bb, 0x201e, 0x201c }, |
84 QUOTES_LANG("bem", "\x201c", "\x201d", "\x2018", "\x2019"); | 113 { "bem", 0x201c, 0x201d, 0x2018, 0x2019 }, |
85 QUOTES_LANG("bez", "\x201c", "\x201d", "\x2018", "\x2019"); | 114 { "bez", 0x201c, 0x201d, 0x2018, 0x2019 }, |
86 QUOTES_LANG("bg", "\x201e", "\x201c", "\x201a", "\x2018"); | 115 { "bg", 0x201e, 0x201c, 0x201a, 0x2018 }, |
87 QUOTES_LANG("bm", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 116 { "bm", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
88 QUOTES_LANG("bn", "\x201c", "\x201d", "\x2018", "\x2019"); | 117 { "bn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
89 QUOTES_LANG("br", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 118 { "br", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
90 QUOTES_LANG("brx", "\x201c", "\x201d", "\x2018", "\x2019"); | 119 { "brx", 0x201c, 0x201d, 0x2018, 0x2019 }, |
91 QUOTES_LANG("bs-Cyrl", "\x201e", "\x201c", "\x201a", "\x2018"); | 120 { "bs-cyrl", 0x201e, 0x201c, 0x201a, 0x2018 }, |
92 QUOTES_LANG("ca", "\x201c", "\x201d", "\x00ab", "\x00bb"); | 121 { "ca", 0x201c, 0x201d, 0x00ab, 0x00bb }, |
93 QUOTES_LANG("cgg", "\x201c", "\x201d", "\x2018", "\x2019"); | 122 { "cgg", 0x201c, 0x201d, 0x2018, 0x2019 }, |
94 QUOTES_LANG("chr", "\x201c", "\x201d", "\x2018", "\x2019"); | 123 { "chr", 0x201c, 0x201d, 0x2018, 0x2019 }, |
95 QUOTES_LANG("cs", "\x201e", "\x201c", "\x201a", "\x2018"); | 124 { "cs", 0x201e, 0x201c, 0x201a, 0x2018 }, |
96 QUOTES_LANG("da", "\x201c", "\x201d", "\x2018", "\x2019"); | 125 { "da", 0x201c, 0x201d, 0x2018, 0x2019 }, |
97 QUOTES_LANG("dav", "\x201c", "\x201d", "\x2018", "\x2019"); | 126 { "dav", 0x201c, 0x201d, 0x2018, 0x2019 }, |
98 QUOTES_LANG("de", "\x201e", "\x201c", "\x201a", "\x2018"); | 127 { "de", 0x201e, 0x201c, 0x201a, 0x2018 }, |
99 QUOTES_LANG("de-CH", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 128 { "de-ch", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
100 QUOTES_LANG("dje", "\x201c", "\x201d", "\x2018", "\x2019"); | 129 { "dje", 0x201c, 0x201d, 0x2018, 0x2019 }, |
101 QUOTES_LANG("dua", "\x00ab", "\x00bb", "\x2018", "\x2019"); | 130 { "dua", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
102 QUOTES_LANG("dyo", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 131 { "dyo", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
103 QUOTES_LANG("dz", "\x201c", "\x201d", "\x2018", "\x2019"); | 132 { "dz", 0x201c, 0x201d, 0x2018, 0x2019 }, |
104 QUOTES_LANG("ebu", "\x201c", "\x201d", "\x2018", "\x2019"); | 133 { "ebu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
105 QUOTES_LANG("ee", "\x201c", "\x201d", "\x2018", "\x2019"); | 134 { "ee", 0x201c, 0x201d, 0x2018, 0x2019 }, |
106 QUOTES_LANG("el", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 135 { "el", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
107 QUOTES_LANG("en", "\x201c", "\x201d", "\x2018", "\x2019"); | 136 { "en", 0x201c, 0x201d, 0x2018, 0x2019 }, |
108 QUOTES_LANG("en-GB", "\x201c", "\x201d", "\x2018", "\x2019"); | 137 { "en-gb", 0x201c, 0x201d, 0x2018, 0x2019 }, |
109 QUOTES_LANG("es", "\x201c", "\x201d", "\x00ab", "\x00bb"); | 138 { "es", 0x201c, 0x201d, 0x00ab, 0x00bb }, |
110 QUOTES_LANG("et", "\x201e", "\x201c", "\x201a", "\x2018"); | 139 { "et", 0x201e, 0x201c, 0x201a, 0x2018 }, |
111 QUOTES_LANG("eu", "\x201c", "\x201d", "\x00ab", "\x00bb"); | 140 { "eu", 0x201c, 0x201d, 0x00ab, 0x00bb }, |
112 QUOTES_LANG("ewo", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 141 { "ewo", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
113 QUOTES_LANG("fa", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 142 { "fa", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
114 QUOTES_LANG("ff", "\x201e", "\x201d", "\x201a", "\x2019"); | 143 { "ff", 0x201e, 0x201d, 0x201a, 0x2019 }, |
115 QUOTES_LANG("fi", "\x201d", "\x201d", "\x2019", "\x2019"); | 144 { "fi", 0x201d, 0x201d, 0x2019, 0x2019 }, |
116 QUOTES_LANG("fr", "\x00ab", "\x00bb", "\x00ab", "\x00bb"); | 145 { "fr", 0x00ab, 0x00bb, 0x00ab, 0x00bb }, |
117 QUOTES_LANG("fr-CA", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 146 { "fr-ca", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
118 QUOTES_LANG("fr-CH", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 147 { "fr-ch", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
119 QUOTES_LANG("gsw", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 148 { "gsw", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
120 QUOTES_LANG("gu", "\x201c", "\x201d", "\x2018", "\x2019"); | 149 { "gu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
121 QUOTES_LANG("guz", "\x201c", "\x201d", "\x2018", "\x2019"); | 150 { "guz", 0x201c, 0x201d, 0x2018, 0x2019 }, |
122 QUOTES_LANG("ha", "\x201c", "\x201d", "\x2018", "\x2019"); | 151 { "ha", 0x201c, 0x201d, 0x2018, 0x2019 }, |
123 QUOTES_LANG("he", "\x0022", "\x0022", "\x0027", "\x0027"); | 152 { "he", 0x0022, 0x0022, 0x0027, 0x0027 }, |
124 QUOTES_LANG("hi", "\x201c", "\x201d", "\x2018", "\x2019"); | 153 { "hi", 0x201c, 0x201d, 0x2018, 0x2019 }, |
125 QUOTES_LANG("hr", "\x201e", "\x201c", "\x201a", "\x2018"); | 154 { "hr", 0x201e, 0x201c, 0x201a, 0x2018 }, |
126 QUOTES_LANG("hu", "\x201e", "\x201d", "\x00bb", "\x00ab"); | 155 { "hu", 0x201e, 0x201d, 0x00bb, 0x00ab }, |
127 QUOTES_LANG("id", "\x201c", "\x201d", "\x2018", "\x2019"); | 156 { "id", 0x201c, 0x201d, 0x2018, 0x2019 }, |
128 QUOTES_LANG("ig", "\x201c", "\x201d", "\x2018", "\x2019"); | 157 { "ig", 0x201c, 0x201d, 0x2018, 0x2019 }, |
129 QUOTES_LANG("it", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 158 { "it", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
130 QUOTES_LANG("ja", "\x300c", "\x300d", "\x300e", "\x300f"); | 159 { "ja", 0x300c, 0x300d, 0x300e, 0x300f }, |
131 QUOTES_LANG("jgo", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 160 { "jgo", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
132 QUOTES_LANG("jmc", "\x201c", "\x201d", "\x2018", "\x2019"); | 161 { "jmc", 0x201c, 0x201d, 0x2018, 0x2019 }, |
133 QUOTES_LANG("kab", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 162 { "kab", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
134 QUOTES_LANG("kam", "\x201c", "\x201d", "\x2018", "\x2019"); | 163 { "kam", 0x201c, 0x201d, 0x2018, 0x2019 }, |
135 QUOTES_LANG("kde", "\x201c", "\x201d", "\x2018", "\x2019"); | 164 { "kde", 0x201c, 0x201d, 0x2018, 0x2019 }, |
136 QUOTES_LANG("kea", "\x201c", "\x201d", "\x2018", "\x2019"); | 165 { "kea", 0x201c, 0x201d, 0x2018, 0x2019 }, |
137 QUOTES_LANG("khq", "\x201c", "\x201d", "\x2018", "\x2019"); | 166 { "khq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
138 QUOTES_LANG("ki", "\x201c", "\x201d", "\x2018", "\x2019"); | 167 { "ki", 0x201c, 0x201d, 0x2018, 0x2019 }, |
139 QUOTES_LANG("kkj", "\x00ab", "\x00bb", "\x2039", "\x203a"); | 168 { "kkj", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
140 QUOTES_LANG("kln", "\x201c", "\x201d", "\x2018", "\x2019"); | 169 { "kln", 0x201c, 0x201d, 0x2018, 0x2019 }, |
141 QUOTES_LANG("km", "\x201c", "\x201d", "\x2018", "\x2019"); | 170 { "km", 0x201c, 0x201d, 0x2018, 0x2019 }, |
142 QUOTES_LANG("kn", "\x201c", "\x201d", "\x2018", "\x2019"); | 171 { "kn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
143 QUOTES_LANG("ko", "\x201c", "\x201d", "\x2018", "\x2019"); | 172 { "ko", 0x201c, 0x201d, 0x2018, 0x2019 }, |
144 QUOTES_LANG("ksb", "\x201c", "\x201d", "\x2018", "\x2019"); | 173 { "ksb", 0x201c, 0x201d, 0x2018, 0x2019 }, |
145 QUOTES_LANG("ksf", "\x00ab", "\x00bb", "\x2018", "\x2019"); | 174 { "ksf", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
146 QUOTES_LANG("lag", "\x201d", "\x201d", "\x2019", "\x2019"); | 175 { "lag", 0x201d, 0x201d, 0x2019, 0x2019 }, |
147 QUOTES_LANG("lg", "\x201c", "\x201d", "\x2018", "\x2019"); | 176 { "lg", 0x201c, 0x201d, 0x2018, 0x2019 }, |
148 QUOTES_LANG("ln", "\x201c", "\x201d", "\x2018", "\x2019"); | 177 { "ln", 0x201c, 0x201d, 0x2018, 0x2019 }, |
149 QUOTES_LANG("lo", "\x201c", "\x201d", "\x2018", "\x2019"); | 178 { "lo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
150 QUOTES_LANG("lt", "\x201e", "\x201c", "\x201e", "\x201c"); | 179 { "lt", 0x201e, 0x201c, 0x201e, 0x201c }, |
151 QUOTES_LANG("lu", "\x201c", "\x201d", "\x2018", "\x2019"); | 180 { "lu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
152 QUOTES_LANG("luo", "\x201c", "\x201d", "\x2018", "\x2019"); | 181 { "luo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
153 QUOTES_LANG("luy", "\x201e", "\x201c", "\x201a", "\x2018"); | 182 { "luy", 0x201e, 0x201c, 0x201a, 0x2018 }, |
154 QUOTES_LANG("lv", "\x201c", "\x201d", "\x2018", "\x2019"); | 183 { "lv", 0x201c, 0x201d, 0x2018, 0x2019 }, |
155 QUOTES_LANG("mas", "\x201c", "\x201d", "\x2018", "\x2019"); | 184 { "mas", 0x201c, 0x201d, 0x2018, 0x2019 }, |
156 QUOTES_LANG("mer", "\x201c", "\x201d", "\x2018", "\x2019"); | 185 { "mer", 0x201c, 0x201d, 0x2018, 0x2019 }, |
157 QUOTES_LANG("mfe", "\x201c", "\x201d", "\x2018", "\x2019"); | 186 { "mfe", 0x201c, 0x201d, 0x2018, 0x2019 }, |
158 QUOTES_LANG("mg", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 187 { "mg", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
159 QUOTES_LANG("mgo", "\x201c", "\x201d", "\x2018", "\x2019"); | 188 { "mgo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
160 QUOTES_LANG("mk", "\x201e", "\x201c", "\x201a", "\x2018"); | 189 { "mk", 0x201e, 0x201c, 0x201a, 0x2018 }, |
161 QUOTES_LANG("ml", "\x201c", "\x201d", "\x2018", "\x2019"); | 190 { "ml", 0x201c, 0x201d, 0x2018, 0x2019 }, |
162 QUOTES_LANG("mr", "\x201c", "\x201d", "\x2018", "\x2019"); | 191 { "mr", 0x201c, 0x201d, 0x2018, 0x2019 }, |
163 QUOTES_LANG("ms", "\x201c", "\x201d", "\x2018", "\x2019"); | 192 { "ms", 0x201c, 0x201d, 0x2018, 0x2019 }, |
164 QUOTES_LANG("mua", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 193 { "mua", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
165 QUOTES_LANG("my", "\x201c", "\x201d", "\x2018", "\x2019"); | 194 { "my", 0x201c, 0x201d, 0x2018, 0x2019 }, |
166 QUOTES_LANG("naq", "\x201c", "\x201d", "\x2018", "\x2019"); | 195 { "naq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
167 QUOTES_LANG("nb", "\x00ab", "\x00bb", "\x2018", "\x2019"); | 196 { "nb", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
168 QUOTES_LANG("nd", "\x201c", "\x201d", "\x2018", "\x2019"); | 197 { "nd", 0x201c, 0x201d, 0x2018, 0x2019 }, |
169 QUOTES_LANG("nl", "\x201c", "\x201d", "\x2018", "\x2019"); | 198 { "nl", 0x201c, 0x201d, 0x2018, 0x2019 }, |
170 QUOTES_LANG("nmg", "\x201e", "\x201d", "\x00ab", "\x00bb"); | 199 { "nmg", 0x201e, 0x201d, 0x00ab, 0x00bb }, |
171 QUOTES_LANG("nn", "\x00ab", "\x00bb", "\x2018", "\x2019"); | 200 { "nn", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
172 QUOTES_LANG("nnh", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 201 { "nnh", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
173 QUOTES_LANG("nus", "\x201c", "\x201d", "\x2018", "\x2019"); | 202 { "nus", 0x201c, 0x201d, 0x2018, 0x2019 }, |
174 QUOTES_LANG("nyn", "\x201c", "\x201d", "\x2018", "\x2019"); | 203 { "nyn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
175 QUOTES_LANG("pl", "\x201e", "\x201d", "\x00ab", "\x00bb"); | 204 { "pl", 0x201e, 0x201d, 0x00ab, 0x00bb }, |
176 QUOTES_LANG("pt", "\x201c", "\x201d", "\x2018", "\x2019"); | 205 { "pt", 0x201c, 0x201d, 0x2018, 0x2019 }, |
177 QUOTES_LANG("pt-PT", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 206 { "pt-pt", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
178 QUOTES_LANG("rn", "\x201d", "\x201d", "\x2019", "\x2019"); | 207 { "rn", 0x201d, 0x201d, 0x2019, 0x2019 }, |
179 QUOTES_LANG("ro", "\x201e", "\x201d", "\x00ab", "\x00bb"); | 208 { "ro", 0x201e, 0x201d, 0x00ab, 0x00bb }, |
180 QUOTES_LANG("rof", "\x201c", "\x201d", "\x2018", "\x2019"); | 209 { "rof", 0x201c, 0x201d, 0x2018, 0x2019 }, |
181 QUOTES_LANG("ru", "\x00ab", "\x00bb", "\x201e", "\x201c"); | 210 { "ru", 0x00ab, 0x00bb, 0x201e, 0x201c }, |
182 QUOTES_LANG("rw", "\x00ab", "\x00bb", "\x2018", "\x2019"); | 211 { "rw", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
183 QUOTES_LANG("rwk", "\x201c", "\x201d", "\x2018", "\x2019"); | 212 { "rwk", 0x201c, 0x201d, 0x2018, 0x2019 }, |
184 QUOTES_LANG("saq", "\x201c", "\x201d", "\x2018", "\x2019"); | 213 { "saq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
185 QUOTES_LANG("sbp", "\x201c", "\x201d", "\x2018", "\x2019"); | 214 { "sbp", 0x201c, 0x201d, 0x2018, 0x2019 }, |
186 QUOTES_LANG("seh", "\x201c", "\x201d", "\x2018", "\x2019"); | 215 { "seh", 0x201c, 0x201d, 0x2018, 0x2019 }, |
187 QUOTES_LANG("ses", "\x201c", "\x201d", "\x2018", "\x2019"); | 216 { "ses", 0x201c, 0x201d, 0x2018, 0x2019 }, |
188 QUOTES_LANG("sg", "\x00ab", "\x00bb", "\x201c", "\x201d"); | 217 { "sg", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
189 QUOTES_LANG("shi", "\x00ab", "\x00bb", "\x201e", "\x201d"); | 218 { "shi", 0x00ab, 0x00bb, 0x201e, 0x201d }, |
190 QUOTES_LANG("shi-Tfng", "\x00ab", "\x00bb", "\x201e", "\x201d"); | 219 { "shi-tfng", 0x00ab, 0x00bb, 0x201e, 0x201d }, |
191 QUOTES_LANG("si", "\x201c", "\x201d", "\x2018", "\x2019"); | 220 { "si", 0x201c, 0x201d, 0x2018, 0x2019 }, |
192 QUOTES_LANG("sk", "\x201e", "\x201c", "\x201a", "\x2018"); | 221 { "sk", 0x201e, 0x201c, 0x201a, 0x2018 }, |
193 QUOTES_LANG("sl", "\x201e", "\x201c", "\x201a", "\x2018"); | 222 { "sl", 0x201e, 0x201c, 0x201a, 0x2018 }, |
194 QUOTES_LANG("sn", "\x201d", "\x201d", "\x2019", "\x2019"); | 223 { "sn", 0x201d, 0x201d, 0x2019, 0x2019 }, |
195 QUOTES_LANG("so", "\x201c", "\x201d", "\x2018", "\x2019"); | 224 { "so", 0x201c, 0x201d, 0x2018, 0x2019 }, |
196 QUOTES_LANG("sq", "\x201e", "\x201c", "\x201a", "\x2018"); | 225 { "sq", 0x201e, 0x201c, 0x201a, 0x2018 }, |
197 QUOTES_LANG("sr", "\x201e", "\x201c", "\x201a", "\x2018"); | 226 { "sr", 0x201e, 0x201c, 0x201a, 0x2018 }, |
198 QUOTES_LANG("sr-Latn", "\x201e", "\x201c", "\x201a", "\x2018"); | 227 { "sr-latn", 0x201e, 0x201c, 0x201a, 0x2018 }, |
199 QUOTES_LANG("sv", "\x201d", "\x201d", "\x2019", "\x2019"); | 228 { "sv", 0x201d, 0x201d, 0x2019, 0x2019 }, |
200 QUOTES_LANG("sw", "\x201c", "\x201d", "\x2018", "\x2019"); | 229 { "sw", 0x201c, 0x201d, 0x2018, 0x2019 }, |
201 QUOTES_LANG("swc", "\x201c", "\x201d", "\x2018", "\x2019"); | 230 { "swc", 0x201c, 0x201d, 0x2018, 0x2019 }, |
202 QUOTES_LANG("ta", "\x201c", "\x201d", "\x2018", "\x2019"); | 231 { "ta", 0x201c, 0x201d, 0x2018, 0x2019 }, |
203 QUOTES_LANG("te", "\x201c", "\x201d", "\x2018", "\x2019"); | 232 { "te", 0x201c, 0x201d, 0x2018, 0x2019 }, |
204 QUOTES_LANG("teo", "\x201c", "\x201d", "\x2018", "\x2019"); | 233 { "teo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
205 QUOTES_LANG("th", "\x201c", "\x201d", "\x2018", "\x2019"); | 234 { "th", 0x201c, 0x201d, 0x2018, 0x2019 }, |
206 QUOTES_LANG("ti-ER", "\x2018", "\x2019", "\x201c", "\x201d"); | 235 { "ti-er", 0x2018, 0x2019, 0x201c, 0x201d }, |
207 QUOTES_LANG("to", "\x201c", "\x201d", "\x2018", "\x2019"); | 236 { "to", 0x201c, 0x201d, 0x2018, 0x2019 }, |
208 QUOTES_LANG("tr", "\x201c", "\x201d", "\x2018", "\x2019"); | 237 { "tr", 0x201c, 0x201d, 0x2018, 0x2019 }, |
209 QUOTES_LANG("twq", "\x201c", "\x201d", "\x2018", "\x2019"); | 238 { "twq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
210 QUOTES_LANG("tzm", "\x201c", "\x201d", "\x2018", "\x2019"); | 239 { "tzm", 0x201c, 0x201d, 0x2018, 0x2019 }, |
211 QUOTES_LANG("uk", "\x00ab", "\x00bb", "\x201e", "\x201c"); | 240 { "uk", 0x00ab, 0x00bb, 0x201e, 0x201c }, |
212 QUOTES_LANG("ur", "\x201d", "\x201c", "\x2019", "\x2018"); | 241 { "ur", 0x201d, 0x201c, 0x2019, 0x2018 }, |
213 QUOTES_LANG("vai", "\x201c", "\x201d", "\x2018", "\x2019"); | 242 { "vai", 0x201c, 0x201d, 0x2018, 0x2019 }, |
214 QUOTES_LANG("vai-Latn", "\x201c", "\x201d", "\x2018", "\x2019"); | 243 { "vai-latn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
215 QUOTES_LANG("vi", "\x201c", "\x201d", "\x2018", "\x2019"); | 244 { "vi", 0x201c, 0x201d, 0x2018, 0x2019 }, |
216 QUOTES_LANG("vun", "\x201c", "\x201d", "\x2018", "\x2019"); | 245 { "vun", 0x201c, 0x201d, 0x2018, 0x2019 }, |
217 QUOTES_LANG("xh", "\x2018", "\x2019", "\x201c", "\x201d"); | 246 { "xh", 0x2018, 0x2019, 0x201c, 0x201d }, |
218 QUOTES_LANG("xog", "\x201c", "\x201d", "\x2018", "\x2019"); | 247 { "xog", 0x201c, 0x201d, 0x2018, 0x2019 }, |
219 QUOTES_LANG("yav", "\x00ab", "\x00bb", "\x00ab", "\x00bb"); | 248 { "yav", 0x00ab, 0x00bb, 0x00ab, 0x00bb }, |
220 QUOTES_LANG("yo", "\x201c", "\x201d", "\x2018", "\x2019"); | 249 { "yo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
221 QUOTES_LANG("zh", "\x201c", "\x201d", "\x2018", "\x2019"); | 250 { "zh", 0x201c, 0x201d, 0x2018, 0x2019 }, |
222 QUOTES_LANG("zh-Hant", "\x300c", "\x300d", "\x300e", "\x300f"); | 251 { "zh-hant", 0x300c, 0x300d, 0x300e, 0x300f }, |
223 QUOTES_LANG("zu", "\x201c", "\x201d", "\x2018", "\x2019"); | 252 { "zu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
224 #undef QUOTES_LANG | 253 }; |
225 | 254 |
226 return staticQuotesMap; | 255 const unsigned maxLanguageLength = 8; |
227 } | 256 |
228 | 257 #if !ASSERT_DISABLED |
229 static const QuotesData* basicQuotesData() | 258 // One time check that the table meets the constraints that the code below r
elies on. |
230 { | 259 |
231 // FIXME: The default quotes should be the fancy quotes for "en". | 260 static bool didOneTimeCheck = false; |
232 static const QuotesData* staticBasicQuotes = QuotesData::create(U("\""), U("
\""), U("'"), U("'")).leakRef(); | 261 if (!didOneTimeCheck) { |
233 return staticBasicQuotes; | 262 didOneTimeCheck = true; |
| 263 |
| 264 checkNumberOfDistinctQuoteCharacters(quotationMark); |
| 265 checkNumberOfDistinctQuoteCharacters(apostrophe); |
| 266 |
| 267 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(quoteTable); ++i) { |
| 268 ASSERT(strlen(quoteTable[i].language) <= maxLanguageLength); |
| 269 |
| 270 if (i) |
| 271 ASSERT(strcmp(quoteTable[i - 1].language, quoteTable[i].language
) < 0); |
| 272 |
| 273 for (unsigned j = 0; UChar character = quoteTable[i].language[j]; ++
j) |
| 274 ASSERT(isASCIILower(character) || character == '-'); |
| 275 |
| 276 checkNumberOfDistinctQuoteCharacters(quoteTable[i].open1); |
| 277 checkNumberOfDistinctQuoteCharacters(quoteTable[i].close1); |
| 278 checkNumberOfDistinctQuoteCharacters(quoteTable[i].open2); |
| 279 checkNumberOfDistinctQuoteCharacters(quoteTable[i].close2); |
| 280 } |
| 281 } |
| 282 #endif |
| 283 |
| 284 unsigned length = language.length(); |
| 285 if (!length || length > maxLanguageLength) |
| 286 return 0; |
| 287 |
| 288 char languageKeyBuffer[maxLanguageLength + 1]; |
| 289 for (unsigned i = 0; i < length; ++i) { |
| 290 UChar character = toASCIILower(language[i]); |
| 291 if (!(isASCIILower(character) || character == '-')) |
| 292 return 0; |
| 293 languageKeyBuffer[i] = static_cast<char>(character); |
| 294 } |
| 295 languageKeyBuffer[length] = 0; |
| 296 |
| 297 QuotesForLanguage languageKey = { languageKeyBuffer, 0, 0, 0, 0 }; |
| 298 |
| 299 return static_cast<const QuotesForLanguage*>(bsearch(&languageKey, |
| 300 quoteTable, WTF_ARRAY_LENGTH(quoteTable), sizeof(quoteTable[0]), quoteTa
bleLanguageComparisonFunction)); |
| 301 } |
| 302 |
| 303 static StringImpl* stringForQuoteCharacter(UChar character) |
| 304 { |
| 305 // Use linear search because there is a small number of distinct characters,
thus binary search is unneeded. |
| 306 ASSERT(character); |
| 307 struct StringForCharacter { |
| 308 UChar character; |
| 309 StringImpl* string; |
| 310 }; |
| 311 static StringForCharacter strings[maxDistinctQuoteCharacters]; |
| 312 for (unsigned i = 0; i < maxDistinctQuoteCharacters; ++i) { |
| 313 if (strings[i].character == character) |
| 314 return strings[i].string; |
| 315 if (!strings[i].character) { |
| 316 strings[i].character = character; |
| 317 strings[i].string = StringImpl::create8BitIfPossible(&character, 1).
leakRef(); |
| 318 return strings[i].string; |
| 319 } |
| 320 } |
| 321 ASSERT_NOT_REACHED(); |
| 322 return StringImpl::empty(); |
| 323 } |
| 324 |
| 325 static inline StringImpl* quotationMarkString() |
| 326 { |
| 327 static StringImpl* quotationMarkString = stringForQuoteCharacter(quotationMa
rk); |
| 328 return quotationMarkString; |
| 329 } |
| 330 |
| 331 static inline StringImpl* apostropheString() |
| 332 { |
| 333 static StringImpl* apostropheString = stringForQuoteCharacter(apostrophe); |
| 334 return apostropheString; |
234 } | 335 } |
235 | 336 |
236 PassRefPtr<StringImpl> RenderQuote::originalText() const | 337 PassRefPtr<StringImpl> RenderQuote::originalText() const |
237 { | 338 { |
| 339 if (m_depth < 0) |
| 340 return StringImpl::empty(); |
| 341 bool isOpenQuote = false; |
238 switch (m_type) { | 342 switch (m_type) { |
239 case NO_OPEN_QUOTE: | 343 case NO_OPEN_QUOTE: |
240 case NO_CLOSE_QUOTE: | 344 case NO_CLOSE_QUOTE: |
241 return StringImpl::empty(); | 345 return StringImpl::empty(); |
| 346 case OPEN_QUOTE: |
| 347 isOpenQuote = true; |
| 348 // fall through |
242 case CLOSE_QUOTE: | 349 case CLOSE_QUOTE: |
243 return quotesData()->getCloseQuote(m_depth - 1).impl(); | 350 if (const QuotesData* quotes = style()->quotes()) |
244 case OPEN_QUOTE: | 351 return isOpenQuote ? quotes->openQuote(m_depth).impl() : quotes->clo
seQuote(m_depth).impl(); |
245 return quotesData()->getOpenQuote(m_depth).impl(); | 352 if (const QuotesForLanguage* quotes = quotesForLanguage(style()->locale(
))) |
| 353 return stringForQuoteCharacter(isOpenQuote ? (m_depth ? quotes->open
2 : quotes->open1) : (m_depth ? quotes->close2 : quotes->close1)); |
| 354 // FIXME: Should the default be the quotes for "en" rather than straight
quotes? |
| 355 return m_depth ? apostropheString() : quotationMarkString(); |
246 } | 356 } |
247 ASSERT_NOT_REACHED(); | 357 ASSERT_NOT_REACHED(); |
248 return StringImpl::empty(); | 358 return StringImpl::empty(); |
249 } | 359 } |
250 | 360 |
251 const QuotesData* RenderQuote::quotesData() const | |
252 { | |
253 if (QuotesData* customQuotes = style()->quotes()) | |
254 return customQuotes; | |
255 | |
256 AtomicString language = style()->locale(); | |
257 if (language.isNull()) | |
258 return basicQuotesData(); | |
259 const QuotesData* quotes = quotesDataLanguageMap().get(language); | |
260 if (!quotes) | |
261 return basicQuotesData(); | |
262 return quotes; | |
263 } | |
264 | |
265 void RenderQuote::attachQuote() | 361 void RenderQuote::attachQuote() |
266 { | 362 { |
267 ASSERT(view()); | 363 ASSERT(view()); |
268 ASSERT(!m_attached); | 364 ASSERT(!m_isAttached); |
269 ASSERT(!m_next && !m_previous); | 365 ASSERT(!m_next); |
| 366 ASSERT(!m_previous); |
270 ASSERT(isRooted()); | 367 ASSERT(isRooted()); |
271 | 368 |
272 if (!view()->renderQuoteHead()) { | 369 // Optimize case where this is the first quote in a RenderView by not search
ing for predecessors in that case. |
273 view()->setRenderQuoteHead(this); | 370 if (view()->renderQuoteHead()) { |
274 m_attached = true; | 371 for (RenderObject* predecessor = previousInPreOrder(); predecessor; pred
ecessor = predecessor->previousInPreOrder()) { |
275 return; | 372 // Skip unattached predecessors to avoid having stale m_previous poi
nters |
276 } | 373 // if the previous node is never attached and is then destroyed. |
277 | 374 if (!predecessor->isQuote() || !toRenderQuote(predecessor)->m_isAtta
ched) |
278 for (RenderObject* predecessor = previousInPreOrder(); predecessor; predeces
sor = predecessor->previousInPreOrder()) { | 375 continue; |
279 // Skip unattached predecessors to avoid having stale m_previous pointer
s | 376 m_previous = toRenderQuote(predecessor); |
280 // if the previous node is never attached and is then destroyed. | 377 m_next = m_previous->m_next; |
281 if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached()
) | 378 m_previous->m_next = this; |
282 continue; | 379 if (m_next) |
283 m_previous = toRenderQuote(predecessor); | 380 m_next->m_previous = this; |
284 m_next = m_previous->m_next; | 381 break; |
285 m_previous->m_next = this; | 382 } |
286 if (m_next) | |
287 m_next->m_previous = this; | |
288 break; | |
289 } | 383 } |
290 | 384 |
291 if (!m_previous) { | 385 if (!m_previous) { |
292 m_next = view()->renderQuoteHead(); | 386 m_next = view()->renderQuoteHead(); |
293 view()->setRenderQuoteHead(this); | 387 view()->setRenderQuoteHead(this); |
294 if (m_next) | 388 if (m_next) |
295 m_next->m_previous = this; | 389 m_next->m_previous = this; |
296 } | 390 } |
297 m_attached = true; | 391 m_isAttached = true; |
298 | 392 |
299 for (RenderQuote* quote = this; quote; quote = quote->m_next) | 393 for (RenderQuote* quote = this; quote; quote = quote->m_next) |
300 quote->updateDepth(); | 394 quote->updateDepth(); |
301 | 395 |
302 ASSERT(!m_next || m_next->m_attached); | 396 ASSERT(!m_next || m_next->m_isAttached); |
303 ASSERT(!m_next || m_next->m_previous == this); | 397 ASSERT(!m_next || m_next->m_previous == this); |
304 ASSERT(!m_previous || m_previous->m_attached); | 398 ASSERT(!m_previous || m_previous->m_isAttached); |
305 ASSERT(!m_previous || m_previous->m_next == this); | 399 ASSERT(!m_previous || m_previous->m_next == this); |
306 } | 400 } |
307 | 401 |
308 void RenderQuote::detachQuote() | 402 void RenderQuote::detachQuote() |
309 { | 403 { |
310 ASSERT(!m_next || m_next->m_attached); | 404 ASSERT(!m_next || m_next->m_isAttached); |
311 ASSERT(!m_previous || m_previous->m_attached); | 405 ASSERT(!m_previous || m_previous->m_isAttached); |
312 if (!m_attached) | 406 if (!m_isAttached) |
313 return; | 407 return; |
314 if (m_previous) | 408 if (m_previous) |
315 m_previous->m_next = m_next; | 409 m_previous->m_next = m_next; |
316 else if (view()) | 410 else if (view()) |
317 view()->setRenderQuoteHead(m_next); | 411 view()->setRenderQuoteHead(m_next); |
318 if (m_next) | 412 if (m_next) |
319 m_next->m_previous = m_previous; | 413 m_next->m_previous = m_previous; |
320 if (!documentBeingDestroyed()) { | 414 if (!documentBeingDestroyed()) { |
321 for (RenderQuote* quote = m_next; quote; quote = quote->m_next) | 415 for (RenderQuote* quote = m_next; quote; quote = quote->m_next) |
322 quote->updateDepth(); | 416 quote->updateDepth(); |
323 } | 417 } |
324 m_attached = false; | 418 m_isAttached = false; |
325 m_next = 0; | 419 m_next = 0; |
326 m_previous = 0; | 420 m_previous = 0; |
327 m_depth = 0; | 421 m_depth = 0; |
328 } | 422 } |
329 | 423 |
330 void RenderQuote::updateDepth() | 424 void RenderQuote::updateDepth() |
331 { | 425 { |
332 ASSERT(m_attached); | 426 ASSERT(m_isAttached); |
333 int oldDepth = m_depth; | 427 int oldDepth = m_depth; |
334 m_depth = 0; | 428 m_depth = 0; |
335 if (m_previous) { | 429 if (m_previous) { |
336 m_depth = m_previous->m_depth; | 430 m_depth = m_previous->m_depth; |
337 switch (m_previous->m_type) { | 431 switch (m_previous->m_type) { |
338 case OPEN_QUOTE: | 432 case OPEN_QUOTE: |
339 case NO_OPEN_QUOTE: | 433 case NO_OPEN_QUOTE: |
340 m_depth++; | 434 m_depth++; |
341 break; | 435 break; |
342 case CLOSE_QUOTE: | 436 case CLOSE_QUOTE: |
343 case NO_CLOSE_QUOTE: | 437 case NO_CLOSE_QUOTE: |
344 if (m_depth) | 438 if (m_depth) |
345 m_depth--; | 439 m_depth--; |
346 break; | 440 break; |
347 } | 441 } |
348 } | 442 } |
349 if (oldDepth != m_depth) | 443 if (oldDepth != m_depth) |
350 setText(originalText()); | 444 setText(originalText()); |
351 } | 445 } |
352 | 446 |
353 } // namespace WebCore | 447 } // namespace WebCore |
OLD | NEW |