Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 2011 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 #include "core/dom/NamedFlow.h"
     32 
     33 #include "RuntimeEnabledFeatures.h"
     34 #include "core/dom/EventNames.h"
     35 #include "core/dom/NamedFlowCollection.h"
     36 #include "core/dom/StaticNodeList.h"
     37 #include "core/dom/UIEvent.h"
     38 #include "core/rendering/RenderNamedFlowThread.h"
     39 #include "core/rendering/RenderRegion.h"
     40 
     41 namespace WebCore {
     42 
     43 NamedFlow::NamedFlow(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
     44     : m_flowThreadName(flowThreadName)
     45     , m_flowManager(manager)
     46     , m_parentFlowThread(0)
     47 {
     48     ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
     49     ScriptWrappable::init(this);
     50 }
     51 
     52 NamedFlow::~NamedFlow()
     53 {
     54     // The named flow is not "strong" referenced from anywhere at this time so it shouldn't be reused if the named flow is recreated.
     55     m_flowManager->discardNamedFlow(this);
     56 }
     57 
     58 PassRefPtr<NamedFlow> NamedFlow::create(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
     59 {
     60     return adoptRef(new NamedFlow(manager, flowThreadName));
     61 }
     62 
     63 const AtomicString& NamedFlow::name() const
     64 {
     65     return m_flowThreadName;
     66 }
     67 
     68 bool NamedFlow::overset() const
     69 {
     70     if (m_flowManager->document())
     71         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
     72 
     73     // The renderer may be destroyed or created after the style update.
     74     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
     75     return m_parentFlowThread ? m_parentFlowThread->overset() : true;
     76 }
     77 
     78 static inline bool inFlowThread(RenderObject* renderer, RenderNamedFlowThread* flowThread)
     79 {
     80     if (!renderer)
     81         return false;
     82     RenderFlowThread* currentFlowThread = renderer->flowThreadContainingBlock();
     83     if (flowThread == currentFlowThread)
     84         return true;
     85     if (renderer->flowThreadState() != RenderObject::InsideInFlowThread)
     86         return false;
     87 
     88     // An in-flow flow thread can be nested inside an out-of-flow one, so we have to recur up to check.
     89     return inFlowThread(currentFlowThread->containingBlock(), flowThread);
     90 }
     91 
     92 int NamedFlow::firstEmptyRegionIndex() const
     93 {
     94     if (m_flowManager->document())
     95         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
     96 
     97     if (!m_parentFlowThread)
     98         return -1;
     99 
    100     const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
    101     if (regionList.isEmpty())
    102         return -1;
    103     RenderRegionList::const_iterator iter = regionList.begin();
    104     for (int index = 0; iter != regionList.end(); ++index, ++iter) {
    105         const RenderRegion* renderRegion = *iter;
    106         if (renderRegion->regionOversetState() == RegionEmpty)
    107             return index;
    108     }
    109     return -1;
    110 }
    111 
    112 PassRefPtr<NodeList> NamedFlow::getRegionsByContent(Node* contentNode)
    113 {
    114     Vector<RefPtr<Node> > regionNodes;
    115 
    116     if (!contentNode)
    117         return StaticNodeList::adopt(regionNodes);
    118 
    119     if (m_flowManager->document())
    120         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
    121 
    122     // The renderer may be destroyed or created after the style update.
    123     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
    124     if (!m_parentFlowThread)
    125         return StaticNodeList::adopt(regionNodes);
    126 
    127     if (inFlowThread(contentNode->renderer(), m_parentFlowThread)) {
    128         const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
    129         for (RenderRegionList::const_iterator iter = regionList.begin(); iter != regionList.end(); ++iter) {
    130             const RenderRegion* renderRegion = *iter;
    131             // FIXME: Pseudo-elements are not included in the list.
    132             if (!renderRegion->node())
    133                 continue;
    134             if (m_parentFlowThread->objectInFlowRegion(contentNode->renderer(), renderRegion))
    135                 regionNodes.append(renderRegion->node());
    136         }
    137     }
    138 
    139     return StaticNodeList::adopt(regionNodes);
    140 }
    141 
    142 PassRefPtr<NodeList> NamedFlow::getRegions()
    143 {
    144     Vector<RefPtr<Node> > regionNodes;
    145 
    146     if (m_flowManager->document())
    147         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
    148 
    149     // The renderer may be destroyed or created after the style update.
    150     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
    151     if (!m_parentFlowThread)
    152         return StaticNodeList::adopt(regionNodes);
    153 
    154     const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
    155     for (RenderRegionList::const_iterator iter = regionList.begin(); iter != regionList.end(); ++iter) {
    156         const RenderRegion* renderRegion = *iter;
    157         // FIXME: Pseudo-elements are not included in the list.
    158         if (!renderRegion->node())
    159             continue;
    160         regionNodes.append(renderRegion->node());
    161     }
    162 
    163     return StaticNodeList::adopt(regionNodes);
    164 }
    165 
    166 PassRefPtr<NodeList> NamedFlow::getContent()
    167 {
    168     Vector<RefPtr<Node> > contentNodes;
    169 
    170     if (m_flowManager->document())
    171         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
    172 
    173     // The renderer may be destroyed or created after the style update.
    174     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
    175     if (!m_parentFlowThread)
    176         return StaticNodeList::adopt(contentNodes);
    177 
    178     const NamedFlowContentNodes& contentNodesList = m_parentFlowThread->contentNodes();
    179     for (NamedFlowContentNodes::const_iterator it = contentNodesList.begin(); it != contentNodesList.end(); ++it) {
    180         Node* node = *it;
    181         ASSERT(node->computedStyle()->flowThread() == m_parentFlowThread->flowThreadName());
    182         contentNodes.append(node);
    183     }
    184 
    185     return StaticNodeList::adopt(contentNodes);
    186 }
    187 
    188 void NamedFlow::setRenderer(RenderNamedFlowThread* parentFlowThread)
    189 {
    190     // The named flow can either go from a no_renderer->renderer or renderer->no_renderer state; anything else could indicate a bug.
    191     ASSERT((!m_parentFlowThread && parentFlowThread) || (m_parentFlowThread && !parentFlowThread));
    192 
    193     // If parentFlowThread is 0, the flow thread will move in the "NULL" state.
    194     m_parentFlowThread = parentFlowThread;
    195 }
    196 
    197 EventTargetData* NamedFlow::eventTargetData()
    198 {
    199     return &m_eventTargetData;
    200 }
    201 
    202 EventTargetData* NamedFlow::ensureEventTargetData()
    203 {
    204     return &m_eventTargetData;
    205 }
    206 
    207 void NamedFlow::dispatchRegionLayoutUpdateEvent()
    208 {
    209     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
    210 
    211     // If the flow is in the "NULL" state the event should not be dispatched any more.
    212     if (flowState() == FlowStateNull)
    213         return;
    214 
    215     RefPtr<Event> event = UIEvent::create(eventNames().webkitregionlayoutupdateEvent, false, false, m_flowManager->document()->defaultView(), 0);
    216 
    217     dispatchEvent(event);
    218 }
    219 
    220 void NamedFlow::dispatchRegionOversetChangeEvent()
    221 {
    222     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
    223 
    224     // If the flow is in the "NULL" state the event should not be dispatched any more.
    225     if (flowState() == FlowStateNull)
    226         return;
    227 
    228     RefPtr<Event> event = UIEvent::create(eventNames().webkitregionoversetchangeEvent, false, false, m_flowManager->document()->defaultView(), 0);
    229 
    230     dispatchEvent(event);
    231 }
    232 
    233 const AtomicString& NamedFlow::interfaceName() const
    234 {
    235     return eventNames().interfaceForNamedFlow;
    236 }
    237 
    238 ScriptExecutionContext* NamedFlow::scriptExecutionContext() const
    239 {
    240     return m_flowManager->document();
    241 }
    242 
    243 Node* NamedFlow::ownerNode() const
    244 {
    245     return m_flowManager->document();
    246 }
    247 
    248 } // namespace WebCore
    249 
    250