Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2012 Victor Carbune (victor (at) rosedu.org)
      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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include "core/rendering/RenderTextTrackCue.h"
     29 
     30 #include "core/html/track/TextTrackCue.h"
     31 #include "core/html/track/TextTrackCueGeneric.h"
     32 
     33 namespace WebCore {
     34 
     35 RenderTextTrackCue::RenderTextTrackCue(TextTrackCueBox* element)
     36     : RenderBlock(element)
     37     , m_cue(element->getCue())
     38 {
     39 }
     40 
     41 void RenderTextTrackCue::layout()
     42 {
     43     StackStats::LayoutCheckPoint layoutCheckPoint;
     44     RenderBlock::layout();
     45 
     46 #if ENABLE(WEBVTT_REGIONS)
     47     // If WebVTT Regions are used, the regular WebVTT layout algorithm is no
     48     // longer necessary, since cues having the region parameter set do not have
     49     // any positioning parameters. Also, in this case, the regions themselves
     50     // have positioning information.
     51     if (!m_cue->regionId().isEmpty())
     52         return;
     53 #endif
     54 
     55     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
     56 
     57     if (m_cue->cueType()== TextTrackCue::WebVTT) {
     58         if (m_cue->snapToLines())
     59             repositionCueSnapToLinesSet();
     60         else
     61             repositionCueSnapToLinesNotSet();
     62     } else
     63         repositionGenericCue();
     64 
     65     statePusher.pop();
     66 }
     67 
     68 bool RenderTextTrackCue::findFirstLineBox(InlineFlowBox*& firstLineBox)
     69 {
     70     if (firstChild()->isRenderInline())
     71         firstLineBox = toRenderInline(firstChild())->firstLineBox();
     72     else
     73         return false;
     74 
     75     return true;
     76 }
     77 
     78 bool RenderTextTrackCue::initializeLayoutParameters(InlineFlowBox* firstLineBox, LayoutUnit& step, LayoutUnit& position)
     79 {
     80     ASSERT(firstChild());
     81 
     82     RenderBlock* parentBlock = containingBlock();
     83 
     84     // 1. Horizontal: Let step be the height of the first line box in boxes.
     85     //    Vertical: Let step be the width of the first line box in boxes.
     86     step = m_cue->getWritingDirection() == TextTrackCue::Horizontal ? firstLineBox->height() : firstLineBox->width();
     87 
     88     // 2. If step is zero, then jump to the step labeled done positioning below.
     89     if (!step)
     90         return false;
     91 
     92     // 3. Let line position be the text track cue computed line position.
     93     int linePosition = m_cue->calculateComputedLinePosition();
     94 
     95     // 4. Vertical Growing Left: Add one to line position then negate it.
     96     if (m_cue->getWritingDirection() == TextTrackCue::VerticalGrowingLeft)
     97         linePosition = -(linePosition + 1);
     98 
     99     // 5. Let position be the result of multiplying step and line position.
    100     position = step * linePosition;
    101 
    102     // 6. Vertical Growing Left: Decrease position by the width of the
    103     // bounding box of the boxes in boxes, then increase position by step.
    104     if (m_cue->getWritingDirection() == TextTrackCue::VerticalGrowingLeft) {
    105         position -= width();
    106         position += step;
    107     }
    108 
    109     // 7. If line position is less than zero...
    110     if (linePosition < 0) {
    111         // Horizontal / Vertical: ... then increase position by the
    112         // height / width of the video's rendering area ...
    113         position += m_cue->getWritingDirection() == TextTrackCue::Horizontal ? parentBlock->height() : parentBlock->width();
    114 
    115         // ... and negate step.
    116         step = -step;
    117     }
    118 
    119     return true;
    120 }
    121 
    122 void RenderTextTrackCue::placeBoxInDefaultPosition(LayoutUnit position, bool& switched)
    123 {
    124     // 8. Move all boxes in boxes ...
    125     if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
    126         // Horizontal: ... down by the distance given by position
    127         setY(y() + position);
    128     else
    129         // Vertical: ... right by the distance given by position
    130         setX(x() + position);
    131 
    132     // 9. Default: Remember the position of all the boxes in boxes as their
    133     // default position.
    134     m_fallbackPosition = FloatPoint(x(), y());
    135 
    136     // 10. Let switched be false.
    137     switched = false;
    138 }
    139 
    140 bool RenderTextTrackCue::isOutside() const
    141 {
    142     return !containingBlock()->absoluteBoundingBoxRect().contains(absoluteContentBox());
    143 }
    144 
    145 bool RenderTextTrackCue::isOverlapping() const
    146 {
    147     for (RenderObject* box = previousSibling(); box; box = box->previousSibling()) {
    148         IntRect boxRect = box->absoluteBoundingBoxRect();
    149 
    150         if (absoluteBoundingBoxRect().intersects(boxRect))
    151             return true;
    152     }
    153 
    154     return false;
    155 }
    156 
    157 bool RenderTextTrackCue::shouldSwitchDirection(InlineFlowBox* firstLineBox, LayoutUnit step) const
    158 {
    159     LayoutUnit top = y();
    160     LayoutUnit left = x();
    161     LayoutUnit bottom = top + firstLineBox->height();
    162     LayoutUnit right = left + firstLineBox->width();
    163 
    164     // 12. Horizontal: If step is negative and the top of the first line
    165     // box in boxes is now above the top of the video's rendering area,
    166     // or if step is positive and the bottom of the first line box in
    167     // boxes is now below the bottom of the video's rendering area, jump
    168     // to the step labeled switch direction.
    169     LayoutUnit parentHeight = containingBlock()->height();
    170     if (m_cue->getWritingDirection() == TextTrackCue::Horizontal && ((step < 0 && top < 0) || (step > 0 && bottom > parentHeight)))
    171         return true;
    172 
    173     // 12. Vertical: If step is negative and the left edge of the first line
    174     // box in boxes is now to the left of the left edge of the video's
    175     // rendering area, or if step is positive and the right edge of the
    176     // first line box in boxes is now to the right of the right edge of
    177     // the video's rendering area, jump to the step labeled switch direction.
    178     LayoutUnit parentWidth = containingBlock()->width();
    179     if (m_cue->getWritingDirection() != TextTrackCue::Horizontal && ((step < 0 && left < 0) || (step > 0 && right > parentWidth)))
    180         return true;
    181 
    182     return false;
    183 }
    184 
    185 void RenderTextTrackCue::moveBoxesByStep(LayoutUnit step)
    186 {
    187     // 13. Horizontal: Move all the boxes in boxes down by the distance
    188     // given by step. (If step is negative, then this will actually
    189     // result in an upwards movement of the boxes in absolute terms.)
    190     if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
    191         setY(y() + step);
    192 
    193     // 13. Vertical: Move all the boxes in boxes right by the distance
    194     // given by step. (If step is negative, then this will actually
    195     // result in a leftwards movement of the boxes in absolute terms.)
    196     else
    197         setX(x() + step);
    198 }
    199 
    200 bool RenderTextTrackCue::switchDirection(bool& switched, LayoutUnit& step)
    201 {
    202     // 15. Switch direction: Move all the boxes in boxes back to their
    203     // default position as determined in the step above labeled default.
    204     setX(m_fallbackPosition.x());
    205     setY(m_fallbackPosition.y());
    206 
    207     // 16. If switched is true, jump to the step labeled done
    208     // positioning below.
    209     if (switched)
    210         return false;
    211 
    212     // 17. Negate step.
    213     step = -step;
    214 
    215     // 18. Set switched to true.
    216     switched = true;
    217     return true;
    218 }
    219 
    220 void RenderTextTrackCue::repositionCueSnapToLinesSet()
    221 {
    222     InlineFlowBox* firstLineBox;
    223     LayoutUnit step;
    224     LayoutUnit position;
    225 
    226     if (!findFirstLineBox(firstLineBox))
    227         return;
    228 
    229     if (!initializeLayoutParameters(firstLineBox, step, position))
    230         return;
    231 
    232     bool switched;
    233     placeBoxInDefaultPosition(position, switched);
    234 
    235     // 11. Step loop: If none of the boxes in boxes would overlap any of the boxes
    236     // in output and all the boxes in output are within the video's rendering area
    237     // then jump to the step labeled done positioning.
    238     while (isOutside() || isOverlapping()) {
    239         if (!shouldSwitchDirection(firstLineBox, step))
    240             // 13. Move all the boxes in boxes ...
    241             // 14. Jump back to the step labeled step loop.
    242             moveBoxesByStep(step);
    243         else if (!switchDirection(switched, step))
    244             break;
    245 
    246         // 19. Jump back to the step labeled step loop.
    247     }
    248 
    249     // Acommodate extra top and bottom padding, border or margin.
    250     // Note: this is supported only for internal UA styling, not through the cue selector.
    251     if (hasInlineDirectionBordersPaddingOrMargin()) {
    252         IntRect containerRect = containingBlock()->absoluteBoundingBoxRect();
    253         IntRect cueRect = absoluteBoundingBoxRect();
    254 
    255         int topOverflow = cueRect.y() - containerRect.y();
    256         int bottomOverflow = containerRect.y() + containerRect.height() - cueRect.y() - cueRect.height();
    257 
    258         int adjustment = 0;
    259         if (topOverflow < 0)
    260             adjustment = -topOverflow;
    261         else if (bottomOverflow < 0)
    262             adjustment = bottomOverflow;
    263 
    264         if (adjustment)
    265             setY(y() + adjustment);
    266     }
    267 }
    268 
    269 void RenderTextTrackCue::repositionGenericCue()
    270 {
    271     TextTrackCueGeneric* cue = static_cast<TextTrackCueGeneric*>(m_cue);
    272     if (!cue->useDefaultPosition())
    273         return;
    274 
    275     ASSERT(firstChild());
    276 
    277     InlineFlowBox* firstLineBox;
    278     if (!findFirstLineBox(firstLineBox))
    279         return;
    280 
    281     LayoutUnit parentWidth = containingBlock()->logicalWidth();
    282     LayoutUnit width = firstLineBox->width();
    283     LayoutUnit right = (parentWidth / 2) - (width / 2);
    284     setX(right);
    285 }
    286 
    287 void RenderTextTrackCue::repositionCueSnapToLinesNotSet()
    288 {
    289     // FIXME: Implement overlapping detection when snap-to-lines is not set. http://wkb.ug/84296
    290 }
    291 
    292 } // namespace WebCore
    293 
    294