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