Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderQuote.cpp
1 /**
2  * Copyright (C) 2011 Nokia Inc.  All rights reserved.
3  * Copyright (C) 2012 Google Inc. 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
22 #include "config.h"
23 #include "core/rendering/RenderQuote.h"
24
25 #include "core/rendering/RenderTextFragment.h"
26 #include "core/rendering/RenderView.h"
27 #include "wtf/StdLibExtras.h"
28 #include "wtf/text/AtomicString.h"
29
30 #include <algorithm>
31
32 namespace blink {
33
34 RenderQuote::RenderQuote(Document* node, QuoteType quote)
35     : RenderInline(0)
36     , m_type(quote)
37     , m_depth(0)
38     , m_next(nullptr)
39     , m_previous(nullptr)
40     , m_attached(false)
41 {
42     setDocumentForAnonymous(node);
43 }
44
45 RenderQuote::~RenderQuote()
46 {
47     ASSERT(!m_attached);
48     ASSERT(!m_next && !m_previous);
49 }
50
51 void RenderQuote::trace(Visitor* visitor)
52 {
53     visitor->trace(m_next);
54     visitor->trace(m_previous);
55     RenderInline::trace(visitor);
56 }
57
58 void RenderQuote::willBeDestroyed()
59 {
60     detachQuote();
61     RenderInline::willBeDestroyed();
62 }
63
64 void RenderQuote::willBeRemovedFromTree()
65 {
66     RenderInline::willBeRemovedFromTree();
67     detachQuote();
68 }
69
70 void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
71 {
72     RenderInline::styleDidChange(diff, oldStyle);
73     updateText();
74 }
75
76 struct Language {
77     const char* lang;
78     UChar open1;
79     UChar close1;
80     UChar open2;
81     UChar close2;
82     QuotesData* data;
83
84     bool operator<(const Language& b) const { return strcmp(lang, b.lang) < 0; }
85 };
86
87 // Table of quotes from http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#quote
88 Language languages[] = {
89     { "af",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
90     { "agq",           0x201e, 0x201d, 0x201a, 0x2019, 0 },
91     { "ak",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
92     { "am",            0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
93     { "ar",            0x201d, 0x201c, 0x2019, 0x2018, 0 },
94     { "asa",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
95     { "az-cyrl",       0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
96     { "bas",           0x00ab, 0x00bb, 0x201e, 0x201c, 0 },
97     { "bem",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
98     { "bez",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
99     { "bg",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
100     { "bm",            0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
101     { "bn",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
102     { "br",            0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
103     { "brx",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
104     { "bs-cyrl" ,      0x201e, 0x201c, 0x201a, 0x2018, 0 },
105     { "ca",            0x201c, 0x201d, 0x00ab, 0x00bb, 0 },
106     { "cgg",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
107     { "chr",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
108     { "cs",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
109     { "da",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
110     { "dav",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
111     { "de",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
112     { "de-ch",         0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
113     { "dje",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
114     { "dua",           0x00ab, 0x00bb, 0x2018, 0x2019, 0 },
115     { "dyo",           0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
116     { "dz",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
117     { "ebu",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
118     { "ee",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
119     { "el",            0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
120     { "en",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
121     { "en-gb",         0x201c, 0x201d, 0x2018, 0x2019, 0 },
122     { "es",            0x201c, 0x201d, 0x00ab, 0x00bb, 0 },
123     { "et",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
124     { "eu",            0x201c, 0x201d, 0x00ab, 0x00bb, 0 },
125     { "ewo",           0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
126     { "fa",            0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
127     { "ff",            0x201e, 0x201d, 0x201a, 0x2019, 0 },
128     { "fi",            0x201d, 0x201d, 0x2019, 0x2019, 0 },
129     { "fr",            0x00ab, 0x00bb, 0x00ab, 0x00bb, 0 },
130     { "fr-ca",         0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
131     { "fr-ch",         0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
132     { "gsw",           0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
133     { "gu",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
134     { "guz",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
135     { "ha",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
136     { "he",            0x0022, 0x0022, 0x0027, 0x0027, 0 },
137     { "hi",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
138     { "hr",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
139     { "hu",            0x201e, 0x201d, 0x00bb, 0x00ab, 0 },
140     { "id",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
141     { "ig",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
142     { "it",            0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
143     { "ja",            0x300c, 0x300d, 0x300e, 0x300f, 0 },
144     { "jgo",           0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
145     { "jmc",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
146     { "kab",           0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
147     { "kam",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
148     { "kde",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
149     { "kea",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
150     { "khq",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
151     { "ki",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
152     { "kkj",           0x00ab, 0x00bb, 0x2039, 0x203a, 0 },
153     { "kln",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
154     { "km",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
155     { "kn",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
156     { "ko",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
157     { "ksb",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
158     { "ksf",           0x00ab, 0x00bb, 0x2018, 0x2019, 0 },
159     { "lag",           0x201d, 0x201d, 0x2019, 0x2019, 0 },
160     { "lg",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
161     { "ln",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
162     { "lo",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
163     { "lt",            0x201e, 0x201c, 0x201e, 0x201c, 0 },
164     { "lu",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
165     { "luo",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
166     { "luy",           0x201e, 0x201c, 0x201a, 0x2018, 0 },
167     { "lv",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
168     { "mas",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
169     { "mer",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
170     { "mfe",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
171     { "mg",            0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
172     { "mgo",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
173     { "mk",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
174     { "ml",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
175     { "mr",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
176     { "ms",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
177     { "mua",           0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
178     { "my",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
179     { "naq",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
180     { "nb",            0x00ab, 0x00bb, 0x2018, 0x2019, 0 },
181     { "nd",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
182     { "nl",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
183     { "nmg",           0x201e, 0x201d, 0x00ab, 0x00bb, 0 },
184     { "nn",            0x00ab, 0x00bb, 0x2018, 0x2019, 0 },
185     { "nnh",           0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
186     { "nus",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
187     { "nyn",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
188     { "pl",            0x201e, 0x201d, 0x00ab, 0x00bb, 0 },
189     { "pt",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
190     { "pt-pt",         0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
191     { "rn",            0x201d, 0x201d, 0x2019, 0x2019, 0 },
192     { "ro",            0x201e, 0x201d, 0x00ab, 0x00bb, 0 },
193     { "rof",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
194     { "ru",            0x00ab, 0x00bb, 0x201e, 0x201c, 0 },
195     { "rw",            0x00ab, 0x00bb, 0x2018, 0x2019, 0 },
196     { "rwk",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
197     { "saq",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
198     { "sbp",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
199     { "seh",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
200     { "ses",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
201     { "sg",            0x00ab, 0x00bb, 0x201c, 0x201d, 0 },
202     { "shi",           0x00ab, 0x00bb, 0x201e, 0x201d, 0 },
203     { "shi-tfng",      0x00ab, 0x00bb, 0x201e, 0x201d, 0 },
204     { "si",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
205     { "sk",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
206     { "sl",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
207     { "sn",            0x201d, 0x201d, 0x2019, 0x2019, 0 },
208     { "so",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
209     { "sq",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
210     { "sr",            0x201e, 0x201c, 0x201a, 0x2018, 0 },
211     { "sr-latn",       0x201e, 0x201c, 0x201a, 0x2018, 0 },
212     { "sv",            0x201d, 0x201d, 0x2019, 0x2019, 0 },
213     { "sw",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
214     { "swc",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
215     { "ta",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
216     { "te",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
217     { "teo",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
218     { "th",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
219     { "ti-er",         0x2018, 0x2019, 0x201c, 0x201d, 0 },
220     { "to",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
221     { "tr",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
222     { "twq",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
223     { "tzm",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
224     { "uk",            0x00ab, 0x00bb, 0x201e, 0x201c, 0 },
225     { "ur",            0x201d, 0x201c, 0x2019, 0x2018, 0 },
226     { "vai",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
227     { "vai-latn",      0x201c, 0x201d, 0x2018, 0x2019, 0 },
228     { "vi",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
229     { "vun",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
230     { "xh",            0x2018, 0x2019, 0x201c, 0x201d, 0 },
231     { "xog",           0x201c, 0x201d, 0x2018, 0x2019, 0 },
232     { "yav",           0x00ab, 0x00bb, 0x00ab, 0x00bb, 0 },
233     { "yo",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
234     { "zh",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
235     { "zh-hant",       0x300c, 0x300d, 0x300e, 0x300f, 0 },
236     { "zu",            0x201c, 0x201d, 0x2018, 0x2019, 0 },
237 };
238
239 const QuotesData* quotesDataForLanguage(const AtomicString& lang)
240 {
241     if (lang.isNull())
242         return 0;
243
244     // This could be just a hash table, but doing that adds 200k to RenderQuote.o
245     Language* languagesEnd = languages + WTF_ARRAY_LENGTH(languages);
246     CString lowercaseLang = lang.string().lower().utf8();
247     Language key = { lowercaseLang.data(), 0, 0, 0, 0, 0 };
248     Language* match = std::lower_bound(languages, languagesEnd, key);
249     if (match == languagesEnd || strcmp(match->lang, key.lang))
250         return 0;
251
252     if (!match->data)
253         match->data = QuotesData::create(match->open1, match->close1, match->open2, match->close2).leakRef();
254
255     return match->data;
256 }
257
258 static const QuotesData* basicQuotesData()
259 {
260     // FIXME: The default quotes should be the fancy quotes for "en".
261     DEFINE_STATIC_REF(QuotesData, staticBasicQuotes, (QuotesData::create('"', '"', '\'', '\'')));
262     return staticBasicQuotes;
263 }
264
265 void RenderQuote::updateText()
266 {
267     String text = computeText();
268     if (m_text == text)
269         return;
270
271     m_text = text;
272
273     while (RenderObject* child = lastChild())
274         child->destroy();
275
276     RenderTextFragment* fragment = new RenderTextFragment(&document(), m_text.impl());
277     fragment->setStyle(style());
278     addChild(fragment);
279 }
280
281 String RenderQuote::computeText() const
282 {
283     switch (m_type) {
284     case NO_OPEN_QUOTE:
285     case NO_CLOSE_QUOTE:
286         return emptyString();
287     case CLOSE_QUOTE:
288         return quotesData()->getCloseQuote(m_depth - 1).impl();
289     case OPEN_QUOTE:
290         return quotesData()->getOpenQuote(m_depth).impl();
291     }
292     ASSERT_NOT_REACHED();
293     return emptyString();
294 }
295
296 const QuotesData* RenderQuote::quotesData() const
297 {
298     if (const QuotesData* customQuotes = style()->quotes())
299         return customQuotes;
300
301     if (const QuotesData* quotes = quotesDataForLanguage(style()->locale()))
302         return quotes;
303
304     return basicQuotesData();
305 }
306
307 void RenderQuote::attachQuote()
308 {
309     ASSERT(view());
310     ASSERT(!m_attached);
311     ASSERT(!m_next && !m_previous);
312     ASSERT(isRooted());
313
314     if (!view()->renderQuoteHead()) {
315         view()->setRenderQuoteHead(this);
316         m_attached = true;
317         return;
318     }
319
320     for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) {
321         // Skip unattached predecessors to avoid having stale m_previous pointers
322         // if the previous node is never attached and is then destroyed.
323         if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached())
324             continue;
325         m_previous = toRenderQuote(predecessor);
326         m_next = m_previous->m_next;
327         m_previous->m_next = this;
328         if (m_next)
329             m_next->m_previous = this;
330         break;
331     }
332
333     if (!m_previous) {
334         m_next = view()->renderQuoteHead();
335         view()->setRenderQuoteHead(this);
336         if (m_next)
337             m_next->m_previous = this;
338     }
339     m_attached = true;
340
341     for (RenderQuote* quote = this; quote; quote = quote->m_next)
342         quote->updateDepth();
343
344     ASSERT(!m_next || m_next->m_attached);
345     ASSERT(!m_next || m_next->m_previous == this);
346     ASSERT(!m_previous || m_previous->m_attached);
347     ASSERT(!m_previous || m_previous->m_next == this);
348 }
349
350 void RenderQuote::detachQuote()
351 {
352     ASSERT(!m_next || m_next->m_attached);
353     ASSERT(!m_previous || m_previous->m_attached);
354     if (!m_attached)
355         return;
356     if (m_previous)
357         m_previous->m_next = m_next;
358     else if (view())
359         view()->setRenderQuoteHead(m_next);
360     if (m_next)
361         m_next->m_previous = m_previous;
362     if (!documentBeingDestroyed()) {
363         for (RenderQuote* quote = m_next; quote; quote = quote->m_next)
364             quote->updateDepth();
365     }
366     m_attached = false;
367     m_next = nullptr;
368     m_previous = nullptr;
369     m_depth = 0;
370 }
371
372 void RenderQuote::updateDepth()
373 {
374     ASSERT(m_attached);
375     int oldDepth = m_depth;
376     m_depth = 0;
377     if (m_previous) {
378         m_depth = m_previous->m_depth;
379         switch (m_previous->m_type) {
380         case OPEN_QUOTE:
381         case NO_OPEN_QUOTE:
382             m_depth++;
383             break;
384         case CLOSE_QUOTE:
385         case NO_CLOSE_QUOTE:
386             if (m_depth)
387                 m_depth--;
388             break;
389         }
390     }
391     if (oldDepth != m_depth)
392         updateText();
393 }
394
395 } // namespace blink