RenderTextTrackCue.cpp [plain text]
#include "config.h"
#if ENABLE(VIDEO_TRACK)
#include "RenderTextTrackCue.h"
#include "TextTrackCue.h"
#include "TextTrackCueGeneric.h"
#include <wtf/StackStats.h>
namespace WebCore {
RenderTextTrackCue::RenderTextTrackCue(TextTrackCueBox* element)
: RenderBlock(element)
, m_cue(element->getCue())
{
}
void RenderTextTrackCue::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
RenderBlock::layout();
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
if (m_cue->cueType()== TextTrackCue::WebVTT) {
if (m_cue->snapToLines())
repositionCueSnapToLinesSet();
else
repositionCueSnapToLinesNotSet();
} else
repositionGenericCue();
statePusher.pop();
}
bool RenderTextTrackCue::initializeLayoutParameters(InlineFlowBox*& firstLineBox, LayoutUnit& step, LayoutUnit& position)
{
ASSERT(firstChild());
RenderBlock* parentBlock = containingBlock();
firstLineBox = toRenderInline(firstChild())->firstLineBox();
step = m_cue->getWritingDirection() == TextTrackCue::Horizontal ? firstLineBox->height() : firstLineBox->width();
if (!step)
return false;
int linePosition = m_cue->calculateComputedLinePosition();
if (m_cue->getWritingDirection() == TextTrackCue::VerticalGrowingLeft)
linePosition = -(linePosition + 1);
position = step * linePosition;
if (m_cue->getWritingDirection() == TextTrackCue::VerticalGrowingLeft) {
position -= width();
position += step;
}
if (linePosition < 0) {
position += m_cue->getWritingDirection() == TextTrackCue::Horizontal ? parentBlock->height() : parentBlock->width();
step = -step;
}
return true;
}
void RenderTextTrackCue::placeBoxInDefaultPosition(LayoutUnit position, bool& switched)
{
if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
setY(y() + position);
else
setX(x() + position);
m_fallbackPosition = FloatPoint(x(), y());
switched = false;
}
bool RenderTextTrackCue::isOutside() const
{
return !rectIsWithinContainer(absoluteContentBox());
}
bool RenderTextTrackCue::rectIsWithinContainer(const IntRect& rect) const
{
return containingBlock()->absoluteBoundingBoxRect().contains(rect);
}
bool RenderTextTrackCue::isOverlapping() const
{
return overlappingObject();
}
RenderObject* RenderTextTrackCue::overlappingObject() const
{
return overlappingObjectForRect(absoluteBoundingBoxRect());
}
RenderObject* RenderTextTrackCue::overlappingObjectForRect(const IntRect& rect) const
{
for (RenderObject* box = previousSibling(); box; box = box->previousSibling()) {
IntRect boxRect = box->absoluteBoundingBoxRect();
if (rect.intersects(boxRect))
return box;
}
return 0;
}
bool RenderTextTrackCue::shouldSwitchDirection(InlineFlowBox* firstLineBox, LayoutUnit step) const
{
LayoutUnit top = y();
LayoutUnit left = x();
LayoutUnit bottom = top + firstLineBox->height();
LayoutUnit right = left + firstLineBox->width();
LayoutUnit parentHeight = containingBlock()->height();
if (m_cue->getWritingDirection() == TextTrackCue::Horizontal && ((step < 0 && top < 0) || (step > 0 && bottom > parentHeight)))
return true;
LayoutUnit parentWidth = containingBlock()->width();
if (m_cue->getWritingDirection() != TextTrackCue::Horizontal && ((step < 0 && left < 0) || (step > 0 && right > parentWidth)))
return true;
return false;
}
void RenderTextTrackCue::moveBoxesByStep(LayoutUnit step)
{
if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
setY(y() + step);
else
setX(x() + step);
}
bool RenderTextTrackCue::switchDirection(bool& switched, LayoutUnit& step)
{
setX(m_fallbackPosition.x());
setY(m_fallbackPosition.y());
if (switched)
return false;
step = -step;
switched = true;
return true;
}
void RenderTextTrackCue::moveIfNecessaryToKeepWithinContainer()
{
IntRect containerRect = containingBlock()->absoluteBoundingBoxRect();
IntRect cueRect = absoluteBoundingBoxRect();
int topOverflow = cueRect.y() - containerRect.y();
int bottomOverflow = containerRect.maxY() - cueRect.maxY();
int verticalAdjustment = 0;
if (topOverflow < 0)
verticalAdjustment = -topOverflow;
else if (bottomOverflow < 0)
verticalAdjustment = bottomOverflow;
if (verticalAdjustment)
setY(y() + verticalAdjustment);
int leftOverflow = cueRect.x() - containerRect.x();
int rightOverflow = containerRect.maxX() - cueRect.maxX();
int horizontalAdjustment = 0;
if (leftOverflow < 0)
horizontalAdjustment = -leftOverflow;
else if (rightOverflow < 0)
horizontalAdjustment = rightOverflow;
if (horizontalAdjustment)
setX(x() + horizontalAdjustment);
}
bool RenderTextTrackCue::findNonOverlappingPosition(int& newX, int& newY) const
{
newX = x();
newY = y();
IntRect srcRect = absoluteBoundingBoxRect();
IntRect destRect = srcRect;
while (RenderObject* box = overlappingObjectForRect(destRect)) {
if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
destRect.setY(box->absoluteBoundingBoxRect().y() - destRect.height());
else
destRect.setX(box->absoluteBoundingBoxRect().x() - destRect.width());
}
if (rectIsWithinContainer(destRect)) {
newX += destRect.x() - srcRect.x();
newY += destRect.y() - srcRect.y();
return true;
}
destRect = srcRect;
while (RenderObject* box = overlappingObjectForRect(destRect)) {
if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
destRect.setY(box->absoluteBoundingBoxRect().maxY());
else
destRect.setX(box->absoluteBoundingBoxRect().maxX());
}
if (rectIsWithinContainer(destRect)) {
newX += destRect.x() - srcRect.x();
newY += destRect.y() - srcRect.y();
return true;
}
return false;
}
void RenderTextTrackCue::repositionCueSnapToLinesSet()
{
InlineFlowBox* firstLineBox;
LayoutUnit step;
LayoutUnit position;
if (!initializeLayoutParameters(firstLineBox, step, position))
return;
bool switched;
placeBoxInDefaultPosition(position, switched);
while (isOutside() || isOverlapping()) {
if (!shouldSwitchDirection(firstLineBox, step))
moveBoxesByStep(step);
else if (!switchDirection(switched, step))
break;
}
if (hasInlineDirectionBordersPaddingOrMargin())
moveIfNecessaryToKeepWithinContainer();
}
void RenderTextTrackCue::repositionGenericCue()
{
ASSERT(firstChild());
InlineFlowBox* firstLineBox = toRenderInline(firstChild())->firstLineBox();
if (static_cast<TextTrackCueGeneric*>(m_cue)->useDefaultPosition() && firstLineBox) {
LayoutUnit parentWidth = containingBlock()->logicalWidth();
LayoutUnit width = firstLineBox->width();
LayoutUnit right = (parentWidth / 2) - (width / 2);
setX(right);
}
repositionCueSnapToLinesNotSet();
}
void RenderTextTrackCue::repositionCueSnapToLinesNotSet()
{
if (!isOutside() && !isOverlapping())
return;
moveIfNecessaryToKeepWithinContainer();
int x = 0;
int y = 0;
if (!findNonOverlappingPosition(x, y))
return;
setX(x);
setY(y);
}
}
#endif