Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Victor Carbune (victor@rosedu.org) | 2 * Copyright (C) 2012 Victor Carbune (victor@rosedu.org) |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 | 50 |
| 51 // If WebVTT Regions are used, the regular WebVTT layout algorithm is no | 51 // If WebVTT Regions are used, the regular WebVTT layout algorithm is no |
| 52 // longer necessary, since cues having the region parameter set do not have | 52 // longer necessary, since cues having the region parameter set do not have |
| 53 // any positioning parameters. Also, in this case, the regions themselves | 53 // any positioning parameters. Also, in this case, the regions themselves |
| 54 // have positioning information. | 54 // have positioning information. |
| 55 if (!m_cue->regionId().isEmpty()) | 55 if (!m_cue->regionId().isEmpty()) |
| 56 return; | 56 return; |
| 57 | 57 |
| 58 LayoutState state(*this, locationOffset()); | 58 LayoutState state(*this, locationOffset()); |
| 59 | 59 |
| 60 // http://dev.w3.org/html5/webvtt/#dfn-apply-webvtt-cue-settings - step 13. | |
| 60 if (m_cue->snapToLines()) | 61 if (m_cue->snapToLines()) |
| 61 repositionCueSnapToLinesSet(); | 62 repositionCueSnapToLinesSet(); |
| 62 else | 63 else |
| 63 repositionCueSnapToLinesNotSet(); | 64 repositionCueSnapToLinesNotSet(); |
| 64 } | 65 } |
| 65 | 66 |
| 66 bool RenderVTTCue::findFirstLineBox(InlineFlowBox*& firstLineBox) | 67 bool RenderVTTCue::findFirstLineBox(InlineFlowBox*& firstLineBox) |
| 67 { | 68 { |
| 68 if (firstChild()->isRenderInline()) | 69 if (firstChild()->isRenderInline()) |
| 69 firstLineBox = toRenderInline(firstChild())->firstLineBox(); | 70 firstLineBox = toRenderInline(firstChild())->firstLineBox(); |
| 70 else | 71 else |
| 71 return false; | 72 return false; |
| 72 | 73 |
| 73 return true; | 74 return true; |
| 74 } | 75 } |
| 75 | 76 |
| 76 bool RenderVTTCue::initializeLayoutParameters(InlineFlowBox* firstLineBox, Layou tUnit& step, LayoutUnit& position) | 77 bool RenderVTTCue::initializeLayoutParameters(InlineFlowBox* firstLineBox, Layou tUnit& step, LayoutUnit& position) |
| 77 { | 78 { |
| 78 ASSERT(firstChild()); | 79 ASSERT(firstChild()); |
| 79 | 80 |
| 80 RenderBlock* parentBlock = containingBlock(); | 81 // 4. Horizontal: Let step be the height of the first line box in boxes. |
| 81 | |
| 82 // 1. Horizontal: Let step be the height of the first line box in boxes. | |
| 83 // Vertical: Let step be the width of the first line box in boxes. | 82 // Vertical: Let step be the width of the first line box in boxes. |
| 84 step = m_cue->getWritingDirection() == VTTCue::Horizontal ? firstLineBox->si ze().height() : firstLineBox->size().width(); | 83 step = m_cue->getWritingDirection() == VTTCue::Horizontal ? firstLineBox->si ze().height() : firstLineBox->size().width(); |
| 85 | 84 |
| 86 // 2. If step is zero, then jump to the step labeled done positioning below. | 85 // 5. If step is zero, then jump to the step labeled done positioning below. |
| 87 if (!step) | 86 if (!step) |
| 88 return false; | 87 return false; |
| 89 | 88 |
| 90 // 3. Let line position be the text track cue computed line position. | 89 // 6. Let line position be the text track cue computed line position. |
| 91 int linePosition = m_cue->calculateComputedLinePosition(); | 90 // 7. Round line position to an integer by adding 0.5 and then flooring it. |
| 91 int linePosition = clampTo<int>(floorf(m_cue->calculateComputedLinePosition( ) + 0.5f)); | |
| 92 | 92 |
| 93 // 4. Vertical Growing Left: Add one to line position then negate it. | 93 // 8. Vertical Growing Left: Add one to line position then negate it. |
| 94 if (m_cue->getWritingDirection() == VTTCue::VerticalGrowingLeft) | 94 if (m_cue->getWritingDirection() == VTTCue::VerticalGrowingLeft) |
| 95 linePosition = -(linePosition + 1); | 95 linePosition = -(linePosition + 1); |
|
philipj_slow
2015/01/22 14:35:02
This will overflow for INT_MAX. Let linePosition b
fs
2015/01/22 15:49:49
Yes, LayoutUnit is probably (one of) the easier wa
| |
| 96 | 96 |
| 97 // 5. Let position be the result of multiplying step and line position. | 97 // 9. Let position be the result of multiplying step and line position. |
| 98 position = step * linePosition; | 98 position = step * linePosition; |
| 99 | 99 |
| 100 // 6. Vertical Growing Left: Decrease position by the width of the | 100 // 10. Vertical Growing Left: Decrease position by the width of the |
| 101 // bounding box of the boxes in boxes, then increase position by step. | 101 // bounding box of the boxes in boxes, then increase position by step. |
| 102 if (m_cue->getWritingDirection() == VTTCue::VerticalGrowingLeft) { | 102 if (m_cue->getWritingDirection() == VTTCue::VerticalGrowingLeft) { |
| 103 position -= size().width(); | 103 position -= size().width(); |
| 104 position += step; | 104 position += step; |
| 105 } | 105 } |
| 106 | 106 |
| 107 // 7. If line position is less than zero... | 107 // 11. If line position is less than zero... |
| 108 if (linePosition < 0) { | 108 if (linePosition < 0) { |
| 109 RenderBlock* parentBlock = containingBlock(); | |
| 110 | |
| 109 // Horizontal / Vertical: ... then increase position by the | 111 // Horizontal / Vertical: ... then increase position by the |
| 110 // height / width of the video's rendering area ... | 112 // height / width of the video's rendering area ... |
| 111 position += m_cue->getWritingDirection() == VTTCue::Horizontal ? parentB lock->size().height() : parentBlock->size().width(); | 113 position += m_cue->getWritingDirection() == VTTCue::Horizontal ? parentB lock->size().height() : parentBlock->size().width(); |
| 112 | 114 |
| 113 // ... and negate step. | 115 // ... and negate step. |
| 114 step = -step; | 116 step = -step; |
| 115 } | 117 } |
| 116 | |
| 117 return true; | 118 return true; |
| 118 } | 119 } |
| 119 | 120 |
| 120 void RenderVTTCue::placeBoxInDefaultPosition(LayoutUnit position, bool& switched ) | 121 void RenderVTTCue::placeBoxInDefaultPosition(LayoutUnit position, bool& switched ) |
| 121 { | 122 { |
| 122 // 8. Move all boxes in boxes ... | 123 // 12. Move all boxes in boxes ... |
| 123 if (m_cue->getWritingDirection() == VTTCue::Horizontal) { | 124 if (m_cue->getWritingDirection() == VTTCue::Horizontal) { |
| 124 // Horizontal: ... down by the distance given by position | 125 // Horizontal: ... down by the distance given by position |
| 125 setY(location().y() + position); | 126 setY(location().y() + position); |
| 126 } else { | 127 } else { |
| 127 // Vertical: ... right by the distance given by position | 128 // Vertical: ... right by the distance given by position |
| 128 setX(location().x() + position); | 129 setX(location().x() + position); |
| 129 } | 130 } |
| 130 | 131 |
| 131 // 9. Default: Remember the position of all the boxes in boxes as their | 132 // 13. Remember the position of all the boxes in boxes as their specified po sition. |
| 132 // default position. | 133 m_specifiedPosition = location(); |
| 133 m_defaultPosition = location(); | |
| 134 | 134 |
| 135 // 10. Let switched be false. | 135 // 14. Let best position be null. It will hold a position for boxes, much li ke specified position in the previous step. |
| 136 // 15. Let best position score be null. | |
| 137 | |
| 138 // 16. Let switched be false. | |
| 136 switched = false; | 139 switched = false; |
| 137 } | 140 } |
| 138 | 141 |
| 139 bool RenderVTTCue::isOutside() const | 142 bool RenderVTTCue::isOutside() const |
| 140 { | 143 { |
| 141 return !containingBlock()->absoluteBoundingBoxRect().contains(absoluteConten tBox()); | 144 return !containingBlock()->absoluteBoundingBoxRect().contains(absoluteConten tBox()); |
| 142 } | 145 } |
| 143 | 146 |
| 144 bool RenderVTTCue::isOverlapping() const | 147 bool RenderVTTCue::isOverlapping() const |
| 145 { | 148 { |
| 146 for (RenderObject* box = previousSibling(); box; box = box->previousSibling( )) { | 149 for (RenderObject* box = previousSibling(); box; box = box->previousSibling( )) { |
| 147 IntRect boxRect = box->absoluteBoundingBoxRect(); | 150 IntRect boxRect = box->absoluteBoundingBoxRect(); |
| 148 | 151 |
| 149 if (absoluteBoundingBoxRect().intersects(boxRect)) | 152 if (absoluteBoundingBoxRect().intersects(boxRect)) |
| 150 return true; | 153 return true; |
| 151 } | 154 } |
| 152 | 155 |
| 153 return false; | 156 return false; |
| 154 } | 157 } |
| 155 | 158 |
| 156 bool RenderVTTCue::shouldSwitchDirection(InlineFlowBox* firstLineBox, LayoutUnit step) const | 159 bool RenderVTTCue::shouldSwitchDirection(InlineFlowBox* firstLineBox, LayoutUnit step) const |
| 157 { | 160 { |
| 158 LayoutUnit top = location().y(); | 161 LayoutUnit top = location().y(); |
| 159 LayoutUnit left = location().x(); | 162 LayoutUnit left = location().x(); |
| 160 LayoutUnit bottom = top + firstLineBox->size().height(); | 163 LayoutUnit bottom = top + firstLineBox->size().height(); |
| 161 LayoutUnit right = left + firstLineBox->size().width(); | 164 LayoutUnit right = left + firstLineBox->size().width(); |
| 162 | 165 |
| 163 // 12. Horizontal: If step is negative and the top of the first line | 166 // 21. Horizontal: If step is negative and the top of the first line box in |
| 164 // box in boxes is now above the top of the video's rendering area, | 167 // boxes is now above the top of the title area, or if step is positive and |
| 165 // or if step is positive and the bottom of the first line box in | 168 // the bottom of the first line box in boxes is now below the bottom of the |
| 166 // boxes is now below the bottom of the video's rendering area, jump | 169 // title area, jump to the step labeled switch direction. |
| 167 // to the step labeled switch direction. | |
| 168 LayoutUnit parentHeight = containingBlock()->size().height(); | 170 LayoutUnit parentHeight = containingBlock()->size().height(); |
| 169 if (m_cue->getWritingDirection() == VTTCue::Horizontal && ((step < 0 && top < 0) || (step > 0 && bottom > parentHeight))) | 171 if (m_cue->getWritingDirection() == VTTCue::Horizontal && ((step < 0 && top < 0) || (step > 0 && bottom > parentHeight))) |
| 170 return true; | 172 return true; |
| 171 | 173 |
| 172 // 12. Vertical: If step is negative and the left edge of the first line | 174 // 21. Vertical: If step is negative and the left edge of the first line |
| 173 // box in boxes is now to the left of the left edge of the video's | 175 // box in boxes is now to the left of the left edge of the title area, or |
| 174 // rendering area, or if step is positive and the right edge of the | 176 // if step is positive and the right edge of the first line box in boxes is |
| 175 // first line box in boxes is now to the right of the right edge of | 177 // now to the right of the right edge of the title area, jump to the step |
| 176 // the video's rendering area, jump to the step labeled switch direction. | 178 // labeled switch direction. |
| 177 LayoutUnit parentWidth = containingBlock()->size().width(); | 179 LayoutUnit parentWidth = containingBlock()->size().width(); |
| 178 if (m_cue->getWritingDirection() != VTTCue::Horizontal && ((step < 0 && left < 0) || (step > 0 && right > parentWidth))) | 180 if (m_cue->getWritingDirection() != VTTCue::Horizontal && ((step < 0 && left < 0) || (step > 0 && right > parentWidth))) |
| 179 return true; | 181 return true; |
| 180 | 182 |
| 181 return false; | 183 return false; |
| 182 } | 184 } |
| 183 | 185 |
| 184 void RenderVTTCue::moveBoxesByStep(LayoutUnit step) | 186 void RenderVTTCue::moveBoxesByStep(LayoutUnit step) |
| 185 { | 187 { |
| 186 // 13. Horizontal: Move all the boxes in boxes down by the distance | 188 // 22. Horizontal: Move all the boxes in boxes down by the distance |
| 187 // given by step. (If step is negative, then this will actually | 189 // given by step. (If step is negative, then this will actually |
| 188 // result in an upwards movement of the boxes in absolute terms.) | 190 // result in an upwards movement of the boxes in absolute terms.) |
| 189 if (m_cue->getWritingDirection() == VTTCue::Horizontal) | 191 if (m_cue->getWritingDirection() == VTTCue::Horizontal) |
| 190 setY(location().y() + step); | 192 setY(location().y() + step); |
| 191 | 193 |
| 192 // 13. Vertical: Move all the boxes in boxes right by the distance | 194 // 22. Vertical: Move all the boxes in boxes right by the distance |
| 193 // given by step. (If step is negative, then this will actually | 195 // given by step. (If step is negative, then this will actually |
| 194 // result in a leftwards movement of the boxes in absolute terms.) | 196 // result in a leftwards movement of the boxes in absolute terms.) |
| 195 else | 197 else |
| 196 setX(location().x() + step); | 198 setX(location().x() + step); |
| 197 } | 199 } |
| 198 | 200 |
| 199 bool RenderVTTCue::switchDirection(bool& switched, LayoutUnit& step) | 201 bool RenderVTTCue::switchDirection(bool& switched, LayoutUnit& step) |
| 200 { | 202 { |
| 201 // 15. Switch direction: Move all the boxes in boxes back to their | 203 // 24. Switch direction: If switched is true, then move all the boxes in |
| 202 // default position as determined in the step above labeled default. | 204 // boxes back to their best position, and jump to the step labeled done |
| 203 setLocation(m_defaultPosition); | 205 // positioning below. |
| 204 | 206 |
| 205 // 16. If switched is true, jump to the step labeled done | 207 // 25. Otherwise, move all the boxes in boxes back to their specified |
| 208 // position as determined in the earlier step. | |
| 209 setLocation(m_specifiedPosition); | |
| 210 | |
| 211 // XX. If switched is true, jump to the step labeled done | |
| 206 // positioning below. | 212 // positioning below. |
| 207 if (switched) | 213 if (switched) |
| 208 return false; | 214 return false; |
| 209 | 215 |
| 210 // 17. Negate step. | 216 // 26. Negate step. |
| 211 step = -step; | 217 step = -step; |
| 212 | 218 |
| 213 // 18. Set switched to true. | 219 // 27. Set switched to true. |
| 214 switched = true; | 220 switched = true; |
| 215 return true; | 221 return true; |
| 216 } | 222 } |
| 217 | 223 |
| 218 void RenderVTTCue::repositionCueSnapToLinesSet() | 224 void RenderVTTCue::repositionCueSnapToLinesSet() |
| 219 { | 225 { |
| 226 // http://dev.w3.org/html5/webvtt/#dfn-apply-webvtt-cue-settings | |
| 227 // Step 13, "If cue's text track cue snap-to-lines flag is set". | |
| 228 | |
| 220 InlineFlowBox* firstLineBox; | 229 InlineFlowBox* firstLineBox; |
| 221 LayoutUnit step; | |
| 222 LayoutUnit position; | |
| 223 | |
| 224 if (!findFirstLineBox(firstLineBox)) | 230 if (!findFirstLineBox(firstLineBox)) |
| 225 return; | 231 return; |
| 226 | 232 |
| 233 // Step 1 skipped. | |
| 234 | |
| 235 LayoutUnit step; | |
| 236 LayoutUnit position; | |
| 227 if (!initializeLayoutParameters(firstLineBox, step, position)) | 237 if (!initializeLayoutParameters(firstLineBox, step, position)) |
| 228 return; | 238 return; |
| 229 | 239 |
| 230 bool switched; | 240 bool switched; |
| 231 placeBoxInDefaultPosition(position, switched); | 241 placeBoxInDefaultPosition(position, switched); |
| 232 | 242 |
| 233 // 11. Step loop: If none of the boxes in boxes would overlap any of the box es | 243 // Step 17 skipped. (margin == 0; title area == video area) |
| 234 // in output and all the boxes in output are within the video's rendering ar ea | 244 |
| 235 // then jump to the step labeled done positioning. | 245 // 18. Step loop: If none of the boxes in boxes would overlap any of the |
| 246 // boxes in output, and all of the boxes in output are entirely within the | |
| 247 // title area box, then jump to the step labeled done positioning below. | |
| 236 while (isOutside() || isOverlapping()) { | 248 while (isOutside() || isOverlapping()) { |
| 249 // 19. Let current position score be the percentage of the area of the | |
| 250 // bounding box of the boxes in boxes that is outside the title area | |
| 251 // box. | |
| 252 // 20. If best position is null (i.e. this is the first run through | |
| 253 // this loop, switched is still false, the boxes in boxes are at their | |
| 254 // specified position, and best position score is still null), or if | |
| 255 // current position score is a lower percentage than that in best | |
| 256 // position score, then remember the position of all the boxes in boxes | |
| 257 // as their best position, and set best position score to current | |
| 258 // position score. | |
| 237 if (!shouldSwitchDirection(firstLineBox, step)) { | 259 if (!shouldSwitchDirection(firstLineBox, step)) { |
| 238 // 13. Move all the boxes in boxes ... | 260 // 22. Move all the boxes in boxes ... |
| 239 // 14. Jump back to the step labeled step loop. | |
| 240 moveBoxesByStep(step); | 261 moveBoxesByStep(step); |
| 262 // 23. Jump back to the step labeled step loop. | |
| 241 } else if (!switchDirection(switched, step)) { | 263 } else if (!switchDirection(switched, step)) { |
| 242 break; | 264 break; |
| 243 } | 265 } |
| 244 | 266 |
| 245 // 19. Jump back to the step labeled step loop. | 267 // 28. Jump back to the step labeled step loop. |
| 246 } | 268 } |
| 247 | 269 |
| 248 // Acommodate extra top and bottom padding, border or margin. | 270 // Acommodate extra top and bottom padding, border or margin. |
| 249 // Note: this is supported only for internal UA styling, not through the cue selector. | 271 // Note: this is supported only for internal UA styling, not through the cue selector. |
| 250 if (hasInlineDirectionBordersPaddingOrMargin()) { | 272 if (hasInlineDirectionBordersPaddingOrMargin()) { |
| 251 IntRect containerRect = containingBlock()->absoluteBoundingBoxRect(); | 273 IntRect containerRect = containingBlock()->absoluteBoundingBoxRect(); |
| 252 IntRect cueRect = absoluteBoundingBoxRect(); | 274 IntRect cueRect = absoluteBoundingBoxRect(); |
| 253 | 275 |
| 254 int topOverflow = cueRect.y() - containerRect.y(); | 276 int topOverflow = cueRect.y() - containerRect.y(); |
| 255 int bottomOverflow = containerRect.y() + containerRect.height() - cueRec t.y() - cueRect.height(); | 277 int bottomOverflow = containerRect.y() + containerRect.height() - cueRec t.y() - cueRect.height(); |
| 256 | 278 |
| 257 int adjustment = 0; | 279 int adjustment = 0; |
| 258 if (topOverflow < 0) | 280 if (topOverflow < 0) |
| 259 adjustment = -topOverflow; | 281 adjustment = -topOverflow; |
| 260 else if (bottomOverflow < 0) | 282 else if (bottomOverflow < 0) |
| 261 adjustment = bottomOverflow; | 283 adjustment = bottomOverflow; |
| 262 | 284 |
| 263 if (adjustment) | 285 if (adjustment) |
| 264 setY(location().y() + adjustment); | 286 setY(location().y() + adjustment); |
| 265 } | 287 } |
| 266 } | 288 } |
| 267 | 289 |
| 268 void RenderVTTCue::repositionCueSnapToLinesNotSet() | 290 void RenderVTTCue::repositionCueSnapToLinesNotSet() |
| 269 { | 291 { |
| 270 // FIXME: Implement overlapping detection when snap-to-lines is not set. htt p://wkb.ug/84296 | 292 // FIXME: Implement overlapping detection when snap-to-lines is not set. htt p://wkb.ug/84296 |
| 293 | |
| 294 // http://dev.w3.org/html5/webvtt/#dfn-apply-webvtt-cue-settings | |
| 295 // Step 13, "If cue's text track cue snap-to-lines flag is not set". | |
| 296 | |
| 297 // 1. Let bounding box be the bounding box of the boxes in boxes. | |
| 298 | |
| 299 // 2. Run the appropriate steps from the following list: | |
| 300 // If the text track cue writing direction is horizontal | |
| 301 // If the text track cue line alignment is middle alignment | |
| 302 // Move all the boxes in boxes up by half of the height of | |
| 303 // bounding box. | |
| 304 // If the text track cue line alignment is end alignment | |
| 305 // Move all the boxes in boxes up by the height of bounding box. | |
| 306 // | |
| 307 // If the text track cue writing direction is vertical growing left or | |
| 308 // vertical growing right | |
| 309 // If the text track cue line alignment is middle alignment | |
| 310 // Move all the boxes in boxes left by half of the width of | |
| 311 // bounding box. | |
| 312 // If the text track cue line alignment is end alignment | |
| 313 // Move all the boxes in boxes left by the width of bounding box. | |
| 314 | |
| 315 // 3. If none of the boxes in boxes would overlap any of the boxes in | |
| 316 // output, and all the boxes in output are within the video's rendering | |
| 317 // area, then jump to the step labeled done positioning below. | |
| 318 | |
| 319 // 4. If there is a position to which the boxes in boxes can be moved while | |
| 320 // maintaining the relative positions of the boxes in boxes to each other | |
| 321 // such that none of the boxes in boxes would overlap any of the boxes in | |
| 322 // output, and all the boxes in output would be within the video's | |
| 323 // rendering area, then move the boxes in boxes to the closest such | |
| 324 // position to their current position, and then jump to the step labeled | |
| 325 // done positioning below. If there are multiple such positions that are | |
| 326 // equidistant from their current position, use the highest one amongst | |
| 327 // them; if there are several at that height, then use the leftmost one | |
| 328 // amongst them. | |
| 329 | |
| 330 // 5. Otherwise, jump to the step labeled done positioning below. (The | |
| 331 // boxes will unfortunately overlap.) | |
| 271 } | 332 } |
| 272 | 333 |
| 273 } // namespace blink | 334 } // namespace blink |
| 274 | 335 |
| OLD | NEW |