#include "config.h"
#include "RenderInline.h"
#include "Chrome.h"
#include "FloatQuad.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
#include "InlineTextBox.h"
#include "Page.h"
#include "RenderArena.h"
#include "RenderBlock.h"
#include "RenderLayer.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "TransformState.h"
#include "VisiblePosition.h"
#if ENABLE(DASHBOARD_SUPPORT)
#include "Frame.h"
#endif
using namespace std;
namespace WebCore {
RenderInline::RenderInline(Node* node)
: RenderBoxModelObject(node)
, m_alwaysCreateLineBoxes(false)
{
setChildrenInline(true);
}
void RenderInline::willBeDestroyed()
{
#if !ASSERT_DISABLED
if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
if (containingBlockPaintsContinuationOutline) {
if (RenderBlock* cb = containingBlock()) {
if (RenderBlock* cbCb = cb->containingBlock())
ASSERT(!cbCb->paintsContinuationOutline(this));
}
}
}
#endif
children()->destroyLeftoverChildren();
RenderBoxModelObject* continuation = this->continuation();
if (continuation) {
continuation->destroy();
setContinuation(0);
}
if (!documentBeingDestroyed()) {
if (firstLineBox()) {
if (isSelectionBorder())
view()->clearSelection();
if (firstLineBox()->parent()) {
for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
box->remove();
}
} else if (parent())
parent()->dirtyLinesFromChangedChild(this);
}
m_lineBoxes.deleteLineBoxes(renderArena());
RenderBoxModelObject::willBeDestroyed();
}
RenderInline* RenderInline::inlineElementContinuation() const
{
RenderBoxModelObject* continuation = this->continuation();
if (!continuation || continuation->isInline())
return toRenderInline(continuation);
return toRenderBlock(continuation)->inlineElementContinuation();
}
void RenderInline::updateBoxModelInfoFromStyle()
{
RenderBoxModelObject::updateBoxModelInfoFromStyle();
setInline(true);
setHasTransform(false);
setHasReflection(false);
}
static bool hasRelPositionedInlineAncestor(RenderObject* p)
{
while (p && p->isRenderInline()) {
if (p->isRelPositioned())
return true;
p = p->parent();
}
return false;
}
static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
{
for (;block && block->isAnonymousBlock(); block = block->nextSibling()) {
if (!toRenderBlock(block)->isAnonymousBlockContinuation() || block->style()->position() == newStyle->position())
continue;
RenderInline* cont = toRenderBlock(block)->inlineElementContinuation();
if (oldStyle->position() == RelativePosition && hasRelPositionedInlineAncestor(cont))
continue;
RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), BLOCK);
blockStyle->setPosition(newStyle->position());
block->setStyle(blockStyle);
}
}
void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBoxModelObject::styleDidChange(diff, oldStyle);
RenderStyle* newStyle = style();
RenderInline* continuation = inlineElementContinuation();
for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
RenderBoxModelObject* nextCont = currCont->continuation();
currCont->setContinuation(0);
currCont->setStyle(newStyle);
currCont->setContinuation(nextCont);
}
if (continuation && oldStyle && newStyle->position() != oldStyle->position()
&& (newStyle->position() == RelativePosition || (oldStyle->position() == RelativePosition))) {
RenderObject* block = containingBlock()->nextSibling();
ASSERT(block && block->isAnonymousBlock());
updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
}
if (!m_alwaysCreateLineBoxes) {
bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
if (oldStyle && alwaysCreateLineBoxes) {
dirtyLineBoxes(false);
setNeedsLayout(true);
}
m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
}
if (!isAnonymous() && document()->usesBeforeAfterRules()) {
children()->updateBeforeAfterContent(this, BEFORE);
children()->updateBeforeAfterContent(this, AFTER);
}
}
void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
{
if (m_alwaysCreateLineBoxes)
return;
RenderStyle* parentStyle = parent()->style();
RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
bool checkFonts = document()->inNoQuirksMode();
bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
|| (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
|| style()->verticalAlign() != BASELINE
|| style()->textEmphasisMark() != TextEmphasisMarkNone
|| (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
|| parentStyle->lineHeight() != style()->lineHeight()));
if (!alwaysCreateLineBoxes && checkFonts && document()->usesFirstLineRules()) {
parentStyle = parent()->style(true);
RenderStyle* childStyle = style(true);
alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
|| childStyle->verticalAlign() != BASELINE
|| parentStyle->lineHeight() != childStyle->lineHeight();
}
if (alwaysCreateLineBoxes) {
if (!fullLayout)
dirtyLineBoxes(false);
m_alwaysCreateLineBoxes = true;
}
}
void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
if (continuation())
return addChildToContinuation(newChild, beforeChild);
return addChildIgnoringContinuation(newChild, beforeChild);
}
static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
{
if (renderer->isInline() && !renderer->isReplaced())
return toRenderInline(renderer)->continuation();
return toRenderBlock(renderer)->inlineElementContinuation();
}
RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
{
if (beforeChild && beforeChild->parent() == this)
return this;
RenderBoxModelObject* curr = nextContinuation(this);
RenderBoxModelObject* nextToLast = this;
RenderBoxModelObject* last = this;
while (curr) {
if (beforeChild && beforeChild->parent() == curr) {
if (curr->firstChild() == beforeChild)
return last;
return curr;
}
nextToLast = last;
last = curr;
curr = nextContinuation(curr);
}
if (!beforeChild && !last->firstChild())
return nextToLast;
return last;
}
void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
{
if (!beforeChild && isAfterContent(lastChild()))
beforeChild = lastChild();
if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
if (hasRelPositionedInlineAncestor(this))
newStyle->setPosition(RelativePosition);
RenderBlock* newBox = new (renderArena()) RenderBlock(document() );
newBox->setStyle(newStyle.release());
RenderBoxModelObject* oldContinuation = continuation();
setContinuation(newBox);
bool isLastChild = (beforeChild == lastChild());
if (document()->usesBeforeAfterRules())
children()->updateBeforeAfterContent(this, AFTER);
if (isLastChild && beforeChild != lastChild())
beforeChild = 0;
splitFlow(beforeChild, newBox, newChild, oldContinuation);
return;
}
RenderBoxModelObject::addChild(newChild, beforeChild);
newChild->setNeedsLayoutAndPrefWidthsRecalc();
}
RenderInline* RenderInline::cloneInline(RenderInline* src)
{
RenderInline* o = new (src->renderArena()) RenderInline(src->node());
o->setStyle(src->style());
return o;
}
void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
RenderBlock* middleBlock,
RenderObject* beforeChild, RenderBoxModelObject* oldCont)
{
RenderInline* clone = cloneInline(this);
clone->setContinuation(oldCont);
RenderObject* o = beforeChild;
while (o) {
RenderObject* tmp = o;
o = tmp->nextSibling();
clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
tmp->setNeedsLayoutAndPrefWidthsRecalc();
}
middleBlock->setContinuation(clone);
RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
RenderBoxModelObject* currChild = this;
unsigned splitDepth = 1;
const unsigned cMaxSplitDepth = 200;
while (curr && curr != fromBlock) {
ASSERT(curr->isRenderInline());
if (splitDepth < cMaxSplitDepth) {
RenderInline* cloneChild = clone;
clone = cloneInline(toRenderInline(curr));
clone->addChildIgnoringContinuation(cloneChild, 0);
RenderInline* inlineCurr = toRenderInline(curr);
oldCont = inlineCurr->continuation();
inlineCurr->setContinuation(clone);
clone->setContinuation(oldCont);
if (document()->usesBeforeAfterRules())
inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
o = currChild->nextSibling();
while (o) {
RenderObject* tmp = o;
o = tmp->nextSibling();
clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
tmp->setNeedsLayoutAndPrefWidthsRecalc();
}
}
currChild = curr;
curr = toRenderBoxModelObject(curr->parent());
splitDepth++;
}
toBlock->children()->appendChildNode(toBlock, clone);
o = currChild->nextSibling();
while (o) {
RenderObject* tmp = o;
o = tmp->nextSibling();
toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
}
}
void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
RenderObject* newChild, RenderBoxModelObject* oldCont)
{
RenderBlock* pre = 0;
RenderBlock* block = containingBlock();
block->deleteLineBoxTree();
bool madeNewBeforeBlock = false;
if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
pre = block;
pre->removePositionedObjects(0);
block = block->containingBlock();
} else {
pre = block->createAnonymousBlock();
madeNewBeforeBlock = true;
}
RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
if (madeNewBeforeBlock)
block->children()->insertChildNode(block, pre, boxFirst);
block->children()->insertChildNode(block, newBlockBox, boxFirst);
block->children()->insertChildNode(block, post, boxFirst);
block->setChildrenInline(false);
if (madeNewBeforeBlock) {
RenderObject* o = boxFirst;
while (o) {
RenderObject* no = o;
o = no->nextSibling();
pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
no->setNeedsLayoutAndPrefWidthsRecalc();
}
}
splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
newBlockBox->setChildrenInline(false);
newBlockBox->addChild(newChild);
pre->setNeedsLayoutAndPrefWidthsRecalc();
block->setNeedsLayoutAndPrefWidthsRecalc();
post->setNeedsLayoutAndPrefWidthsRecalc();
}
void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
{
RenderBoxModelObject* flow = continuationBefore(beforeChild);
ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
RenderBoxModelObject* beforeChildParent = 0;
if (beforeChild)
beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
else {
RenderBoxModelObject* cont = nextContinuation(flow);
if (cont)
beforeChildParent = cont;
else
beforeChildParent = flow;
}
if (newChild->isFloatingOrPositioned())
return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
bool childInline = newChild->isInline();
bool bcpInline = beforeChildParent->isInline();
bool flowInline = flow->isInline();
if (flow == beforeChildParent)
return flow->addChildIgnoringContinuation(newChild, beforeChild);
else {
if (childInline == bcpInline)
return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
else if (flowInline == childInline)
return flow->addChildIgnoringContinuation(newChild, 0); else
return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
}
}
void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
m_lineBoxes.paint(this, paintInfo, paintOffset);
}
void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
{
if (!alwaysCreateLineBoxes())
culledInlineAbsoluteRects(this, rects, toLayoutSize(accumulatedOffset));
else if (InlineFlowBox* curr = firstLineBox()) {
for (; curr; curr = curr->nextLineBox())
rects.append(enclosingIntRect(FloatRect(accumulatedOffset + curr->topLeft(), curr->size())));
} else
rects.append(IntRect(roundedIntPoint(accumulatedOffset), IntSize()));
if (continuation()) {
if (continuation()->isBox()) {
RenderBox* box = toRenderBox(continuation());
continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->size()));
} else
continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
}
}
void RenderInline::culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>& rects, const LayoutSize& offset) const
{
if (!culledInlineFirstLineBox()) {
rects.append(IntRect(offset.width(), offset.height(), 0, 0));
return;
}
bool isHorizontal = style()->isHorizontalWritingMode();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox()) {
RenderBox* currBox = toRenderBox(curr);
if (currBox->inlineBoxWrapper()) {
RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
FloatRect result;
if (isHorizontal)
result = FloatRect(offset.width() + currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), offset.height() + logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight);
else
result = FloatRect(offset.width() + logicalTop, offset.height() + currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight());
rects.append(enclosingIntRect(result));
}
} else if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
if (!currInline->alwaysCreateLineBoxes())
currInline->culledInlineAbsoluteRects(container, rects, offset);
else {
for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
RootInlineBox* rootBox = childLine->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
FloatRect result;
if (isHorizontal)
result = FloatRect(offset.width() + childLine->x() - childLine->marginLogicalLeft(),
offset.height() + logicalTop,
childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
logicalHeight);
else
result = FloatRect(offset.width() + logicalTop,
offset.height() + childLine->y() - childLine->marginLogicalLeft(),
logicalHeight,
childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
rects.append(enclosingIntRect(result));
}
}
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
RootInlineBox* rootBox = childText->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
FloatRect result;
if (isHorizontal)
result = FloatRect(offset.width() + childText->x(), offset.height() + logicalTop, childText->logicalWidth(), logicalHeight);
else
result = FloatRect(offset.width() + logicalTop, offset.height() + childText->y(), logicalHeight, childText->logicalWidth());
rects.append(enclosingIntRect(result));
}
}
}
}
void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
{
if (!alwaysCreateLineBoxes())
culledInlineAbsoluteQuads(this, quads);
else if (InlineFlowBox* curr = firstLineBox()) {
for (; curr; curr = curr->nextLineBox()) {
FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
quads.append(localToAbsoluteQuad(localRect, false, wasFixed));
}
} else
quads.append(localToAbsoluteQuad(FloatRect(), false, wasFixed));
if (continuation())
continuation()->absoluteQuads(quads, wasFixed);
}
void RenderInline::culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>& quads) const
{
if (!culledInlineFirstLineBox()) {
quads.append(localToAbsoluteQuad(FloatRect()));
return;
}
bool isHorizontal = style()->isHorizontalWritingMode();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox()) {
RenderBox* currBox = toRenderBox(curr);
if (currBox->inlineBoxWrapper()) {
RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
FloatRect result;
if (isHorizontal)
result = FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight);
else
result = FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight());
quads.append(localToAbsoluteQuad(result));
}
} else if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
if (!currInline->alwaysCreateLineBoxes())
currInline->culledInlineAbsoluteQuads(container, quads);
else {
for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
RootInlineBox* rootBox = childLine->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
FloatRect result;
if (isHorizontal)
result = FloatRect(childLine->x() - childLine->marginLogicalLeft(),
logicalTop,
childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
logicalHeight);
else
result = FloatRect(logicalTop,
childLine->y() - childLine->marginLogicalLeft(),
logicalHeight,
childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
quads.append(localToAbsoluteQuad(result));
}
}
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
RootInlineBox* rootBox = childText->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
FloatRect result;
if (isHorizontal)
result = FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight);
else
result = FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth());
quads.append(localToAbsoluteQuad(result));
}
}
}
}
LayoutUnit RenderInline::offsetLeft() const
{
LayoutUnit x = RenderBoxModelObject::offsetLeft();
if (InlineBox* firstBox = firstLineBoxIncludingCulling())
x += firstBox->x();
return x;
}
LayoutUnit RenderInline::offsetTop() const
{
LayoutUnit y = RenderBoxModelObject::offsetTop();
if (InlineBox* firstBox = firstLineBoxIncludingCulling())
y += firstBox->y();
return y;
}
static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
{
if (margin.isAuto())
return 0;
if (margin.isFixed())
return margin.value();
if (margin.isPercent())
return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
if (margin.isViewportPercentage())
return valueForLength(margin, 0, renderer->view());
return 0;
}
LayoutUnit RenderInline::marginLeft() const
{
return computeMargin(this, style()->marginLeft());
}
LayoutUnit RenderInline::marginRight() const
{
return computeMargin(this, style()->marginRight());
}
LayoutUnit RenderInline::marginTop() const
{
return computeMargin(this, style()->marginTop());
}
LayoutUnit RenderInline::marginBottom() const
{
return computeMargin(this, style()->marginBottom());
}
LayoutUnit RenderInline::marginStart() const
{
return computeMargin(this, style()->marginStart());
}
LayoutUnit RenderInline::marginEnd() const
{
return computeMargin(this, style()->marginEnd());
}
LayoutUnit RenderInline::marginBefore() const
{
return computeMargin(this, style()->marginBefore());
}
LayoutUnit RenderInline::marginAfter() const
{
return computeMargin(this, style()->marginAfter());
}
const char* RenderInline::renderName() const
{
if (isRelPositioned())
return "RenderInline (relative positioned)";
if (isAnonymous())
return "RenderInline (generated)";
if (isRunIn())
return "RenderInline (run-in)";
return "RenderInline";
}
bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
{
return m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction);
}
VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point)
{
RenderBlock* cb = containingBlock();
if (firstLineBox()) {
return cb->positionForPoint(point);
}
LayoutPoint parentBlockPoint = cb->location() + point;
RenderBoxModelObject* c = continuation();
while (c) {
RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
if (c->isInline() || c->firstChild())
return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
c = toRenderBlock(c)->inlineElementContinuation();
}
return RenderBoxModelObject::positionForPoint(point);
}
IntRect RenderInline::linesBoundingBox() const
{
if (!alwaysCreateLineBoxes()) {
ASSERT(!firstLineBox());
return enclosingIntRect(culledInlineBoundingBox(this));
}
IntRect result;
ASSERT(!firstLineBox() == !lastLineBox()); if (firstLineBox() && lastLineBox()) {
float logicalLeftSide = 0;
float logicalRightSide = 0;
for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
logicalLeftSide = curr->logicalLeft();
if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
logicalRightSide = curr->logicalRight();
}
bool isHorizontal = style()->isHorizontalWritingMode();
float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
result = enclosingIntRect(FloatRect(x, y, width, height));
}
return result;
}
FloatRect RenderInline::culledInlineBoundingBox(const RenderInline* container) const
{
FloatRect result;
bool isHorizontal = style()->isHorizontalWritingMode();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox()) {
RenderBox* currBox = toRenderBox(curr);
if (currBox->inlineBoxWrapper()) {
RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
if (isHorizontal)
result.uniteIfNonZero(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight));
else
result.uniteIfNonZero(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight()));
}
} else if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
if (!currInline->alwaysCreateLineBoxes())
result.uniteIfNonZero(currInline->culledInlineBoundingBox(container));
else {
for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
RootInlineBox* rootBox = childLine->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
if (isHorizontal)
result.uniteIfNonZero(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
logicalTop,
childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
logicalHeight));
else
result.uniteIfNonZero(FloatRect(logicalTop,
childLine->y() - childLine->marginLogicalLeft(),
logicalHeight,
childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
}
}
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
RootInlineBox* rootBox = childText->root();
int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
if (isHorizontal)
result.uniteIfNonZero(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
else
result.uniteIfNonZero(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
}
}
}
return enclosingLayoutRect(result);
}
InlineBox* RenderInline::culledInlineFirstLineBox() const
{
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox())
return toRenderBox(curr)->inlineBoxWrapper();
if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
InlineBox* result = currInline->firstLineBoxIncludingCulling();
if (result)
return result;
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
if (currText->firstTextBox())
return currText->firstTextBox();
}
}
return 0;
}
InlineBox* RenderInline::culledInlineLastLineBox() const
{
for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox())
return toRenderBox(curr)->inlineBoxWrapper();
if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
InlineBox* result = currInline->lastLineBoxIncludingCulling();
if (result)
return result;
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
if (currText->lastTextBox())
return currText->lastTextBox();
}
}
return 0;
}
LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
{
LayoutRect result(culledInlineBoundingBox(this));
bool isHorizontal = style()->isHorizontalWritingMode();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox()) {
RenderBox* currBox = toRenderBox(curr);
if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
if (isHorizontal) {
logicalRect.moveBy(currBox->location());
result.uniteIfNonZero(logicalRect);
} else {
logicalRect.moveBy(currBox->location());
result.uniteIfNonZero(logicalRect.transposedRect());
}
}
} else if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
if (!currInline->alwaysCreateLineBoxes())
result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
else if (!currInline->hasSelfPaintingLayer())
result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
}
}
return result;
}
LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
{
if (!alwaysCreateLineBoxes())
return culledInlineVisualOverflowBoundingBox();
if (!firstLineBox() || !lastLineBox())
return LayoutRect();
LayoutUnit logicalLeftSide = MAX_LAYOUT_UNIT;
LayoutUnit logicalRightSide = MIN_LAYOUT_UNIT;
for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
}
RootInlineBox* firstRootBox = firstLineBox()->root();
RootInlineBox* lastRootBox = lastLineBox()->root();
LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
if (!style()->isHorizontalWritingMode())
rect = rect.transposedRect();
return rect;
}
LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
{
ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
if (!firstLineBoxIncludingCulling() && !continuation())
return LayoutRect();
LayoutRect boundingBox(linesVisualOverflowBoundingBox());
LayoutUnit left = boundingBox.x();
LayoutUnit top = boundingBox.y();
LayoutUnit ow = style() ? style()->outlineSize() : 0;
bool hitRepaintContainer = false;
RenderBlock* cb = containingBlock();
for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
inlineFlow = inlineFlow->parent()) {
if (inlineFlow == repaintContainer) {
hitRepaintContainer = true;
break;
}
if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
}
LayoutRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
if (hitRepaintContainer || !cb)
return r;
if (cb->hasColumns())
cb->adjustRectForColumns(r);
if (cb->hasOverflowClip()) {
LayoutRect repaintRect(r);
repaintRect.move(-cb->scrolledContentOffset());
LayoutRect boxRect(LayoutPoint(), cb->cachedSizeForOverflowClip());
r = intersection(repaintRect, boxRect);
}
cb->computeRectForRepaint(repaintContainer, r);
if (ow) {
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText()) {
LayoutRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
r.unite(childRect);
}
}
if (continuation() && !continuation()->isInline() && continuation()->parent()) {
LayoutRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
r.unite(contRect);
}
}
return r;
}
LayoutRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const
{
LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText())
r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
}
return r;
}
void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
{
if (RenderView* v = view()) {
if (v->layoutStateEnabled() && !repaintContainer) {
LayoutState* layoutState = v->layoutState();
if (style()->position() == RelativePosition && layer())
rect.move(layer()->relativePositionOffset());
rect.move(layoutState->m_paintOffset);
if (layoutState->m_clipped)
rect.intersect(layoutState->m_clipRect);
return;
}
}
if (repaintContainer == this)
return;
bool containerSkipped;
RenderObject* o = container(repaintContainer, &containerSkipped);
if (!o)
return;
LayoutPoint topLeft = rect.location();
if (o->isBlockFlow() && !style()->isPositioned()) {
RenderBlock* cb = toRenderBlock(o);
if (cb->hasColumns()) {
LayoutRect repaintRect(topLeft, rect.size());
cb->adjustRectForColumns(repaintRect);
topLeft = repaintRect.location();
rect = repaintRect;
}
}
if (style()->position() == RelativePosition && layer()) {
topLeft += layer()->relativePositionOffset();
}
if (o->hasOverflowClip()) {
RenderBox* containerBox = toRenderBox(o);
topLeft -= containerBox->scrolledContentOffset();
LayoutRect repaintRect(topLeft, rect.size());
LayoutRect boxRect(LayoutPoint(), containerBox->cachedSizeForOverflowClip());
rect = intersection(repaintRect, boxRect);
if (rect.isEmpty())
return;
} else
rect.setLocation(topLeft);
if (containerSkipped) {
LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
rect.move(-containerOffset);
return;
}
o->computeRectForRepaint(repaintContainer, rect, fixed);
}
LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point) const
{
ASSERT(container == this->container());
LayoutSize offset;
if (isRelPositioned())
offset += relativePositionOffset();
container->adjustForColumns(offset, point);
if (container->hasOverflowClip())
offset -= toRenderBox(container)->scrolledContentOffset();
return offset;
}
void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot applyContainerFlip, bool* wasFixed) const
{
if (repaintContainer == this)
return;
if (RenderView *v = view()) {
if (v->layoutStateEnabled() && !repaintContainer) {
LayoutState* layoutState = v->layoutState();
LayoutSize offset = layoutState->m_paintOffset;
if (style()->position() == RelativePosition && layer())
offset += layer()->relativePositionOffset();
transformState.move(offset);
return;
}
}
bool containerSkipped;
RenderObject* o = container(repaintContainer, &containerSkipped);
if (!o)
return;
if (applyContainerFlip && o->isBox() && o->style()->isFlippedBlocksWritingMode()) {
IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint);
applyContainerFlip = DoNotApplyContainerFlip;
}
LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
if (useTransforms && shouldUseTransformFromContainer(o)) {
TransformationMatrix t;
getTransformFromContainer(o, containerOffset, t);
transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
} else
transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
if (containerSkipped) {
LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
return;
}
o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, applyContainerFlip, wasFixed);
}
void RenderInline::updateDragState(bool dragOn)
{
RenderBoxModelObject::updateDragState(dragOn);
if (continuation())
continuation()->updateDragState(dragOn);
}
void RenderInline::childBecameNonInline(RenderObject* child)
{
RenderBlock* newBox = containingBlock()->createAnonymousBlock();
RenderBoxModelObject* oldContinuation = continuation();
setContinuation(newBox);
RenderObject* beforeChild = child->nextSibling();
children()->removeChildNode(this, child);
splitFlow(beforeChild, newBox, child, oldContinuation);
}
void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
{
if (result.innerNode())
return;
Node* n = node();
LayoutPoint localPoint(point);
if (n) {
if (isInlineElementContinuation()) {
RenderBlock* firstBlock = n->renderer()->containingBlock();
RenderBox* block = containingBlock();
localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
}
result.setInnerNode(n);
if (!result.innerNonSharedNode())
result.setInnerNonSharedNode(n);
result.setLocalPoint(localPoint);
}
}
void RenderInline::dirtyLineBoxes(bool fullLayout)
{
if (fullLayout) {
m_lineBoxes.deleteLineBoxes(renderArena());
return;
}
if (!alwaysCreateLineBoxes()) {
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrPositioned())
continue;
if (curr->isBox() && !curr->needsLayout()) {
RenderBox* currBox = toRenderBox(curr);
if (currBox->inlineBoxWrapper())
currBox->inlineBoxWrapper()->root()->markDirty();
} else if (!curr->selfNeedsLayout()) {
if (curr->isRenderInline()) {
RenderInline* currInline = toRenderInline(curr);
for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
childLine->root()->markDirty();
} else if (curr->isText()) {
RenderText* currText = toRenderText(curr);
for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
childText->root()->markDirty();
}
}
}
} else
m_lineBoxes.dirtyLineBoxes();
}
InlineFlowBox* RenderInline::createInlineFlowBox()
{
return new (renderArena()) InlineFlowBox(this);
}
InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
{
setAlwaysCreateLineBoxes();
InlineFlowBox* flowBox = createInlineFlowBox();
m_lineBoxes.appendLineBox(flowBox);
return flowBox;
}
LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode , LinePositionMode ) const
{
if (firstLine && document()->usesFirstLineRules()) {
RenderStyle* s = style(firstLine);
if (s != style())
return s->computedLineHeight(view());
}
return style()->computedLineHeight(view());
}
LayoutUnit RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
}
LayoutSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
{
ASSERT(isRelPositioned());
if (!isRelPositioned())
return LayoutSize();
LayoutSize logicalOffset;
LayoutUnit inlinePosition;
LayoutUnit blockPosition;
if (firstLineBox()) {
inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft());
blockPosition = firstLineBox()->logicalTop();
} else {
inlinePosition = layer()->staticInlinePosition();
blockPosition = layer()->staticBlockPosition();
}
if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
logicalOffset.setWidth(inlinePosition);
else if (!child->style()->isOriginalDisplayInlineType())
logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
logicalOffset.setHeight(blockPosition);
return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
}
void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
{
if (!parent())
return;
repaint();
}
void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
{
if (!alwaysCreateLineBoxes())
culledInlineAbsoluteRects(this, rects, toLayoutSize(additionalOffset));
else {
for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
rects.append(enclosingIntRect(FloatRect(additionalOffset.x() + curr->x(), additionalOffset.y() + curr->y(), curr->width(), curr->height())));
}
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText() && !curr->isListMarker()) {
FloatPoint pos(additionalOffset);
if (curr->hasLayer())
pos = curr->localToAbsolute();
else if (curr->isBox())
pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
curr->addFocusRingRects(rects, flooredIntPoint(pos));
}
}
if (continuation()) {
if (continuation()->isInline())
continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()));
else
continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()));
}
}
void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset)
{
if (!hasOutline())
return;
RenderStyle* styleToUse = style();
if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
if (!theme()->supportsFocusRing(styleToUse)) {
paintFocusRing(graphicsContext, paintOffset, styleToUse);
}
}
if (graphicsContext->paintingDisabled())
return;
if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
return;
Vector<LayoutRect> rects;
rects.append(LayoutRect());
for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
RootInlineBox* root = curr->root();
LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop());
LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom());
rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
}
rects.append(LayoutRect());
Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
bool useTransparencyLayer = outlineColor.hasAlpha();
if (useTransparencyLayer) {
graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
}
for (unsigned i = 1; i < rects.size() - 1; i++)
paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
if (useTransparencyLayer)
graphicsContext->endTransparencyLayer();
}
void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
const Color outlineColor)
{
RenderStyle* styleToUse = style();
int outlineWidth = styleToUse->outlineWidth();
EBorderStyle outlineStyle = styleToUse->outlineStyle();
bool antialias = shouldAntialiasLines(graphicsContext);
int offset = style()->outlineOffset();
LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
LayoutSize(thisline.width() + offset, thisline.height() + offset));
IntRect pixelSnappedBox = pixelSnappedIntRect(box);
IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
drawLineForBoxSide(graphicsContext,
pixelSnappedBox.x() - outlineWidth,
pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
pixelSnappedBox.x(),
pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
BSLeft,
outlineColor, outlineStyle,
(lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
(nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
antialias);
drawLineForBoxSide(graphicsContext,
pixelSnappedBox.maxX(),
pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
pixelSnappedBox.maxX() + outlineWidth,
pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
BSRight,
outlineColor, outlineStyle,
(lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
(nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
antialias);
if (thisline.x() < lastline.x())
drawLineForBoxSide(graphicsContext,
pixelSnappedBox.x() - outlineWidth,
pixelSnappedBox.y() - outlineWidth,
min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
pixelSnappedBox.y(),
BSTop, outlineColor, outlineStyle,
outlineWidth,
(!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
antialias);
if (lastline.maxX() < thisline.maxX())
drawLineForBoxSide(graphicsContext,
max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
pixelSnappedBox.y() - outlineWidth,
pixelSnappedBox.maxX() + outlineWidth,
pixelSnappedBox.y(),
BSTop, outlineColor, outlineStyle,
(!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
outlineWidth, antialias);
if (thisline.x() == thisline.maxX())
drawLineForBoxSide(graphicsContext,
pixelSnappedBox.x() - outlineWidth,
pixelSnappedBox.y() - outlineWidth,
pixelSnappedBox.maxX() + outlineWidth,
pixelSnappedBox.y(),
BSTop, outlineColor, outlineStyle,
outlineWidth,
outlineWidth,
antialias);
if (thisline.x() < nextline.x())
drawLineForBoxSide(graphicsContext,
pixelSnappedBox.x() - outlineWidth,
pixelSnappedBox.maxY(),
min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
pixelSnappedBox.maxY() + outlineWidth,
BSBottom, outlineColor, outlineStyle,
outlineWidth,
(!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
antialias);
if (nextline.maxX() < thisline.maxX())
drawLineForBoxSide(graphicsContext,
max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
pixelSnappedBox.maxY(),
pixelSnappedBox.maxX() + outlineWidth,
pixelSnappedBox.maxY() + outlineWidth,
BSBottom, outlineColor, outlineStyle,
(!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
outlineWidth, antialias);
if (thisline.x() == thisline.maxX())
drawLineForBoxSide(graphicsContext,
pixelSnappedBox.x() - outlineWidth,
pixelSnappedBox.maxY(),
pixelSnappedBox.maxX() + outlineWidth,
pixelSnappedBox.maxY() + outlineWidth,
BSBottom, outlineColor, outlineStyle,
outlineWidth,
outlineWidth,
antialias);
}
#if ENABLE(DASHBOARD_SUPPORT)
void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
{
if (style()->visibility() != VISIBLE)
return;
const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
unsigned i, count = styleRegions.size();
for (i = 0; i < count; i++) {
StyleDashboardRegion styleRegion = styleRegions[i];
LayoutRect linesBoundingBox = this->linesBoundingBox();
LayoutUnit w = linesBoundingBox.width();
LayoutUnit h = linesBoundingBox.height();
DashboardRegionValue region;
region.label = styleRegion.label;
region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
linesBoundingBox.y() + styleRegion.offset.top().value(),
w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
region.type = styleRegion.type;
RenderObject* container = containingBlock();
if (!container)
container = this;
region.clip = region.bounds;
container->computeAbsoluteRepaintRect(region.clip);
if (region.clip.height() < 0) {
region.clip.setHeight(0);
region.clip.setWidth(0);
}
FloatPoint absPos = container->localToAbsolute();
region.bounds.setX(absPos.x() + region.bounds.x());
region.bounds.setY(absPos.y() + region.bounds.y());
regions.append(region);
}
}
#endif
}