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