| Index: Source/WebCore/rendering/RenderQuote.cpp
|
| ===================================================================
|
| --- Source/WebCore/rendering/RenderQuote.cpp (revision 127610)
|
| +++ Source/WebCore/rendering/RenderQuote.cpp (working copy)
|
| @@ -21,119 +21,34 @@
|
| #include "config.h"
|
| #include "RenderQuote.h"
|
|
|
| -#include "Document.h"
|
| -#include "QuotesData.h"
|
| -#include "RenderStyle.h"
|
| #include <wtf/text/AtomicString.h>
|
|
|
| -#define UNKNOWN_DEPTH -1
|
| +#define U(x) ((const UChar*)L##x)
|
|
|
| namespace WebCore {
|
| -static inline void adjustDepth(int &depth, QuoteType type)
|
| -{
|
| - switch (type) {
|
| - case OPEN_QUOTE:
|
| - case NO_OPEN_QUOTE:
|
| - ++depth;
|
| - break;
|
| - case CLOSE_QUOTE:
|
| - case NO_CLOSE_QUOTE:
|
| - if (depth)
|
| - --depth;
|
| - break;
|
| - default:
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| -}
|
|
|
| RenderQuote::RenderQuote(Document* node, QuoteType quote)
|
| : RenderText(node, StringImpl::empty())
|
| , m_type(quote)
|
| - , m_depth(UNKNOWN_DEPTH)
|
| + , m_depth(0)
|
| , m_next(0)
|
| , m_previous(0)
|
| + , m_attached(false)
|
| {
|
| - view()->addRenderQuote();
|
| }
|
|
|
| RenderQuote::~RenderQuote()
|
| {
|
| + ASSERT(!m_attached);
|
| + ASSERT(!m_next && !m_previous);
|
| }
|
|
|
| void RenderQuote::willBeDestroyed()
|
| {
|
| - if (view())
|
| - view()->removeRenderQuote();
|
| + detachQuote();
|
| RenderText::willBeDestroyed();
|
| }
|
|
|
| -const char* RenderQuote::renderName() const
|
| -{
|
| - return "RenderQuote";
|
| -}
|
| -
|
| -// This function places a list of quote renderers starting at "this" in the list of quote renderers already
|
| -// in the document's renderer tree.
|
| -// The assumptions are made (for performance):
|
| -// 1. The list of quotes already in the renderers tree of the document is already in a consistent state
|
| -// (All quote renderers are linked and have the correct depth set)
|
| -// 2. The quote renderers of the inserted list are in a tree of renderers of their own which has been just
|
| -// inserted in the main renderer tree with its root as child of some renderer.
|
| -// 3. The quote renderers in the inserted list have depths consistent with their position in the list relative
|
| -// to "this", thus if "this" does not need to change its depth upon insertion, the other renderers in the list don't
|
| -// need to either.
|
| -void RenderQuote::placeQuote()
|
| -{
|
| - RenderQuote* head = this;
|
| - ASSERT(!head->m_previous);
|
| - RenderQuote* tail = 0;
|
| - for (RenderObject* predecessor = head->previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) {
|
| - if (!predecessor->isQuote())
|
| - continue;
|
| - head->m_previous = toRenderQuote(predecessor);
|
| - if (head->m_previous->m_next) {
|
| - // We need to splice the list of quotes headed by head into the document's list of quotes.
|
| - tail = head;
|
| - while (tail->m_next)
|
| - tail = tail->m_next;
|
| - tail->m_next = head->m_previous->m_next;
|
| - ASSERT(tail->m_next->m_previous == head->m_previous);
|
| - tail->m_next->m_previous = tail;
|
| - tail = tail->m_next; // This marks the splicing point here there may be a depth discontinuity
|
| - }
|
| - head->m_previous->m_next = head;
|
| - ASSERT(head->m_previous->m_depth != UNKNOWN_DEPTH);
|
| - break;
|
| - }
|
| - int newDepth;
|
| - if (!head->m_previous) {
|
| - newDepth = 0;
|
| - goto skipNewDepthCalc;
|
| - }
|
| - newDepth = head->m_previous->m_depth;
|
| - do {
|
| - adjustDepth(newDepth, head->m_previous->m_type);
|
| -skipNewDepthCalc:
|
| - if (head->m_depth == newDepth) { // All remaining depth should be correct except if splicing was done.
|
| - if (!tail) // We've done the post splicing section already or there was no splicing.
|
| - break;
|
| - head = tail; // Continue after the splicing point
|
| - tail = 0; // Mark the possible splicing point discontinuity fixed.
|
| - newDepth = head->m_previous->m_depth;
|
| - continue;
|
| - }
|
| - head->m_depth = newDepth;
|
| - // FIXME: If the width and height of the quotation characters does not change we may only need to
|
| - // Invalidate the renderer's area not a relayout.
|
| - head->setNeedsLayoutAndPrefWidthsRecalc();
|
| - head = head->m_next;
|
| - if (head == tail) // We are at the splicing point
|
| - tail = 0; // Mark the possible depth discontinuity fixed.
|
| - } while (head);
|
| -}
|
| -
|
| -#define U(x) ((const UChar*)L##x)
|
| -
|
| typedef HashMap<AtomicString, const QuotesData*, CaseFoldingHash> QuotesMap;
|
|
|
| static const QuotesMap& quotesDataLanguageMap()
|
| @@ -157,27 +72,24 @@
|
|
|
| PassRefPtr<StringImpl> RenderQuote::originalText() const
|
| {
|
| - if (!parent())
|
| - return 0;
|
| - ASSERT(m_depth != UNKNOWN_DEPTH);
|
| - const QuotesData* quotes = quotesData();
|
| switch (m_type) {
|
| case NO_OPEN_QUOTE:
|
| case NO_CLOSE_QUOTE:
|
| return StringImpl::empty();
|
| case CLOSE_QUOTE:
|
| // FIXME: When m_depth is 0 we should return empty string.
|
| - return quotes->getCloseQuote(std::max(m_depth - 1, 0)).impl();
|
| + return quotesData()->getCloseQuote(std::max(m_depth - 1, 0)).impl();
|
| case OPEN_QUOTE:
|
| - return quotes->getOpenQuote(m_depth).impl();
|
| - default:
|
| - ASSERT_NOT_REACHED();
|
| - return StringImpl::empty();
|
| + return quotesData()->getOpenQuote(m_depth).impl();
|
| }
|
| + ASSERT_NOT_REACHED();
|
| + return StringImpl::empty();
|
| }
|
|
|
| void RenderQuote::computePreferredLogicalWidths(float lead)
|
| {
|
| + if (!m_attached)
|
| + attachQuote();
|
| setTextInternal(originalText());
|
| RenderText::computePreferredLogicalWidths(lead);
|
| }
|
| @@ -196,58 +108,98 @@
|
| return quotes;
|
| }
|
|
|
| -void RenderQuote::rendererSubtreeAttached(RenderObject* renderer)
|
| +void RenderQuote::attachQuote()
|
| {
|
| - ASSERT(renderer->view());
|
| - if (!renderer->view()->hasRenderQuotes())
|
| + ASSERT(view());
|
| + ASSERT(!m_attached);
|
| + ASSERT(!m_next && !m_previous);
|
| +
|
| + // FIXME: Don't set pref widths dirty during layout. See updateDepth() for
|
| + // more detail.
|
| + if (!isRooted()) {
|
| + setNeedsLayoutAndPrefWidthsRecalc();
|
| return;
|
| - for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
|
| - if (descendant->isQuote()) {
|
| - toRenderQuote(descendant)->placeQuote();
|
| - break;
|
| - }
|
| + }
|
| +
|
| + if (!view()->renderQuoteHead()) {
|
| + view()->setRenderQuoteHead(this);
|
| + m_attached = true;
|
| + return;
|
| + }
|
| +
|
| + for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) {
|
| + // Skip unattached predecessors to avoid having stale m_previous pointers
|
| + // if the previous node is never attached and is then destroyed.
|
| + if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached())
|
| + continue;
|
| + m_previous = toRenderQuote(predecessor);
|
| + m_next = m_previous->m_next;
|
| + m_previous->m_next = this;
|
| + if (m_next)
|
| + m_next->m_previous = this;
|
| + break;
|
| + }
|
| +
|
| + if (!m_previous) {
|
| + m_next = view()->renderQuoteHead();
|
| + view()->setRenderQuoteHead(this);
|
| + }
|
| + m_attached = true;
|
| +
|
| + for (RenderQuote* quote = this; quote; quote = quote->m_next)
|
| + quote->updateDepth();
|
| +
|
| + ASSERT(!m_next || m_next->m_attached);
|
| + ASSERT(!m_previous || m_previous->m_attached);
|
| }
|
|
|
| -void RenderQuote::rendererRemovedFromTree(RenderObject* renderer)
|
| +void RenderQuote::detachQuote()
|
| {
|
| - ASSERT(renderer->view());
|
| - if (!renderer->view()->hasRenderQuotes())
|
| + ASSERT(!m_next || m_next->m_attached);
|
| + ASSERT(!m_previous || m_previous->m_attached);
|
| + if (!m_attached)
|
| return;
|
| - for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
|
| - if (descendant->isQuote()) {
|
| - RenderQuote* removedQuote = toRenderQuote(descendant);
|
| - RenderQuote* lastQuoteBefore = removedQuote->m_previous;
|
| - removedQuote->m_previous = 0;
|
| - int depth = removedQuote->m_depth;
|
| - for (descendant = descendant->nextInPreOrder(renderer); descendant; descendant = descendant->nextInPreOrder(renderer))
|
| - if (descendant->isQuote())
|
| - removedQuote = toRenderQuote(descendant);
|
| - RenderQuote* quoteAfter = removedQuote->m_next;
|
| - removedQuote->m_next = 0;
|
| - if (lastQuoteBefore)
|
| - lastQuoteBefore->m_next = quoteAfter;
|
| - if (quoteAfter) {
|
| - quoteAfter->m_previous = lastQuoteBefore;
|
| - do {
|
| - if (depth == quoteAfter->m_depth)
|
| - break;
|
| - quoteAfter->m_depth = depth;
|
| - quoteAfter->setNeedsLayoutAndPrefWidthsRecalc();
|
| - adjustDepth(depth, quoteAfter->m_type);
|
| - quoteAfter = quoteAfter->m_next;
|
| - } while (quoteAfter);
|
| - }
|
| - break;
|
| - }
|
| + if (m_previous)
|
| + m_previous->m_next = m_next;
|
| + else if (view())
|
| + view()->setRenderQuoteHead(m_next);
|
| + if (m_next)
|
| + m_next->m_previous = m_previous;
|
| + if (!documentBeingDestroyed()) {
|
| + for (RenderQuote* quote = m_next; quote; quote = quote->m_next)
|
| + quote->updateDepth();
|
| + }
|
| + m_attached = false;
|
| + m_next = 0;
|
| + m_previous = 0;
|
| + m_depth = 0;
|
| }
|
|
|
| -void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
|
| +void RenderQuote::updateDepth()
|
| {
|
| - const QuotesData* newQuotes = style()->quotes();
|
| - const QuotesData* oldQuotes = oldStyle ? oldStyle->quotes() : 0;
|
| - if (!QuotesData::equals(newQuotes, oldQuotes))
|
| + ASSERT(m_attached);
|
| + int oldDepth = m_depth;
|
| + m_depth = 0;
|
| + if (m_previous) {
|
| + m_depth = m_previous->m_depth;
|
| + switch (m_previous->m_type) {
|
| + case OPEN_QUOTE:
|
| + case NO_OPEN_QUOTE:
|
| + m_depth++;
|
| + break;
|
| + case CLOSE_QUOTE:
|
| + case NO_CLOSE_QUOTE:
|
| + if (m_depth)
|
| + m_depth--;
|
| + break;
|
| + }
|
| + }
|
| + // FIXME: Don't call setNeedsLayout or dirty our preferred widths during layout.
|
| + // This is likely to fail anyway as one of our ancestor will call setNeedsLayout(false),
|
| + // preventing the future layout to occur on |this|. The solution is to move that to a
|
| + // pre-layout phase.
|
| + if (oldDepth != m_depth)
|
| setNeedsLayoutAndPrefWidthsRecalc();
|
| - RenderText::styleDidChange(diff, oldStyle);
|
| }
|
|
|
| } // namespace WebCore
|
|
|