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#ifndef RenderFlowThread_h 31#define RenderFlowThread_h 32 33 34#include "RenderBlockFlow.h" 35#include <wtf/HashCountedSet.h> 36#include <wtf/ListHashSet.h> 37#include <wtf/PassRefPtr.h> 38 39namespace WebCore { 40 41class CurrentRenderRegionMaintainer; 42struct LayerFragment; 43typedef Vector<LayerFragment, 1> LayerFragments; 44class RenderFlowThread; 45class RenderNamedFlowFragment; 46class RenderStyle; 47class RenderRegion; 48class RootInlineBox; 49 50typedef ListHashSet<RenderRegion*> RenderRegionList; 51typedef Vector<RenderLayer*> RenderLayerList; 52typedef HashMap<RenderNamedFlowFragment*, RenderLayerList> RegionToLayerListMap; 53typedef HashMap<RenderLayer*, RenderNamedFlowFragment*> LayerToRegionMap; 54typedef HashMap<const RootInlineBox*, RenderRegion*> ContainingRegionMap; 55 56// RenderFlowThread is used to collect all the render objects that participate in a 57// flow thread. It will also help in doing the layout. However, it will not render 58// directly to screen. Instead, RenderRegion objects will redirect their paint 59// and nodeAtPoint methods to this object. Each RenderRegion will actually be a viewPort 60// of the RenderFlowThread. 61 62class RenderFlowThread: public RenderBlockFlow { 63public: 64 virtual ~RenderFlowThread() { } 65 66 virtual void removeFlowChildInfo(RenderObject*); 67#ifndef NDEBUG 68 bool hasChildInfo(RenderObject* child) const { return child && child->isBox() && m_regionRangeMap.contains(toRenderBox(child)); } 69#endif 70 71#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 72 bool checkLinesConsistency(const RenderBlockFlow*) const; 73#endif 74 75 virtual void deleteLines() override; 76 77 virtual void addRegionToThread(RenderRegion*) = 0; 78 virtual void removeRegionFromThread(RenderRegion*); 79 const RenderRegionList& renderRegionList() const { return m_regionList; } 80 81 virtual void updateLogicalWidth() override final; 82 virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const override; 83 84 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; 85 86 bool hasRegions() const { return m_regionList.size(); } 87 virtual void regionChangedWritingMode(RenderRegion*) { } 88 89 void validateRegions(); 90 void invalidateRegions(); 91 bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); } 92 93 // Some renderers (column spanners) are moved out of the flow thread to live among column 94 // sets. If |child| is such a renderer, resolve it to the placeholder that lives at the original 95 // location in the tree. 96 virtual RenderObject* resolveMovedChild(RenderObject* child) const { return child; } 97 // Called when a descendant of the flow thread has been inserted. 98 virtual void flowThreadDescendantInserted(RenderObject*) { } 99 // Called when a sibling or descendant of the flow thread is about to be removed. 100 virtual void flowThreadRelativeWillBeRemoved(RenderObject*) { } 101 // Called when a descendant box's layout is finished and it has been positioned within its container. 102 virtual void flowThreadDescendantBoxLaidOut(RenderBox*) { } 103 104 static PassRef<RenderStyle> createFlowThreadStyle(RenderStyle* parentStyle); 105 106 virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; 107 108 void repaintRectangleInRegions(const LayoutRect&) const; 109 110 LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&); 111 112 LayoutUnit pageLogicalTopForOffset(LayoutUnit); 113 LayoutUnit pageLogicalWidthForOffset(LayoutUnit); 114 LayoutUnit pageLogicalHeightForOffset(LayoutUnit); 115 LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary); 116 117 virtual void setPageBreak(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { } 118 virtual void updateMinimumPageHeight(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { } 119 120 enum RegionAutoGenerationPolicy { 121 AllowRegionAutoGeneration, 122 DisallowRegionAutoGeneration, 123 }; 124 125 virtual RenderRegion* regionAtBlockOffset(const RenderBox*, LayoutUnit, bool extendLastRegion = false, RegionAutoGenerationPolicy = AllowRegionAutoGeneration); 126 127 bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; } 128 bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; } 129 130 virtual RenderRegion* mapFromFlowToRegion(TransformState&) const; 131 132 void logicalWidthChangedInRegionsForBlock(const RenderBlock*, bool&); 133 134 LayoutUnit contentLogicalWidthOfFirstRegion() const; 135 LayoutUnit contentLogicalHeightOfFirstRegion() const; 136 LayoutUnit contentLogicalLeftOfFirstRegion() const; 137 138 RenderRegion* firstRegion() const; 139 RenderRegion* lastRegion() const; 140 141 bool previousRegionCountChanged() const { return m_previousRegionCount != m_regionList.size(); }; 142 void updatePreviousRegionCount() { m_previousRegionCount = m_regionList.size(); }; 143 144 virtual void setRegionRangeForBox(const RenderBox*, RenderRegion*, RenderRegion*); 145 bool getRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const; 146 bool computedRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const; 147 bool hasCachedRegionRangeForBox(const RenderBox*) const; 148 149 // Check if the object is in region and the region is part of this flow thread. 150 bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const; 151 152 // Check if the object should be painted in this region and if the region is part of this flow thread. 153 bool objectShouldFragmentInFlowRegion(const RenderObject*, const RenderRegion*) const; 154 155 void markAutoLogicalHeightRegionsForLayout(); 156 void markRegionsForOverflowLayoutIfNeeded(); 157 158 virtual bool addForcedRegionBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0); 159 virtual void applyBreakAfterContent(LayoutUnit) { } 160 161 virtual bool isPageLogicalHeightKnown() const { return true; } 162 bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; } 163 164 bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; } 165 void incrementAutoLogicalHeightRegions(); 166 void decrementAutoLogicalHeightRegions(); 167 168#ifndef NDEBUG 169 bool isAutoLogicalHeightRegionsCountConsistent() const; 170#endif 171 172 void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect); 173 LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox); 174 175 // A flow thread goes through different states during layout. 176 enum LayoutPhase { 177 LayoutPhaseMeasureContent = 0, // The initial phase, used to measure content for the auto-height regions. 178 LayoutPhaseConstrained, // In this phase the regions are laid out using the sizes computed in the normal phase. 179 LayoutPhaseOverflow, // In this phase the layout overflow is propagated from the content to the regions. 180 LayoutPhaseFinal // In case scrollbars have resized the regions, content is laid out one last time to respect the change. 181 }; 182 bool inMeasureContentLayoutPhase() const { return m_layoutPhase == LayoutPhaseMeasureContent; } 183 bool inConstrainedLayoutPhase() const { return m_layoutPhase == LayoutPhaseConstrained; } 184 bool inOverflowLayoutPhase() const { return m_layoutPhase == LayoutPhaseOverflow; } 185 bool inFinalLayoutPhase() const { return m_layoutPhase == LayoutPhaseFinal; } 186 void setLayoutPhase(LayoutPhase phase) { m_layoutPhase = phase; } 187 188 bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; } 189 void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; } 190 191 // Whether any of the regions has a compositing descendant. 192 bool hasCompositingRegionDescendant() const; 193 194 void setNeedsLayerToRegionMappingsUpdate() { m_layersToRegionMappingsDirty = true; } 195 void updateAllLayerToRegionMappingsIfNeeded() 196 { 197 if (m_layersToRegionMappingsDirty) 198 updateAllLayerToRegionMappings(); 199 } 200 201 const RenderLayerList* getLayerListForRegion(RenderNamedFlowFragment*) const; 202 203 RenderNamedFlowFragment* regionForCompositedLayer(RenderLayer&); // By means of getRegionRangeForBox or regionAtBlockOffset. 204 RenderNamedFlowFragment* cachedRegionForCompositedLayer(RenderLayer&) const; 205 206 virtual bool collectsGraphicsLayersUnderRegions() const; 207 208 void pushFlowThreadLayoutState(const RenderObject&); 209 void popFlowThreadLayoutState(); 210 LayoutUnit offsetFromLogicalTopOfFirstRegion(const RenderBlock*) const; 211 void clearRenderBoxRegionInfoAndCustomStyle(const RenderBox*, const RenderRegion*, const RenderRegion*, const RenderRegion*, const RenderRegion*); 212 213 void addRegionsVisualEffectOverflow(const RenderBox*); 214 void addRegionsVisualOverflowFromTheme(const RenderBlock*); 215 void addRegionsOverflowFromChild(const RenderBox*, const RenderBox*, const LayoutSize&); 216 void addRegionsLayoutOverflow(const RenderBox*, const LayoutRect&); 217 void addRegionsVisualOverflow(const RenderBox*, const LayoutRect&); 218 void clearRegionsOverflow(const RenderBox*); 219 220 LayoutRect mapFromFlowThreadToLocal(const RenderBox*, const LayoutRect&) const; 221 LayoutRect mapFromLocalToFlowThread(const RenderBox*, const LayoutRect&) const; 222 223 void flipForWritingModeLocalCoordinates(LayoutRect&) const; 224 225 // Used to estimate the maximum height of the flow thread. 226 static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; } 227 228 bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const; 229 230 virtual bool absoluteQuadsForBox(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) const { return false; } 231 232 virtual void layout() override; 233 234 void setCurrentRegionMaintainer(CurrentRenderRegionMaintainer* currentRegionMaintainer) { m_currentRegionMaintainer = currentRegionMaintainer; } 235 RenderRegion* currentRegion() const; 236 237 ContainingRegionMap& containingRegionMap(); 238 239 // FIXME: Eventually as column and region flow threads start nesting, this may end up changing. 240 virtual bool shouldCheckColumnBreaks() const { return false; } 241 242private: 243 virtual bool isRenderFlowThread() const override final { return true; } 244 245 // Always create a RenderLayer for the RenderFlowThread so that we 246 // can easily avoid drawing the children directly. 247 virtual bool requiresLayer() const override final { return true; } 248 249protected: 250 RenderFlowThread(Document&, PassRef<RenderStyle>); 251 252 virtual const char* renderName() const = 0; 253 254 // Overridden by columns/pages to set up an initial logical width of the page width even when 255 // no regions have been generated yet. 256 virtual LayoutUnit initialLogicalWidth() const { return 0; }; 257 258 void clearLinesToRegionMap(); 259 virtual void willBeDestroyed() override; 260 261 virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override; 262 263 void updateRegionsFlowThreadPortionRect(const RenderRegion* = 0); 264 bool shouldRepaint(const LayoutRect&) const; 265 266 bool updateAllLayerToRegionMappings(); 267 268 // Triggers a layers' update if a layer has moved from a region to another since the last update. 269 void updateLayerToRegionMappings(RenderLayer&, LayerToRegionMap&, RegionToLayerListMap&, bool& needsLayerUpdate); 270 void updateRegionForRenderLayer(RenderLayer*, LayerToRegionMap&, RegionToLayerListMap&, bool& needsLayerUpdate); 271 272 void initializeRegionsComputedAutoHeight(RenderRegion* = 0); 273 274 virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) { }; 275 276 inline bool hasCachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const; 277 inline LayoutUnit cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const; 278 inline void setOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit); 279 inline void clearOffsetFromLogicalTopOfFirstRegion(const RenderBox*); 280 281 inline const RenderBox* currentActiveRenderBox() const; 282 283 bool getRegionRangeForBoxFromCachedInfo(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const; 284 285 void removeRenderBoxRegionInfo(RenderBox*); 286 void removeLineRegionInfo(const RenderBlockFlow*); 287 288 RenderRegionList m_regionList; 289 unsigned short m_previousRegionCount; 290 291 class RenderRegionRange { 292 public: 293 RenderRegionRange() 294 { 295 setRange(0, 0); 296 } 297 298 RenderRegionRange(RenderRegion* start, RenderRegion* end) 299 { 300 setRange(start, end); 301 } 302 303 void setRange(RenderRegion* start, RenderRegion* end) 304 { 305 m_startRegion = start; 306 m_endRegion = end; 307 m_rangeInvalidated = true; 308 } 309 310 RenderRegion* startRegion() const { return m_startRegion; } 311 RenderRegion* endRegion() const { return m_endRegion; } 312 bool rangeInvalidated() const { return m_rangeInvalidated; } 313 void clearRangeInvalidated() { m_rangeInvalidated = false; } 314 315 private: 316 RenderRegion* m_startRegion; 317 RenderRegion* m_endRegion; 318 bool m_rangeInvalidated; 319 }; 320 321 typedef PODInterval<LayoutUnit, RenderRegion*> RegionInterval; 322 typedef PODIntervalTree<LayoutUnit, RenderRegion*> RegionIntervalTree; 323 324 class RegionSearchAdapter { 325 public: 326 RegionSearchAdapter(LayoutUnit offset) 327 : m_offset(offset) 328 , m_result(0) 329 { 330 } 331 332 const LayoutUnit& lowValue() const { return m_offset; } 333 const LayoutUnit& highValue() const { return m_offset; } 334 void collectIfNeeded(const RegionInterval&); 335 336 RenderRegion* result() const { return m_result; } 337 338 private: 339 LayoutUnit m_offset; 340 RenderRegion* m_result; 341 }; 342 343 // Map a layer to the region in which the layer is painted. 344 std::unique_ptr<LayerToRegionMap> m_layerToRegionMap; 345 346 // Map a region to the list of layers that paint in that region. 347 std::unique_ptr<RegionToLayerListMap> m_regionToLayerListMap; 348 349 // Map a line to its containing region. 350 std::unique_ptr<ContainingRegionMap> m_lineToRegionMap; 351 352 // Map a box to the list of regions in which the box is rendered. 353 typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap; 354 RenderRegionRangeMap m_regionRangeMap; 355 356 // Map a box with a region break to the auto height region affected by that break. 357 typedef HashMap<RenderBox*, RenderRegion*> RenderBoxToRegionMap; 358 RenderBoxToRegionMap m_breakBeforeToRegionMap; 359 RenderBoxToRegionMap m_breakAfterToRegionMap; 360 361 typedef ListHashSet<const RenderObject*> RenderObjectStack; 362 RenderObjectStack m_activeObjectsStack; 363 364 typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap; 365 RenderBoxToOffsetMap m_boxesToOffsetMap; 366 367 unsigned m_autoLogicalHeightRegionsCount; 368 369 RegionIntervalTree m_regionIntervalTree; 370 371 CurrentRenderRegionMaintainer* m_currentRegionMaintainer; 372 373 bool m_regionsInvalidated : 1; 374 bool m_regionsHaveUniformLogicalWidth : 1; 375 bool m_regionsHaveUniformLogicalHeight : 1; 376 bool m_pageLogicalSizeChanged : 1; 377 unsigned m_layoutPhase : 2; 378 bool m_needsTwoPhasesLayout : 1; 379 bool m_layersToRegionMappingsDirty : 1; 380}; 381 382RENDER_OBJECT_TYPE_CASTS(RenderFlowThread, isRenderFlowThread()) 383 384class CurrentRenderFlowThreadMaintainer { 385 WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadMaintainer); 386public: 387 CurrentRenderFlowThreadMaintainer(RenderFlowThread*); 388 ~CurrentRenderFlowThreadMaintainer(); 389private: 390 RenderFlowThread* m_renderFlowThread; 391 RenderFlowThread* m_previousRenderFlowThread; 392}; 393 394class CurrentRenderFlowThreadDisabler { 395 WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadDisabler); 396public: 397 CurrentRenderFlowThreadDisabler(RenderView*); 398 ~CurrentRenderFlowThreadDisabler(); 399private: 400 RenderView* m_view; 401 RenderFlowThread* m_renderFlowThread; 402}; 403 404// This structure is used by PODIntervalTree for debugging. 405#ifndef NDEBUG 406template <> struct ValueToString<RenderRegion*> { 407 static String string(const RenderRegion* value) { return String::format("%p", value); } 408}; 409#endif 410 411} // namespace WebCore 412 413#endif // RenderFlowThread_h 414