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 #include "config.h"
     31 #include "core/rendering/RenderRegion.h"
     32 
     33 #include "core/css/resolver/StyleResolver.h"
     34 #include "core/rendering/FlowThreadController.h"
     35 #include "core/rendering/HitTestLocation.h"
     36 #include "core/rendering/PaintInfo.h"
     37 #include "core/rendering/RenderFlowThread.h"
     38 #include "core/rendering/RenderView.h"
     39 
     40 using namespace std;
     41 
     42 namespace WebCore {
     43 
     44 RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread)
     45     : RenderBlockFlow(element)
     46     , m_flowThread(flowThread)
     47     , m_isValid(false)
     48 {
     49 }
     50 
     51 LayoutUnit RenderRegion::pageLogicalWidth() const
     52 {
     53     ASSERT(m_flowThread);
     54     return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHeight();
     55 }
     56 
     57 LayoutUnit RenderRegion::pageLogicalHeight() const
     58 {
     59     ASSERT(m_flowThread);
     60     return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth();
     61 }
     62 
     63 LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const
     64 {
     65     ASSERT(m_flowThread);
     66     return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth();
     67 }
     68 
     69 LayoutRect RenderRegion::flowThreadPortionOverflowRect() const
     70 {
     71     return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion());
     72 }
     73 
     74 LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const
     75 {
     76     ASSERT(isValid());
     77 
     78     if (hasOverflowClip())
     79         return flowThreadPortionRect;
     80 
     81     LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect();
     82 
     83     // Only clip along the flow thread axis.
     84     LayoutRect clipRect;
     85     if (m_flowThread->isHorizontalWritingMode()) {
     86         LayoutUnit minY = isFirstPortion ? flowThreadOverflow.y() : flowThreadPortionRect.y();
     87         LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) : flowThreadPortionRect.maxY();
     88         LayoutUnit minX = min(flowThreadPortionRect.x(), flowThreadOverflow.x());
     89         LayoutUnit maxX = max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX());
     90         clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
     91     } else {
     92         LayoutUnit minX = isFirstPortion ? flowThreadOverflow.x() : flowThreadPortionRect.x();
     93         LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) : flowThreadPortionRect.maxX();
     94         LayoutUnit minY = min(flowThreadPortionRect.y(), (flowThreadOverflow.y()));
     95         LayoutUnit maxY = max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY()));
     96         clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
     97     }
     98 
     99     return clipRect;
    100 }
    101 
    102 LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const
    103 {
    104     return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x();
    105 }
    106 
    107 bool RenderRegion::isFirstRegion() const
    108 {
    109     ASSERT(isValid());
    110 
    111     return m_flowThread->firstRegion() == this;
    112 }
    113 
    114 bool RenderRegion::isLastRegion() const
    115 {
    116     ASSERT(isValid());
    117 
    118     return m_flowThread->lastRegion() == this;
    119 }
    120 
    121 void RenderRegion::layoutBlock(bool relayoutChildren)
    122 {
    123     RenderBlockFlow::layoutBlock(relayoutChildren);
    124 
    125     // FIXME: We need to find a way to set up overflow properly. Our flow thread hasn't gotten a layout
    126     // yet, so we can't look to it for correct information. It's possible we could wait until after the RenderFlowThread
    127     // gets a layout, and then try to propagate overflow information back to the region, and then mark for a second layout.
    128     // That second layout would then be able to use the information from the RenderFlowThread to set up overflow.
    129     //
    130     // The big problem though is that overflow needs to be region-specific. We can't simply use the RenderFlowThread's global
    131     // overflow values, since then we'd always think any narrow region had huge overflow (all the way to the width of the
    132     // RenderFlowThread itself).
    133 }
    134 
    135 void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const
    136 {
    137     repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flowThreadPortionOverflowRect(), contentBoxRect().location());
    138 }
    139 
    140 void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const
    141 {
    142     ASSERT(isValid());
    143 
    144     // We only have to issue a repaint in this region if the region rect intersects the repaint rect.
    145     LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
    146     LayoutRect flippedFlowThreadPortionOverflowRect(flowThreadPortionOverflowRect);
    147     flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); // Put the region rects into physical coordinates.
    148     flowThread()->flipForWritingMode(flippedFlowThreadPortionOverflowRect);
    149 
    150     LayoutRect clippedRect(repaintRect);
    151     clippedRect.intersect(flippedFlowThreadPortionOverflowRect);
    152     if (clippedRect.isEmpty())
    153         return;
    154 
    155     // Put the region rect into the region's physical coordinate space.
    156     clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFlowThreadPortionRect.location()));
    157 
    158     // Now switch to the region's writing mode coordinate space and let it repaint itself.
    159     flipForWritingMode(clippedRect);
    160 
    161     // Issue the repaint.
    162     invalidatePaintRectangle(clippedRect);
    163 }
    164 
    165 void RenderRegion::attachRegion()
    166 {
    167     if (documentBeingDestroyed())
    168         return;
    169 
    170     // A region starts off invalid.
    171     setIsValid(false);
    172 
    173     if (!m_flowThread)
    174         return;
    175 
    176     // Only after adding the region to the thread, the region is marked to be valid.
    177     m_flowThread->addRegionToThread(this);
    178 }
    179 
    180 void RenderRegion::detachRegion()
    181 {
    182     if (m_flowThread) {
    183         m_flowThread->removeRegionFromThread(this);
    184         m_flowThread = 0;
    185     }
    186 }
    187 
    188 LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rect) const
    189 {
    190     ASSERT(isValid());
    191     return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x();
    192 }
    193 
    194 LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect& rect) const
    195 {
    196     ASSERT(isValid());
    197     return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX();
    198 }
    199 
    200 void RenderRegion::insertedIntoTree()
    201 {
    202     RenderBlockFlow::insertedIntoTree();
    203 
    204     attachRegion();
    205 }
    206 
    207 void RenderRegion::willBeRemovedFromTree()
    208 {
    209     RenderBlockFlow::willBeRemovedFromTree();
    210 
    211     detachRegion();
    212 }
    213 
    214 void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
    215 {
    216     if (!isValid()) {
    217         RenderBlockFlow::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
    218         return;
    219     }
    220 
    221     minLogicalWidth = m_flowThread->minPreferredLogicalWidth();
    222     maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth();
    223 }
    224 
    225 } // namespace WebCore
    226