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 "core/rendering/RenderBlockFlow.h" 35 #include "wtf/HashCountedSet.h" 36 #include "wtf/ListHashSet.h" 37 #include "wtf/PassRefPtr.h" 38 39 namespace WebCore { 40 41 struct LayerFragment; 42 typedef Vector<LayerFragment, 1> LayerFragments; 43 class RenderFlowThread; 44 class RenderStyle; 45 class RenderRegion; 46 47 typedef ListHashSet<RenderRegion*> RenderRegionList; 48 49 // RenderFlowThread is used to collect all the render objects that participate in a 50 // flow thread. It will also help in doing the layout. However, it will not render 51 // directly to screen. Instead, RenderRegion objects will redirect their paint 52 // and nodeAtPoint methods to this object. Each RenderRegion will actually be a viewPort 53 // of the RenderFlowThread. 54 55 class RenderFlowThread: public RenderBlockFlow { 56 public: 57 RenderFlowThread(); 58 virtual ~RenderFlowThread() { }; 59 60 virtual bool isRenderFlowThread() const OVERRIDE FINAL { return true; } 61 62 virtual void layout() OVERRIDE FINAL; 63 64 // Always create a RenderLayer for the RenderFlowThread so that we 65 // can easily avoid drawing the children directly. 66 virtual bool requiresLayer() const OVERRIDE FINAL { return true; } 67 68 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; 69 70 void removeFlowChildInfo(RenderObject*); 71 #ifndef NDEBUG 72 bool hasChildInfo(RenderObject* child) const { return child && child->isBox() && m_regionRangeMap.contains(toRenderBox(child)); } 73 #endif 74 75 virtual void addRegionToThread(RenderRegion*); 76 virtual void removeRegionFromThread(RenderRegion*); 77 const RenderRegionList& renderRegionList() const { return m_regionList; } 78 79 virtual void updateLogicalWidth() OVERRIDE FINAL; 80 virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; 81 82 void paintFlowThreadPortionInRegion(PaintInfo&, RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint&) const; 83 bool hitTestFlowThreadPortionInRegion(RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const; 84 85 bool hasRegions() const { return m_regionList.size(); } 86 // Check if the content is flown into at least a region with region styling rules. 87 bool hasRegionsWithStyling() const { return m_hasRegionsWithStyling; } 88 void checkRegionsWithStyling(); 89 virtual void regionChangedWritingMode(RenderRegion*) { } 90 91 void validateRegions(); 92 void invalidateRegions(); 93 bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); } 94 95 static PassRefPtr<RenderStyle> createFlowThreadStyle(RenderStyle* parentStyle); 96 97 void styleDidChange(StyleDifference, const RenderStyle* oldStyle); 98 99 void repaintRectangleInRegions(const LayoutRect&) const; 100 101 LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&); 102 103 LayoutUnit pageLogicalTopForOffset(LayoutUnit); 104 LayoutUnit pageLogicalWidthForOffset(LayoutUnit); 105 LayoutUnit pageLogicalHeightForOffset(LayoutUnit); 106 LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary); 107 108 virtual void setPageBreak(LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { } 109 virtual void updateMinimumPageHeight(LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { } 110 111 enum RegionAutoGenerationPolicy { 112 AllowRegionAutoGeneration, 113 DisallowRegionAutoGeneration, 114 }; 115 RenderRegion* regionAtBlockOffset(LayoutUnit, bool extendLastRegion = false, RegionAutoGenerationPolicy = AllowRegionAutoGeneration); 116 117 RenderRegion* regionFromAbsolutePointAndBox(IntPoint, const RenderBox* flowedBox); 118 119 bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; } 120 bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; } 121 122 RenderRegion* mapFromFlowToRegion(TransformState&) const; 123 124 void removeRenderBoxRegionInfo(RenderBox*); 125 bool logicalWidthChangedInRegionsForBlock(const RenderBlock*); 126 127 LayoutUnit contentLogicalWidthOfFirstRegion() const; 128 LayoutUnit contentLogicalHeightOfFirstRegion() const; 129 LayoutUnit contentLogicalLeftOfFirstRegion() const; 130 131 RenderRegion* firstRegion() const; 132 RenderRegion* lastRegion() const; 133 134 bool previousRegionCountChanged() const { return m_previousRegionCount != m_regionList.size(); } 135 void updatePreviousRegionCount() { m_previousRegionCount = m_regionList.size(); } 136 137 void setRegionRangeForBox(const RenderBox*, LayoutUnit offsetFromLogicalTopOfFirstPage); 138 void getRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const; 139 140 void clearRenderObjectCustomStyle(const RenderObject*, 141 const RenderRegion* oldStartRegion = 0, const RenderRegion* oldEndRegion = 0, 142 const RenderRegion* newStartRegion = 0, const RenderRegion* newEndRegion = 0); 143 144 // Check if the object is in region and the region is part of this flow thread. 145 bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const; 146 147 void markAutoLogicalHeightRegionsForLayout(); 148 149 bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0); 150 void applyBreakAfterContent(LayoutUnit); 151 152 bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; } 153 154 bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; } 155 void incrementAutoLogicalHeightRegions(); 156 void decrementAutoLogicalHeightRegions(); 157 158 #ifndef NDEBUG 159 bool isAutoLogicalHeightRegionsCountConsistent() const; 160 #endif 161 162 void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect); 163 LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox); 164 165 void setInConstrainedLayoutPhase(bool value) { m_inConstrainedLayoutPhase = value; } 166 bool inConstrainedLayoutPhase() const { return m_inConstrainedLayoutPhase; } 167 168 bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; } 169 void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; } 170 171 void pushFlowThreadLayoutState(const RenderObject*); 172 void popFlowThreadLayoutState(); 173 LayoutUnit offsetFromLogicalTopOfFirstRegion(const RenderBlock*) const; 174 175 // Used to estimate the maximum height of the flow thread. 176 static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; } 177 178 protected: 179 virtual const char* renderName() const = 0; 180 181 // Overridden by columns/pages to set up an initial logical width of the page width even when 182 // no regions have been generated yet. 183 virtual LayoutUnit initialLogicalWidth() const { return 0; }; 184 185 virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; 186 187 void updateRegionsFlowThreadPortionRect(const RenderRegion* = 0); 188 bool shouldRepaint(const LayoutRect&) const; 189 bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const; 190 191 LayoutRect computeRegionClippingRect(const LayoutPoint&, const LayoutRect&, const LayoutRect&) const; 192 193 void setDispatchRegionLayoutUpdateEvent(bool value) { m_dispatchRegionLayoutUpdateEvent = value; } 194 bool shouldDispatchRegionLayoutUpdateEvent() { return m_dispatchRegionLayoutUpdateEvent; } 195 196 void setDispatchRegionOversetChangeEvent(bool value) { m_dispatchRegionOversetChangeEvent = value; } 197 bool shouldDispatchRegionOversetChangeEvent() const { return m_dispatchRegionOversetChangeEvent; } 198 199 // Override if the flow thread implementation supports dispatching events when the flow layout is updated (e.g. for named flows) 200 virtual void dispatchRegionLayoutUpdateEvent() { m_dispatchRegionLayoutUpdateEvent = false; } 201 virtual void dispatchRegionOversetChangeEvent() { m_dispatchRegionOversetChangeEvent = false; } 202 203 void initializeRegionsComputedAutoHeight(RenderRegion* = 0); 204 205 virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) { }; 206 207 bool cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit&) const; 208 void setOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit); 209 void clearOffsetFromLogicalTopOfFirstRegion(const RenderBox*); 210 211 const RenderBox* currentStatePusherRenderBox() const; 212 213 RenderRegionList m_regionList; 214 unsigned short m_previousRegionCount; 215 216 class RenderRegionRange { 217 public: 218 RenderRegionRange() 219 { 220 setRange(0, 0); 221 } 222 223 RenderRegionRange(RenderRegion* start, RenderRegion* end) 224 { 225 setRange(start, end); 226 } 227 228 void setRange(RenderRegion* start, RenderRegion* end) 229 { 230 m_startRegion = start; 231 m_endRegion = end; 232 } 233 234 RenderRegion* startRegion() const { return m_startRegion; } 235 RenderRegion* endRegion() const { return m_endRegion; } 236 237 private: 238 RenderRegion* m_startRegion; 239 RenderRegion* m_endRegion; 240 }; 241 242 typedef PODInterval<LayoutUnit, RenderRegion*> RegionInterval; 243 typedef PODIntervalTree<LayoutUnit, RenderRegion*> RegionIntervalTree; 244 245 class RegionSearchAdapter { 246 public: 247 RegionSearchAdapter(LayoutUnit offset) 248 : m_offset(offset) 249 , m_result(0) 250 { 251 } 252 253 const LayoutUnit& lowValue() const { return m_offset; } 254 const LayoutUnit& highValue() const { return m_offset; } 255 void collectIfNeeded(const RegionInterval&); 256 257 RenderRegion* result() const { return m_result; } 258 259 private: 260 LayoutUnit m_offset; 261 RenderRegion* m_result; 262 }; 263 264 // A maps from RenderBox 265 typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap; 266 RenderRegionRangeMap m_regionRangeMap; 267 268 typedef HashMap<RenderObject*, RenderRegion*> RenderObjectToRegionMap; 269 RenderObjectToRegionMap m_breakBeforeToRegionMap; 270 RenderObjectToRegionMap m_breakAfterToRegionMap; 271 272 // Stack of objects that pushed a LayoutState object on the RenderView. The 273 // objects on the stack are the ones that are curently in the process of being 274 // laid out. 275 ListHashSet<const RenderObject*> m_statePusherObjectsStack; 276 typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap; 277 RenderBoxToOffsetMap m_boxesToOffsetMap; 278 279 unsigned m_autoLogicalHeightRegionsCount; 280 281 RegionIntervalTree m_regionIntervalTree; 282 283 bool m_regionsInvalidated : 1; 284 bool m_regionsHaveUniformLogicalWidth : 1; 285 bool m_regionsHaveUniformLogicalHeight : 1; 286 bool m_hasRegionsWithStyling : 1; 287 bool m_dispatchRegionLayoutUpdateEvent : 1; 288 bool m_dispatchRegionOversetChangeEvent : 1; 289 bool m_pageLogicalSizeChanged : 1; 290 bool m_inConstrainedLayoutPhase : 1; 291 bool m_needsTwoPhasesLayout : 1; 292 293 private: 294 virtual bool supportsPartialLayout() const OVERRIDE { return false; } 295 296 }; 297 298 DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderFlowThread, isRenderFlowThread()); 299 300 class CurrentRenderFlowThreadMaintainer { 301 WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadMaintainer); 302 public: 303 CurrentRenderFlowThreadMaintainer(RenderFlowThread*); 304 ~CurrentRenderFlowThreadMaintainer(); 305 private: 306 RenderFlowThread* m_renderFlowThread; 307 RenderFlowThread* m_previousRenderFlowThread; 308 }; 309 310 // These structures are used by PODIntervalTree for debugging. 311 #ifndef NDEBUG 312 template <> struct ValueToString<LayoutUnit> { 313 static String string(const LayoutUnit value) { return String::number(value.toFloat()); } 314 }; 315 316 template <> struct ValueToString<RenderRegion*> { 317 static String string(const RenderRegion* value) { return String::format("%p", value); } 318 }; 319 #endif 320 321 } // namespace WebCore 322 323 #endif // RenderFlowThread_h 324