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