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