Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1. Redistributions of source code must retain the above
      9  *    copyright notice, this list of conditions and the following
     10  *    disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above
     12  *    copyright notice, this list of conditions and the following
     13  *    disclaimer in the documentation and/or other materials
     14  *    provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
     20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
     21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
     25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
     26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 
     32 #include "core/rendering/FlowThreadController.h"
     33 
     34 #include "core/dom/NamedFlowCollection.h"
     35 #include "core/rendering/RenderFlowThread.h"
     36 #include "core/rendering/RenderNamedFlowThread.h"
     37 #include "wtf/text/AtomicString.h"
     38 
     39 namespace WebCore {
     40 
     41 PassOwnPtr<FlowThreadController> FlowThreadController::create(RenderView* view)
     42 {
     43     return adoptPtr(new FlowThreadController(view));
     44 }
     45 
     46 FlowThreadController::FlowThreadController(RenderView* view)
     47     : m_view(view)
     48     , m_currentRenderFlowThread(0)
     49     , m_isRenderNamedFlowThreadOrderDirty(false)
     50     , m_flowThreadsWithAutoLogicalHeightRegions(0)
     51 {
     52 }
     53 
     54 FlowThreadController::~FlowThreadController()
     55 {
     56 }
     57 
     58 RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(const AtomicString& name)
     59 {
     60     if (!m_renderNamedFlowThreadList)
     61         m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList());
     62     else {
     63         for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
     64             RenderNamedFlowThread* flowRenderer = *iter;
     65             if (flowRenderer->flowThreadName() == name)
     66                 return flowRenderer;
     67         }
     68     }
     69 
     70     NamedFlowCollection* namedFlows = m_view->document().namedFlows();
     71 
     72     // Sanity check for the absence of a named flow in the "CREATED" state with the same name.
     73     ASSERT(!namedFlows->flowByName(name));
     74 
     75     RenderNamedFlowThread* flowRenderer = RenderNamedFlowThread::createAnonymous(&m_view->document(), namedFlows->ensureFlowWithName(name));
     76     flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style()));
     77     m_renderNamedFlowThreadList->add(flowRenderer);
     78 
     79     // Keep the flow renderer as a child of RenderView.
     80     m_view->addChild(flowRenderer);
     81 
     82     setIsRenderNamedFlowThreadOrderDirty(true);
     83 
     84     return flowRenderer;
     85 }
     86 
     87 void FlowThreadController::styleDidChange()
     88 {
     89     RenderStyle* viewStyle = m_view->style();
     90     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
     91         RenderNamedFlowThread* flowRenderer = *iter;
     92         flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(viewStyle));
     93     }
     94 }
     95 
     96 void FlowThreadController::layoutRenderNamedFlowThreads()
     97 {
     98     updateFlowThreadsChainIfNecessary();
     99 
    100     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    101         RenderNamedFlowThread* flowRenderer = *iter;
    102         flowRenderer->layoutIfNeeded();
    103     }
    104 }
    105 
    106 void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow)
    107 {
    108     ASSERT(contentNode && contentNode->isElementNode());
    109     ASSERT(namedFlow);
    110     ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode));
    111     ASSERT(!namedFlow->hasContentNode(contentNode));
    112     m_mapNamedFlowContentNodes.add(contentNode, namedFlow);
    113     namedFlow->registerNamedFlowContentNode(contentNode);
    114 }
    115 
    116 void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode)
    117 {
    118     ASSERT(contentNode && contentNode->isElementNode());
    119     HashMap<const Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode);
    120     ASSERT_WITH_SECURITY_IMPLICATION(it != m_mapNamedFlowContentNodes.end());
    121     ASSERT(it->value);
    122     ASSERT(it->value->hasContentNode(contentNode));
    123     it->value->unregisterNamedFlowContentNode(contentNode);
    124     m_mapNamedFlowContentNodes.remove(contentNode);
    125 }
    126 
    127 void FlowThreadController::updateFlowThreadsChainIfNecessary()
    128 {
    129     ASSERT(m_renderNamedFlowThreadList);
    130     ASSERT(isAutoLogicalHeightRegionsCountConsistent());
    131 
    132     // Remove the left-over flow threads.
    133     RenderNamedFlowThreadList toRemoveList;
    134     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    135         RenderNamedFlowThread* flowRenderer = *iter;
    136         if (flowRenderer->isMarkedForDestruction())
    137             toRemoveList.add(flowRenderer);
    138     }
    139 
    140     if (toRemoveList.size() > 0)
    141         setIsRenderNamedFlowThreadOrderDirty(true);
    142 
    143     for (RenderNamedFlowThreadList::iterator iter = toRemoveList.begin(); iter != toRemoveList.end(); ++iter) {
    144         RenderNamedFlowThread* flowRenderer = *iter;
    145         m_renderNamedFlowThreadList->remove(flowRenderer);
    146         flowRenderer->destroy();
    147     }
    148 
    149     if (isRenderNamedFlowThreadOrderDirty()) {
    150         // Arrange the thread list according to dependencies.
    151         RenderNamedFlowThreadList sortedList;
    152         for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    153             RenderNamedFlowThread* flowRenderer = *iter;
    154             if (sortedList.contains(flowRenderer))
    155                 continue;
    156             flowRenderer->pushDependencies(sortedList);
    157             sortedList.add(flowRenderer);
    158         }
    159         m_renderNamedFlowThreadList->swap(sortedList);
    160         setIsRenderNamedFlowThreadOrderDirty(false);
    161     }
    162 }
    163 
    164 bool FlowThreadController::updateFlowThreadsNeedingLayout()
    165 {
    166     bool needsTwoPassLayout = false;
    167 
    168     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    169         RenderNamedFlowThread* flowRenderer = *iter;
    170         ASSERT(!flowRenderer->needsTwoPhasesLayout());
    171         flowRenderer->setInConstrainedLayoutPhase(false);
    172         if (flowRenderer->needsLayout() && flowRenderer->hasAutoLogicalHeightRegions())
    173             needsTwoPassLayout = true;
    174     }
    175 
    176     if (needsTwoPassLayout)
    177         resetFlowThreadsWithAutoHeightRegions();
    178 
    179     return needsTwoPassLayout;
    180 }
    181 
    182 bool FlowThreadController::updateFlowThreadsNeedingTwoStepLayout()
    183 {
    184     bool needsTwoPassLayout = false;
    185 
    186     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    187         RenderNamedFlowThread* flowRenderer = *iter;
    188         if (flowRenderer->needsTwoPhasesLayout()) {
    189             needsTwoPassLayout = true;
    190             break;
    191         }
    192     }
    193 
    194     if (needsTwoPassLayout)
    195         resetFlowThreadsWithAutoHeightRegions();
    196 
    197     return needsTwoPassLayout;
    198 }
    199 
    200 void FlowThreadController::resetFlowThreadsWithAutoHeightRegions()
    201 {
    202     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    203         RenderNamedFlowThread* flowRenderer = *iter;
    204         if (flowRenderer->hasAutoLogicalHeightRegions()) {
    205             flowRenderer->markAutoLogicalHeightRegionsForLayout();
    206             flowRenderer->invalidateRegions();
    207         }
    208     }
    209 }
    210 
    211 void FlowThreadController::updateFlowThreadsIntoConstrainedPhase()
    212 {
    213     // Walk the flow chain in reverse order to update the auto-height regions and compute correct sizes for the containing regions. Only after this we can
    214     // set the flow in the constrained layout phase.
    215     for (RenderNamedFlowThreadList::reverse_iterator iter = m_renderNamedFlowThreadList->rbegin(); iter != m_renderNamedFlowThreadList->rend(); ++iter) {
    216         RenderNamedFlowThread* flowRenderer = *iter;
    217         ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo());
    218         flowRenderer->layoutIfNeeded();
    219         if (flowRenderer->hasAutoLogicalHeightRegions()) {
    220             ASSERT(flowRenderer->needsTwoPhasesLayout());
    221             flowRenderer->markAutoLogicalHeightRegionsForLayout();
    222         }
    223         flowRenderer->setInConstrainedLayoutPhase(true);
    224         flowRenderer->clearNeedsTwoPhasesLayout();
    225     }
    226 }
    227 
    228 bool FlowThreadController::isContentNodeRegisteredWithAnyNamedFlow(const Node* contentNode) const
    229 {
    230     return m_mapNamedFlowContentNodes.contains(contentNode);
    231 }
    232 
    233 #ifndef NDEBUG
    234 bool FlowThreadController::isAutoLogicalHeightRegionsCountConsistent() const
    235 {
    236     if (!hasRenderNamedFlowThreads())
    237         return !hasFlowThreadsWithAutoLogicalHeightRegions();
    238 
    239     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
    240         if (!(*iter)->isAutoLogicalHeightRegionsCountConsistent())
    241             return false;
    242     }
    243 
    244     return true;
    245 }
    246 #endif
    247 
    248 } // namespace WebCore
    249