Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1750)

Unified Diff: Source/core/rendering/RenderNamedFlowThread.cpp

Issue 143323014: *** DO NOT LAND *** Attempt to understand Regions complexity Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderNamedFlowThread.h ('k') | Source/core/rendering/RenderObject.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderNamedFlowThread.cpp
diff --git a/Source/core/rendering/RenderNamedFlowThread.cpp b/Source/core/rendering/RenderNamedFlowThread.cpp
deleted file mode 100644
index 72049543c9d3b0b88133850de3438ec70017ebfe..0000000000000000000000000000000000000000
--- a/Source/core/rendering/RenderNamedFlowThread.cpp
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS IN..0TERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/rendering/RenderNamedFlowThread.h"
-
-#include "RuntimeEnabledFeatures.h"
-#include "bindings/v8/ExceptionStatePlaceholder.h"
-#include "core/dom/NamedFlow.h"
-#include "core/dom/NodeRenderingTraversal.h"
-#include "core/dom/NodeTraversal.h"
-#include "core/dom/Position.h"
-#include "core/dom/Range.h"
-#include "core/dom/Text.h"
-#include "core/inspector/InspectorInstrumentation.h"
-#include "core/rendering/FlowThreadController.h"
-#include "core/rendering/InlineTextBox.h"
-#include "core/rendering/RenderInline.h"
-#include "core/rendering/RenderRegion.h"
-#include "core/rendering/RenderText.h"
-#include "core/rendering/RenderView.h"
-
-namespace WebCore {
-
-RenderNamedFlowThread* RenderNamedFlowThread::createAnonymous(Document* document, PassRefPtr<NamedFlow> namedFlow)
-{
- ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
- RenderNamedFlowThread* renderer = new RenderNamedFlowThread(namedFlow);
- renderer->setDocumentForAnonymous(document);
- return renderer;
-}
-
-RenderNamedFlowThread::RenderNamedFlowThread(PassRefPtr<NamedFlow> namedFlow)
- : m_overset(true)
- , m_namedFlow(namedFlow)
- , m_regionLayoutUpdateEventTimer(this, &RenderNamedFlowThread::regionLayoutUpdateEventTimerFired)
- , m_regionOversetChangeEventTimer(this, &RenderNamedFlowThread::regionOversetChangeEventTimerFired)
-{
-}
-
-RenderNamedFlowThread::~RenderNamedFlowThread()
-{
- // The flow thread can be destroyed without unregistering the content nodes if the document is destroyed.
- // This can lead to problems because the nodes are still marked as belonging to a flow thread.
- clearContentNodes();
-
- // Also leave the NamedFlow object in a consistent state by calling mark for destruction.
- setMarkForDestruction();
-}
-
-const char* RenderNamedFlowThread::renderName() const
-{
- return "RenderNamedFlowThread";
-}
-
-void RenderNamedFlowThread::clearContentNodes()
-{
- for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) {
- Node* contentNode = *it;
-
- ASSERT(contentNode && contentNode->isElementNode());
- ASSERT(contentNode->inNamedFlow());
- ASSERT(contentNode->document() == document());
-
- contentNode->clearInNamedFlow();
- }
-
- m_contentNodes.clear();
-}
-
-void RenderNamedFlowThread::updateWritingMode()
-{
- RenderRegion* firstRegion = m_regionList.first();
- if (!firstRegion)
- return;
- if (style()->writingMode() == firstRegion->style()->writingMode())
- return;
-
- // The first region defines the principal writing mode for the entire flow.
- RefPtr<RenderStyle> newStyle = RenderStyle::clone(style());
- newStyle->setWritingMode(firstRegion->style()->writingMode());
- setStyle(newStyle.release());
-}
-
-RenderObject* RenderNamedFlowThread::nextRendererForNode(Node* node) const
-{
- FlowThreadChildList::const_iterator it = m_flowThreadChildList.begin();
- FlowThreadChildList::const_iterator end = m_flowThreadChildList.end();
-
- for (; it != end; ++it) {
- RenderObject* child = *it;
- ASSERT(child->node());
- unsigned short position = node->compareDocumentPosition(child->node());
- if (position & Node::DOCUMENT_POSITION_FOLLOWING)
- return child;
- }
-
- return 0;
-}
-
-RenderObject* RenderNamedFlowThread::previousRendererForNode(Node* node) const
-{
- if (m_flowThreadChildList.isEmpty())
- return 0;
-
- FlowThreadChildList::const_iterator begin = m_flowThreadChildList.begin();
- FlowThreadChildList::const_iterator end = m_flowThreadChildList.end();
- FlowThreadChildList::const_iterator it = end;
-
- do {
- --it;
- RenderObject* child = *it;
- ASSERT(child->node());
- unsigned short position = node->compareDocumentPosition(child->node());
- if (position & Node::DOCUMENT_POSITION_PRECEDING)
- return child;
- } while (it != begin);
-
- return 0;
-}
-
-void RenderNamedFlowThread::addFlowChild(RenderObject* newChild)
-{
- // The child list is used to sort the flow thread's children render objects
- // based on their corresponding nodes DOM order. The list is needed to avoid searching the whole DOM.
-
- Node* childNode = newChild->node();
-
- // Do not add anonymous objects.
- if (!childNode)
- return;
-
- ASSERT(childNode->isElementNode());
-
- RenderObject* beforeChild = nextRendererForNode(childNode);
- if (beforeChild)
- m_flowThreadChildList.insertBefore(beforeChild, newChild);
- else
- m_flowThreadChildList.add(newChild);
-}
-
-void RenderNamedFlowThread::removeFlowChild(RenderObject* child)
-{
- m_flowThreadChildList.remove(child);
-}
-
-bool RenderNamedFlowThread::dependsOn(RenderNamedFlowThread* otherRenderFlowThread) const
-{
- if (m_layoutBeforeThreadsSet.contains(otherRenderFlowThread))
- return true;
-
- // Recursively traverse the m_layoutBeforeThreadsSet.
- RenderNamedFlowThreadCountedSet::const_iterator iterator = m_layoutBeforeThreadsSet.begin();
- RenderNamedFlowThreadCountedSet::const_iterator end = m_layoutBeforeThreadsSet.end();
- for (; iterator != end; ++iterator) {
- const RenderNamedFlowThread* beforeFlowThread = (*iterator).key;
- if (beforeFlowThread->dependsOn(otherRenderFlowThread))
- return true;
- }
-
- return false;
-}
-
-// Compare two regions to determine in which one the content should flow first.
-// The function returns true if the first passed region is "less" than the second passed region.
-// If the first region appears before second region in DOM,
-// the first region is "less" than the second region.
-// If the first region is "less" than the second region, the first region receives content before second region.
-static bool compareRenderRegions(const RenderRegion* firstRegion, const RenderRegion* secondRegion)
-{
- ASSERT(firstRegion);
- ASSERT(secondRegion);
-
- ASSERT(firstRegion->generatingNodeForRegion());
- ASSERT(secondRegion->generatingNodeForRegion());
-
- // If the regions belong to different nodes, compare their position in the DOM.
- if (firstRegion->generatingNodeForRegion() != secondRegion->generatingNodeForRegion()) {
- unsigned short position = firstRegion->generatingNodeForRegion()->compareDocumentPosition(secondRegion->generatingNodeForRegion());
-
- // If the second region is contained in the first one, the first region is "less" if it's :before.
- if (position & Node::DOCUMENT_POSITION_CONTAINED_BY) {
- ASSERT(secondRegion->style()->styleType() == NOPSEUDO);
- return firstRegion->style()->styleType() == BEFORE;
- }
-
- // If the second region contains the first region, the first region is "less" if the second is :after.
- if (position & Node::DOCUMENT_POSITION_CONTAINS) {
- ASSERT(firstRegion->style()->styleType() == NOPSEUDO);
- return secondRegion->style()->styleType() == AFTER;
- }
-
- return (position & Node::DOCUMENT_POSITION_FOLLOWING);
- }
-
- // FIXME: Currently it's not possible for an element to be both a region and have pseudo-children. The case is covered anyway.
- switch (firstRegion->style()->styleType()) {
- case BEFORE:
- // The second region can be the node or the after pseudo-element (before is smaller than any of those).
- return true;
- case AFTER:
- // The second region can be the node or the before pseudo-element (after is greater than any of those).
- return false;
- case NOPSEUDO:
- // The second region can either be the before or the after pseudo-element (the node is only smaller than the after pseudo-element).
- return firstRegion->style()->styleType() == AFTER;
- default:
- break;
- }
-
- ASSERT_NOT_REACHED();
- return true;
-}
-
-// This helper function adds a region to a list preserving the order property of the list.
-static void addRegionToList(RenderRegionList& regionList, RenderRegion* renderRegion)
-{
- if (regionList.isEmpty()) {
- regionList.add(renderRegion);
- } else {
- // Find the first region "greater" than renderRegion.
- RenderRegionList::iterator it = regionList.begin();
- while (it != regionList.end() && !compareRenderRegions(renderRegion, *it))
- ++it;
- regionList.insertBefore(it, renderRegion);
- }
-}
-
-void RenderNamedFlowThread::addRegionToNamedFlowThread(RenderRegion* renderRegion)
-{
- ASSERT(renderRegion);
- ASSERT(!renderRegion->isValid());
-
- if (renderRegion->parentNamedFlowThread())
- addDependencyOnFlowThread(renderRegion->parentNamedFlowThread());
-
- renderRegion->setIsValid(true);
- addRegionToList(m_regionList, renderRegion);
-
- if (m_regionList.first() == renderRegion)
- updateWritingMode();
-}
-
-void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
-{
- ASSERT(renderRegion);
- ASSERT(!renderRegion->isValid());
-
- resetMarkForDestruction();
-
- if (renderRegion->parentNamedFlowThread() && renderRegion->parentNamedFlowThread()->dependsOn(this)) {
- // The order of invalid regions is irrelevant.
- m_invalidRegionList.add(renderRegion);
- // Register ourself to get a notification when the state changes.
- renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this);
- return;
- }
-
- addRegionToNamedFlowThread(renderRegion);
-
- invalidateRegions();
-}
-
-void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
-{
- ASSERT(renderRegion);
-
- if (renderRegion->parentNamedFlowThread()) {
- if (!renderRegion->isValid()) {
- ASSERT(m_invalidRegionList.contains(renderRegion));
- m_invalidRegionList.remove(renderRegion);
- renderRegion->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
- // No need to invalidate the regions rectangles. The removed region
- // was not taken into account. Just return here.
- return;
- }
- removeDependencyOnFlowThread(renderRegion->parentNamedFlowThread());
- }
-
- ASSERT(m_regionList.contains(renderRegion));
- bool wasFirst = m_regionList.first() == renderRegion;
- m_regionList.remove(renderRegion);
-
- if (canBeDestroyed())
- setMarkForDestruction();
-
- // After removing all the regions in the flow the following layout needs to dispatch the regionLayoutUpdate event
- if (m_regionList.isEmpty())
- setDispatchRegionLayoutUpdateEvent(true);
- else if (wasFirst)
- updateWritingMode();
-
- invalidateRegions();
-}
-
-void RenderNamedFlowThread::regionChangedWritingMode(RenderRegion* region)
-{
- if (m_regionList.first() == region)
- updateWritingMode();
-}
-
-void RenderNamedFlowThread::computeOversetStateForRegions(LayoutUnit oldClientAfterEdge)
-{
- LayoutUnit height = oldClientAfterEdge;
-
- // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread)
- // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow
- // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height).
- // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region)
- if (hasRenderOverflow()
- && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY())
- || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX())))
- height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX();
-
- RenderRegion* lastReg = lastRegion();
- for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
- RenderRegion* region = *iter;
- LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x());
- LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX());
- RegionOversetState previousState = region->regionOversetState();
- RegionOversetState state = RegionFit;
- if (flowMin <= 0)
- state = RegionEmpty;
- if (flowMax > 0 && region == lastReg)
- state = RegionOverset;
- region->setRegionOversetState(state);
- // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event
- // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually
- // changed, so it just assumes that the NamedFlow should dispatch the event
- if (previousState != state
- || state == RegionFit
- || state == RegionOverset)
- setDispatchRegionLayoutUpdateEvent(true);
-
- if (previousState != state)
- setDispatchRegionOversetChangeEvent(true);
- }
-
- // If the number of regions has changed since we last computed the overset property, schedule the regionOversetChange event.
- if (previousRegionCountChanged()) {
- setDispatchRegionOversetChangeEvent(true);
- updatePreviousRegionCount();
- }
-
- // With the regions overflow state computed we can also set the overset flag for the named flow.
- // If there are no valid regions in the chain, overset is true.
- m_overset = lastReg ? lastReg->regionOversetState() == RegionOverset : true;
-}
-
-void RenderNamedFlowThread::checkInvalidRegions()
-{
- Vector<RenderRegion*> newValidRegions;
- for (RenderRegionList::iterator iter = m_invalidRegionList.begin(); iter != m_invalidRegionList.end(); ++iter) {
- RenderRegion* region = *iter;
- // The only reason a region would be invalid is because it has a parent flow thread.
- ASSERT(!region->isValid() && region->parentNamedFlowThread());
- if (region->parentNamedFlowThread()->dependsOn(this))
- continue;
-
- newValidRegions.append(region);
- }
-
- for (Vector<RenderRegion*>::iterator iter = newValidRegions.begin(); iter != newValidRegions.end(); ++iter) {
- RenderRegion* region = *iter;
- m_invalidRegionList.remove(region);
- region->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
- addRegionToNamedFlowThread(region);
- }
-
- if (!newValidRegions.isEmpty())
- invalidateRegions();
-
- if (m_observerThreadsSet.isEmpty())
- return;
-
- // Notify all the flow threads that were dependent on this flow.
-
- // Create a copy of the list first. That's because observers might change the list when calling checkInvalidRegions.
- Vector<RenderNamedFlowThread*> observers;
- copyToVector(m_observerThreadsSet, observers);
-
- for (size_t i = 0; i < observers.size(); ++i) {
- RenderNamedFlowThread* flowThread = observers.at(i);
- flowThread->checkInvalidRegions();
- }
-}
-
-void RenderNamedFlowThread::addDependencyOnFlowThread(RenderNamedFlowThread* otherFlowThread)
-{
- RenderNamedFlowThreadCountedSet::AddResult result = m_layoutBeforeThreadsSet.add(otherFlowThread);
- if (result.isNewEntry) {
- // This is the first time we see this dependency. Make sure we recalculate all the dependencies.
- view()->flowThreadController()->setIsRenderNamedFlowThreadOrderDirty(true);
- }
-}
-
-void RenderNamedFlowThread::removeDependencyOnFlowThread(RenderNamedFlowThread* otherFlowThread)
-{
- bool removed = m_layoutBeforeThreadsSet.remove(otherFlowThread);
- if (removed) {
- checkInvalidRegions();
- view()->flowThreadController()->setIsRenderNamedFlowThreadOrderDirty(true);
- }
-}
-
-void RenderNamedFlowThread::pushDependencies(RenderNamedFlowThreadList& list)
-{
- for (RenderNamedFlowThreadCountedSet::iterator iter = m_layoutBeforeThreadsSet.begin(); iter != m_layoutBeforeThreadsSet.end(); ++iter) {
- RenderNamedFlowThread* flowThread = (*iter).key;
- if (list.contains(flowThread))
- continue;
- flowThread->pushDependencies(list);
- list.add(flowThread);
- }
-}
-
-// The content nodes list contains those nodes with -webkit-flow-into: flow.
-// An element with display:none should also be listed among those nodes.
-// The list of nodes is ordered.
-void RenderNamedFlowThread::registerNamedFlowContentNode(Node* contentNode)
-{
- ASSERT(contentNode && contentNode->isElementNode());
- ASSERT(contentNode->document() == document());
-
- contentNode->setInNamedFlow();
-
- resetMarkForDestruction();
-
- // Find the first content node following the new content node.
- for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) {
- Node* node = *it;
- unsigned short position = contentNode->compareDocumentPosition(node);
- if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
- m_contentNodes.insertBefore(node, contentNode);
- return;
- }
- }
- m_contentNodes.add(contentNode);
-}
-
-void RenderNamedFlowThread::unregisterNamedFlowContentNode(Node* contentNode)
-{
- ASSERT(contentNode && contentNode->isElementNode());
- ASSERT(m_contentNodes.contains(contentNode));
- ASSERT(contentNode->inNamedFlow());
- ASSERT(contentNode->document() == document());
-
- contentNode->clearInNamedFlow();
- m_contentNodes.remove(contentNode);
-
- if (canBeDestroyed())
- setMarkForDestruction();
-}
-
-const AtomicString& RenderNamedFlowThread::flowThreadName() const
-{
- return m_namedFlow->name();
-}
-
-bool RenderNamedFlowThread::isChildAllowed(RenderObject* child, RenderStyle* style) const
-{
- if (!child->node())
- return true;
-
- ASSERT(child->node()->isElementNode());
- Node* originalParent = NodeRenderingTraversal::parent(child->node());
- if (!originalParent || !originalParent->renderer())
- return true;
-
- return originalParent->renderer()->isChildAllowed(child, style);
-}
-
-void RenderNamedFlowThread::dispatchRegionLayoutUpdateEvent()
-{
- RenderFlowThread::dispatchRegionLayoutUpdateEvent();
- InspectorInstrumentation::didUpdateRegionLayout(&document(), m_namedFlow.get());
-
- if (!m_regionLayoutUpdateEventTimer.isActive() && m_namedFlow->hasEventListeners())
- m_regionLayoutUpdateEventTimer.startOneShot(0);
-}
-
-void RenderNamedFlowThread::dispatchRegionOversetChangeEvent()
-{
- RenderFlowThread::dispatchRegionOversetChangeEvent();
- InspectorInstrumentation::didChangeRegionOverset(&document(), m_namedFlow.get());
-
- if (!m_regionOversetChangeEventTimer.isActive() && m_namedFlow->hasEventListeners())
- m_regionOversetChangeEventTimer.startOneShot(0);
-}
-
-void RenderNamedFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*)
-{
- ASSERT(m_namedFlow);
-
- m_namedFlow->dispatchRegionLayoutUpdateEvent();
-}
-
-void RenderNamedFlowThread::regionOversetChangeEventTimerFired(Timer<RenderNamedFlowThread>*)
-{
- ASSERT(m_namedFlow);
-
- m_namedFlow->dispatchRegionOversetChangeEvent();
-}
-
-void RenderNamedFlowThread::setMarkForDestruction()
-{
- if (m_namedFlow->flowState() == NamedFlow::FlowStateNull)
- return;
-
- m_namedFlow->setRenderer(0);
- // After this call ends, the renderer can be safely destroyed.
- // The NamedFlow object may outlive its renderer if it's referenced from a script and may be reatached to one if the named flow is recreated in the stylesheet.
-}
-
-void RenderNamedFlowThread::resetMarkForDestruction()
-{
- if (m_namedFlow->flowState() == NamedFlow::FlowStateCreated)
- return;
-
- m_namedFlow->setRenderer(this);
-}
-
-bool RenderNamedFlowThread::isMarkedForDestruction() const
-{
- // Flow threads in the "NULL" state can be destroyed.
- return m_namedFlow->flowState() == NamedFlow::FlowStateNull;
-}
-
-static bool isContainedInNodes(Vector<Node*> others, Node* node)
-{
- for (size_t i = 0; i < others.size(); i++) {
- Node* other = others.at(i);
- if (other->contains(node))
- return true;
- }
- return false;
-}
-
-static bool boxIntersectsRegion(LayoutUnit logicalTopForBox, LayoutUnit logicalBottomForBox, LayoutUnit logicalTopForRegion, LayoutUnit logicalBottomForRegion)
-{
- bool regionIsEmpty = logicalBottomForRegion != LayoutUnit::max() && logicalTopForRegion != LayoutUnit::min()
- && (logicalBottomForRegion - logicalTopForRegion) <= 0;
- return (logicalBottomForBox - logicalTopForBox) > 0
- && !regionIsEmpty
- && logicalTopForBox < logicalBottomForRegion && logicalTopForRegion < logicalBottomForBox;
-}
-
-// Retrieve the next node to be visited while computing the ranges inside a region.
-static Node* nextNodeInsideContentNode(const Node& currNode, const Node* contentNode)
-{
- ASSERT(contentNode && contentNode->inNamedFlow());
-
- if (currNode.renderer() && currNode.renderer()->isSVGRoot())
- return NodeTraversal::nextSkippingChildren(currNode, contentNode);
- return NodeTraversal::next(currNode, contentNode);
-}
-
-void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, const RenderRegion* region) const
-{
- LayoutUnit logicalTopForRegion;
- LayoutUnit logicalBottomForRegion;
-
- // extend the first region top to contain everything up to its logical height
- if (region->isFirstRegion())
- logicalTopForRegion = LayoutUnit::min();
- else
- logicalTopForRegion = region->logicalTopForFlowThreadContent();
-
- // extend the last region to contain everything above its y()
- if (region->isLastRegion())
- logicalBottomForRegion = LayoutUnit::max();
- else
- logicalBottomForRegion = region->logicalBottomForFlowThreadContent();
-
- Vector<Node*> nodes;
- // eliminate the contentNodes that are descendants of other contentNodes
- for (NamedFlowContentNodes::const_iterator it = contentNodes().begin(); it != contentNodes().end(); ++it) {
- Node* node = *it;
- if (!isContainedInNodes(nodes, node))
- nodes.append(node);
- }
-
- for (size_t i = 0; i < nodes.size(); i++) {
- Node* contentNode = nodes.at(i);
- if (!contentNode->renderer())
- continue;
-
- RefPtr<Range> range = Range::create(contentNode->document());
- bool foundStartPosition = false;
- bool startsAboveRegion = true;
- bool endsBelowRegion = true;
- bool skipOverOutsideNodes = false;
- Node* lastEndNode = 0;
-
- for (Node* node = contentNode; node; node = nextNodeInsideContentNode(*node, contentNode)) {
- RenderObject* renderer = node->renderer();
- if (!renderer)
- continue;
-
- LayoutRect boundingBox;
- if (renderer->isRenderInline()) {
- boundingBox = toRenderInline(renderer)->linesBoundingBox();
- } else if (renderer->isText()) {
- boundingBox = toRenderText(renderer)->linesBoundingBox();
- } else {
- boundingBox = toRenderBox(renderer)->frameRect();
- if (toRenderBox(renderer)->isRelPositioned())
- boundingBox.move(toRenderBox(renderer)->relativePositionLogicalOffset());
- }
-
- LayoutUnit offsetTop = renderer->containingBlock()->offsetFromLogicalTopOfFirstPage();
- const LayoutPoint logicalOffsetFromTop(isHorizontalWritingMode() ? LayoutUnit() : offsetTop,
- isHorizontalWritingMode() ? offsetTop : LayoutUnit());
-
- boundingBox.moveBy(logicalOffsetFromTop);
-
- LayoutUnit logicalTopForRenderer = region->logicalTopOfFlowThreadContentRect(boundingBox);
- LayoutUnit logicalBottomForRenderer = region->logicalBottomOfFlowThreadContentRect(boundingBox);
-
- // if the bounding box of the current element doesn't intersect the region box
- // close the current range only if the start element began inside the region,
- // otherwise just move the start position after this node and keep skipping them until we found a proper start position.
- if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) {
- if (foundStartPosition) {
- if (!startsAboveRegion) {
- if (range->intersectsNode(node, IGNORE_EXCEPTION))
- range->setEndBefore(node, IGNORE_EXCEPTION);
- rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION));
- range = Range::create(contentNode->document());
- startsAboveRegion = true;
- } else {
- skipOverOutsideNodes = true;
- }
- }
- if (skipOverOutsideNodes)
- range->setStartAfter(node, IGNORE_EXCEPTION);
- foundStartPosition = false;
- continue;
- }
-
- // start position
- if (logicalTopForRenderer < logicalTopForRegion && startsAboveRegion) {
- if (renderer->isText()) { // Text crosses region top
- // for Text elements, just find the last textbox that is contained inside the region and use its start() offset as start position
- RenderText* textRenderer = toRenderText(renderer);
- for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
- if (offsetTop + box->logicalBottom() < logicalTopForRegion)
- continue;
- range->setStart(Position(toText(node), box->start()));
- startsAboveRegion = false;
- break;
- }
- } else { // node crosses region top
- // for all elements, except Text, just set the start position to be before their children
- startsAboveRegion = true;
- range->setStart(Position(node, Position::PositionIsBeforeChildren));
- }
- } else { // node starts inside region
- // for elements that start inside the region, set the start position to be before them. If we found one, we will just skip the others until
- // the range is closed.
- if (startsAboveRegion) {
- startsAboveRegion = false;
- range->setStartBefore(node, IGNORE_EXCEPTION);
- }
- }
- skipOverOutsideNodes = false;
- foundStartPosition = true;
-
- // end position
- if (logicalBottomForRegion < logicalBottomForRenderer && (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode)))) {
- // for Text elements, just find just find the last textbox that is contained inside the region and use its start()+len() offset as end position
- if (renderer->isText()) { // Text crosses region bottom
- RenderText* textRenderer = toRenderText(renderer);
- InlineTextBox* lastBox = 0;
- for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
- if ((offsetTop + box->logicalTop()) < logicalBottomForRegion) {
- lastBox = box;
- continue;
- }
- ASSERT(lastBox);
- if (lastBox)
- range->setEnd(Position(toText(node), lastBox->start() + lastBox->len()));
- break;
- }
- endsBelowRegion = false;
- lastEndNode = node;
- } else { // node crosses region bottom
- // for all elements, except Text, just set the start position to be after their children
- range->setEnd(Position(node, Position::PositionIsAfterChildren));
- endsBelowRegion = true;
- lastEndNode = node;
- }
- } else { // node ends inside region
- // for elements that ends inside the region, set the end position to be after them
- // allow this end position to be changed only by other elements that are not descendants of the current end node
- if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) {
- range->setEndAfter(node, IGNORE_EXCEPTION);
- endsBelowRegion = false;
- lastEndNode = node;
- }
- }
- }
- if (foundStartPosition || skipOverOutsideNodes)
- rangeObjects.append(range);
- }
-}
-
-}
« no previous file with comments | « Source/core/rendering/RenderNamedFlowThread.h ('k') | Source/core/rendering/RenderObject.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698