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/layout/LayoutQuote.h" |
24 | 24 |
25 #include "core/rendering/RenderTextFragment.h" | 25 #include "core/rendering/RenderTextFragment.h" |
26 #include "core/rendering/RenderView.h" | 26 #include "core/rendering/RenderView.h" |
27 #include "wtf/StdLibExtras.h" | 27 #include "wtf/StdLibExtras.h" |
28 #include "wtf/text/AtomicString.h" | 28 #include "wtf/text/AtomicString.h" |
29 | 29 |
30 #include <algorithm> | 30 #include <algorithm> |
31 | 31 |
32 namespace blink { | 32 namespace blink { |
33 | 33 |
34 RenderQuote::RenderQuote(Document* node, QuoteType quote) | 34 LayoutQuote::LayoutQuote(Document* node, QuoteType quote) |
35 : RenderInline(0) | 35 : RenderInline(0) |
36 , m_type(quote) | 36 , m_type(quote) |
37 , m_depth(0) | 37 , m_depth(0) |
38 , m_next(nullptr) | 38 , m_next(nullptr) |
39 , m_previous(nullptr) | 39 , m_previous(nullptr) |
40 , m_attached(false) | 40 , m_attached(false) |
41 { | 41 { |
42 setDocumentForAnonymous(node); | 42 setDocumentForAnonymous(node); |
43 } | 43 } |
44 | 44 |
45 RenderQuote::~RenderQuote() | 45 LayoutQuote::~LayoutQuote() |
46 { | 46 { |
47 ASSERT(!m_attached); | 47 ASSERT(!m_attached); |
48 ASSERT(!m_next && !m_previous); | 48 ASSERT(!m_next && !m_previous); |
49 } | 49 } |
50 | 50 |
51 void RenderQuote::willBeDestroyed() | 51 void LayoutQuote::willBeDestroyed() |
52 { | 52 { |
53 detachQuote(); | 53 detachQuote(); |
54 RenderInline::willBeDestroyed(); | 54 RenderInline::willBeDestroyed(); |
55 } | 55 } |
56 | 56 |
57 void RenderQuote::willBeRemovedFromTree() | 57 void LayoutQuote::willBeRemovedFromTree() |
58 { | 58 { |
59 RenderInline::willBeRemovedFromTree(); | 59 RenderInline::willBeRemovedFromTree(); |
60 detachQuote(); | 60 detachQuote(); |
61 } | 61 } |
62 | 62 |
63 void RenderQuote::styleDidChange(StyleDifference diff, const LayoutStyle* oldSty
le) | 63 void LayoutQuote::styleDidChange(StyleDifference diff, const LayoutStyle* oldSty
le) |
64 { | 64 { |
65 RenderInline::styleDidChange(diff, oldStyle); | 65 RenderInline::styleDidChange(diff, oldStyle); |
66 updateText(); | 66 updateText(); |
67 } | 67 } |
68 | 68 |
69 struct Language { | 69 struct Language { |
70 const char* lang; | 70 const char* lang; |
71 UChar open1; | 71 UChar open1; |
72 UChar close1; | 72 UChar close1; |
73 UChar open2; | 73 UChar open2; |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 { "zh", 0x201c, 0x201d, 0x2018, 0x2019, 0 }, | 227 { "zh", 0x201c, 0x201d, 0x2018, 0x2019, 0 }, |
228 { "zh-hant", 0x300c, 0x300d, 0x300e, 0x300f, 0 }, | 228 { "zh-hant", 0x300c, 0x300d, 0x300e, 0x300f, 0 }, |
229 { "zu", 0x201c, 0x201d, 0x2018, 0x2019, 0 }, | 229 { "zu", 0x201c, 0x201d, 0x2018, 0x2019, 0 }, |
230 }; | 230 }; |
231 | 231 |
232 const QuotesData* quotesDataForLanguage(const AtomicString& lang) | 232 const QuotesData* quotesDataForLanguage(const AtomicString& lang) |
233 { | 233 { |
234 if (lang.isNull()) | 234 if (lang.isNull()) |
235 return 0; | 235 return 0; |
236 | 236 |
237 // This could be just a hash table, but doing that adds 200k to RenderQuote.
o | 237 // This could be just a hash table, but doing that adds 200k to LayoutQuote.
o |
238 Language* languagesEnd = languages + WTF_ARRAY_LENGTH(languages); | 238 Language* languagesEnd = languages + WTF_ARRAY_LENGTH(languages); |
239 CString lowercaseLang = lang.lower().utf8(); | 239 CString lowercaseLang = lang.lower().utf8(); |
240 Language key = { lowercaseLang.data(), 0, 0, 0, 0, 0 }; | 240 Language key = { lowercaseLang.data(), 0, 0, 0, 0, 0 }; |
241 Language* match = std::lower_bound(languages, languagesEnd, key); | 241 Language* match = std::lower_bound(languages, languagesEnd, key); |
242 if (match == languagesEnd || strcmp(match->lang, key.lang)) | 242 if (match == languagesEnd || strcmp(match->lang, key.lang)) |
243 return 0; | 243 return 0; |
244 | 244 |
245 if (!match->data) | 245 if (!match->data) |
246 match->data = QuotesData::create(match->open1, match->close1, match->ope
n2, match->close2).leakRef(); | 246 match->data = QuotesData::create(match->open1, match->close1, match->ope
n2, match->close2).leakRef(); |
247 | 247 |
248 return match->data; | 248 return match->data; |
249 } | 249 } |
250 | 250 |
251 static const QuotesData* basicQuotesData() | 251 static const QuotesData* basicQuotesData() |
252 { | 252 { |
253 // FIXME: The default quotes should be the fancy quotes for "en". | 253 // FIXME: The default quotes should be the fancy quotes for "en". |
254 DEFINE_STATIC_REF(QuotesData, staticBasicQuotes, (QuotesData::create('"', '"
', '\'', '\''))); | 254 DEFINE_STATIC_REF(QuotesData, staticBasicQuotes, (QuotesData::create('"', '"
', '\'', '\''))); |
255 return staticBasicQuotes; | 255 return staticBasicQuotes; |
256 } | 256 } |
257 | 257 |
258 void RenderQuote::updateText() | 258 void LayoutQuote::updateText() |
259 { | 259 { |
260 String text = computeText(); | 260 String text = computeText(); |
261 if (m_text == text) | 261 if (m_text == text) |
262 return; | 262 return; |
263 | 263 |
264 m_text = text; | 264 m_text = text; |
265 | 265 |
266 RenderTextFragment* fragment = findFragmentChild(); | 266 RenderTextFragment* fragment = findFragmentChild(); |
267 if (fragment) { | 267 if (fragment) { |
268 fragment->setStyle(style()); | 268 fragment->setStyle(style()); |
269 fragment->setContentString(m_text.impl()); | 269 fragment->setContentString(m_text.impl()); |
270 } else { | 270 } else { |
271 fragment = new RenderTextFragment(&document(), m_text.impl()); | 271 fragment = new RenderTextFragment(&document(), m_text.impl()); |
272 fragment->setStyle(style()); | 272 fragment->setStyle(style()); |
273 addChild(fragment); | 273 addChild(fragment); |
274 } | 274 } |
275 } | 275 } |
276 | 276 |
277 RenderTextFragment* RenderQuote::findFragmentChild() const | 277 RenderTextFragment* LayoutQuote::findFragmentChild() const |
278 { | 278 { |
279 // We walk from the end of the child list because, if we've had a first-lett
er | 279 // We walk from the end of the child list because, if we've had a first-lett
er |
280 // renderer inserted then the remaining text will be at the end. | 280 // renderer inserted then the remaining text will be at the end. |
281 while (LayoutObject* child = lastChild()) { | 281 while (LayoutObject* child = lastChild()) { |
282 if (child->isText() && toRenderText(child)->isTextFragment()) | 282 if (child->isText() && toRenderText(child)->isTextFragment()) |
283 return toRenderTextFragment(child); | 283 return toRenderTextFragment(child); |
284 } | 284 } |
285 | 285 |
286 return nullptr; | 286 return nullptr; |
287 } | 287 } |
288 | 288 |
289 String RenderQuote::computeText() const | 289 String LayoutQuote::computeText() const |
290 { | 290 { |
291 switch (m_type) { | 291 switch (m_type) { |
292 case NO_OPEN_QUOTE: | 292 case NO_OPEN_QUOTE: |
293 case NO_CLOSE_QUOTE: | 293 case NO_CLOSE_QUOTE: |
294 return emptyString(); | 294 return emptyString(); |
295 case CLOSE_QUOTE: | 295 case CLOSE_QUOTE: |
296 return quotesData()->getCloseQuote(m_depth - 1).impl(); | 296 return quotesData()->getCloseQuote(m_depth - 1).impl(); |
297 case OPEN_QUOTE: | 297 case OPEN_QUOTE: |
298 return quotesData()->getOpenQuote(m_depth).impl(); | 298 return quotesData()->getOpenQuote(m_depth).impl(); |
299 } | 299 } |
300 ASSERT_NOT_REACHED(); | 300 ASSERT_NOT_REACHED(); |
301 return emptyString(); | 301 return emptyString(); |
302 } | 302 } |
303 | 303 |
304 const QuotesData* RenderQuote::quotesData() const | 304 const QuotesData* LayoutQuote::quotesData() const |
305 { | 305 { |
306 if (const QuotesData* customQuotes = style()->quotes()) | 306 if (const QuotesData* customQuotes = style()->quotes()) |
307 return customQuotes; | 307 return customQuotes; |
308 | 308 |
309 if (const QuotesData* quotes = quotesDataForLanguage(style()->locale())) | 309 if (const QuotesData* quotes = quotesDataForLanguage(style()->locale())) |
310 return quotes; | 310 return quotes; |
311 | 311 |
312 return basicQuotesData(); | 312 return basicQuotesData(); |
313 } | 313 } |
314 | 314 |
315 void RenderQuote::attachQuote() | 315 void LayoutQuote::attachQuote() |
316 { | 316 { |
317 ASSERT(view()); | 317 ASSERT(view()); |
318 ASSERT(!m_attached); | 318 ASSERT(!m_attached); |
319 ASSERT(!m_next && !m_previous); | 319 ASSERT(!m_next && !m_previous); |
320 ASSERT(isRooted()); | 320 ASSERT(isRooted()); |
321 | 321 |
322 if (!view()->renderQuoteHead()) { | 322 if (!view()->layoutQuoteHead()) { |
323 view()->setRenderQuoteHead(this); | 323 view()->setLayoutQuoteHead(this); |
324 m_attached = true; | 324 m_attached = true; |
325 return; | 325 return; |
326 } | 326 } |
327 | 327 |
328 for (LayoutObject* predecessor = previousInPreOrder(); predecessor; predeces
sor = predecessor->previousInPreOrder()) { | 328 for (LayoutObject* predecessor = previousInPreOrder(); predecessor; predeces
sor = predecessor->previousInPreOrder()) { |
329 // Skip unattached predecessors to avoid having stale m_previous pointer
s | 329 // Skip unattached predecessors to avoid having stale m_previous pointer
s |
330 // if the previous node is never attached and is then destroyed. | 330 // if the previous node is never attached and is then destroyed. |
331 if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached()
) | 331 if (!predecessor->isQuote() || !toLayoutQuote(predecessor)->isAttached()
) |
332 continue; | 332 continue; |
333 m_previous = toRenderQuote(predecessor); | 333 m_previous = toLayoutQuote(predecessor); |
334 m_next = m_previous->m_next; | 334 m_next = m_previous->m_next; |
335 m_previous->m_next = this; | 335 m_previous->m_next = this; |
336 if (m_next) | 336 if (m_next) |
337 m_next->m_previous = this; | 337 m_next->m_previous = this; |
338 break; | 338 break; |
339 } | 339 } |
340 | 340 |
341 if (!m_previous) { | 341 if (!m_previous) { |
342 m_next = view()->renderQuoteHead(); | 342 m_next = view()->layoutQuoteHead(); |
343 view()->setRenderQuoteHead(this); | 343 view()->setLayoutQuoteHead(this); |
344 if (m_next) | 344 if (m_next) |
345 m_next->m_previous = this; | 345 m_next->m_previous = this; |
346 } | 346 } |
347 m_attached = true; | 347 m_attached = true; |
348 | 348 |
349 for (RenderQuote* quote = this; quote; quote = quote->m_next) | 349 for (LayoutQuote* quote = this; quote; quote = quote->m_next) |
350 quote->updateDepth(); | 350 quote->updateDepth(); |
351 | 351 |
352 ASSERT(!m_next || m_next->m_attached); | 352 ASSERT(!m_next || m_next->m_attached); |
353 ASSERT(!m_next || m_next->m_previous == this); | 353 ASSERT(!m_next || m_next->m_previous == this); |
354 ASSERT(!m_previous || m_previous->m_attached); | 354 ASSERT(!m_previous || m_previous->m_attached); |
355 ASSERT(!m_previous || m_previous->m_next == this); | 355 ASSERT(!m_previous || m_previous->m_next == this); |
356 } | 356 } |
357 | 357 |
358 void RenderQuote::detachQuote() | 358 void LayoutQuote::detachQuote() |
359 { | 359 { |
360 ASSERT(!m_next || m_next->m_attached); | 360 ASSERT(!m_next || m_next->m_attached); |
361 ASSERT(!m_previous || m_previous->m_attached); | 361 ASSERT(!m_previous || m_previous->m_attached); |
362 if (!m_attached) | 362 if (!m_attached) |
363 return; | 363 return; |
364 | 364 |
365 // Reset our attached status at this point because it's possible for | 365 // Reset our attached status at this point because it's possible for |
366 // updateDepth() to call into attachQuote(). Attach quote walks the render | 366 // updateDepth() to call into attachQuote(). Attach quote walks the render |
367 // tree looking for quotes that are attached and does work on them. | 367 // tree looking for quotes that are attached and does work on them. |
368 m_attached = false; | 368 m_attached = false; |
369 | 369 |
370 if (m_previous) | 370 if (m_previous) |
371 m_previous->m_next = m_next; | 371 m_previous->m_next = m_next; |
372 else if (view()) | 372 else if (view()) |
373 view()->setRenderQuoteHead(m_next); | 373 view()->setLayoutQuoteHead(m_next); |
374 if (m_next) | 374 if (m_next) |
375 m_next->m_previous = m_previous; | 375 m_next->m_previous = m_previous; |
376 if (!documentBeingDestroyed()) { | 376 if (!documentBeingDestroyed()) { |
377 for (RenderQuote* quote = m_next; quote; quote = quote->m_next) | 377 for (LayoutQuote* quote = m_next; quote; quote = quote->m_next) |
378 quote->updateDepth(); | 378 quote->updateDepth(); |
379 } | 379 } |
380 m_next = nullptr; | 380 m_next = nullptr; |
381 m_previous = nullptr; | 381 m_previous = nullptr; |
382 m_depth = 0; | 382 m_depth = 0; |
383 } | 383 } |
384 | 384 |
385 void RenderQuote::updateDepth() | 385 void LayoutQuote::updateDepth() |
386 { | 386 { |
387 ASSERT(m_attached); | 387 ASSERT(m_attached); |
388 int oldDepth = m_depth; | 388 int oldDepth = m_depth; |
389 m_depth = 0; | 389 m_depth = 0; |
390 if (m_previous) { | 390 if (m_previous) { |
391 m_depth = m_previous->m_depth; | 391 m_depth = m_previous->m_depth; |
392 switch (m_previous->m_type) { | 392 switch (m_previous->m_type) { |
393 case OPEN_QUOTE: | 393 case OPEN_QUOTE: |
394 case NO_OPEN_QUOTE: | 394 case NO_OPEN_QUOTE: |
395 m_depth++; | 395 m_depth++; |
396 break; | 396 break; |
397 case CLOSE_QUOTE: | 397 case CLOSE_QUOTE: |
398 case NO_CLOSE_QUOTE: | 398 case NO_CLOSE_QUOTE: |
399 if (m_depth) | 399 if (m_depth) |
400 m_depth--; | 400 m_depth--; |
401 break; | 401 break; |
402 } | 402 } |
403 } | 403 } |
404 if (oldDepth != m_depth) | 404 if (oldDepth != m_depth) |
405 updateText(); | 405 updateText(); |
406 } | 406 } |
407 | 407 |
408 } // namespace blink | 408 } // namespace blink |
OLD | NEW |