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