#include "config.h"
#include "RenderInline.h"
#include "Document.h"
#include "RenderArena.h"
#include "RenderBlock.h"
#include "VisiblePosition.h"
namespace WebCore {
RenderInline::RenderInline(Node* node)
: RenderFlow(node)
{
}
RenderInline::~RenderInline()
{
}
void RenderInline::setStyle(RenderStyle* newStyle)
{
RenderFlow::setStyle(newStyle);
setInline(true);
RenderFlow* currCont = continuation();
while (currCont) {
if (currCont->isInline()) {
RenderFlow* nextCont = currCont->continuation();
currCont->setContinuation(0);
currCont->setStyle(style());
currCont->setContinuation(nextCont);
}
currCont = currCont->continuation();
}
m_lineHeight = -1;
if (!isAnonymous()) {
updateBeforeAfterContent(RenderStyle::BEFORE);
updateBeforeAfterContent(RenderStyle::AFTER);
}
}
bool RenderInline::isInlineContinuation() const
{
return m_isContinuation;
}
static inline bool isAfterContent(RenderObject* child)
{
if (!child)
return false;
if (child->style()->styleType() != RenderStyle::AFTER)
return false;
if (child->isText() && !child->isBR())
return false;
return true;
}
void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild)
{
if (!beforeChild && isAfterContent(lastChild()))
beforeChild = lastChild();
if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
RenderStyle* newStyle = new (renderArena()) RenderStyle();
newStyle->inheritFrom(style());
newStyle->setDisplay(BLOCK);
RenderBlock* newBox = new (renderArena()) RenderBlock(document() );
newBox->setStyle(newStyle);
RenderFlow* oldContinuation = continuation();
setContinuation(newBox);
bool isLastChild = (beforeChild == lastChild());
updateBeforeAfterContent(RenderStyle::AFTER);
if (isLastChild && beforeChild != lastChild())
beforeChild = 0;
splitFlow(beforeChild, newBox, newChild, oldContinuation);
return;
}
RenderContainer::addChild(newChild, beforeChild);
newChild->setNeedsLayoutAndPrefWidthsRecalc();
}
RenderInline* RenderInline::cloneInline(RenderFlow* src)
{
RenderInline* o = new (src->renderArena()) RenderInline(src->element());
o->m_isContinuation = true;
o->setStyle(src->style());
return o;
}
void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
RenderBlock* middleBlock,
RenderObject* beforeChild, RenderFlow* oldCont)
{
RenderInline* clone = cloneInline(this);
clone->setContinuation(oldCont);
RenderObject* o = beforeChild;
while (o) {
RenderObject* tmp = o;
o = tmp->nextSibling();
clone->addChildToFlow(removeChildNode(tmp), 0);
tmp->setNeedsLayoutAndPrefWidthsRecalc();
}
middleBlock->setContinuation(clone);
RenderFlow* curr = static_cast<RenderFlow*>(parent());
RenderFlow* currChild = this;
unsigned splitDepth = 1;
const unsigned cMaxSplitDepth = 200;
while (curr && curr != fromBlock) {
if (splitDepth < cMaxSplitDepth) {
RenderInline* cloneChild = clone;
clone = cloneInline(curr);
clone->addChildToFlow(cloneChild, 0);
RenderFlow* oldCont = curr->continuation();
curr->setContinuation(clone);
clone->setContinuation(oldCont);
curr->updateBeforeAfterContent(RenderStyle::AFTER);
o = currChild->nextSibling();
while (o) {
RenderObject* tmp = o;
o = tmp->nextSibling();
clone->addChildToFlow(curr->removeChildNode(tmp), 0);
tmp->setNeedsLayoutAndPrefWidthsRecalc();
}
}
currChild = curr;
curr = static_cast<RenderFlow*>(curr->parent());
splitDepth++;
}
toBlock->appendChildNode(clone);
o = currChild->nextSibling();
while (o) {
RenderObject* tmp = o;
o = tmp->nextSibling();
toBlock->appendChildNode(fromBlock->removeChildNode(tmp));
}
}
void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
RenderObject* newChild, RenderFlow* oldCont)
{
RenderBlock* pre = 0;
RenderBlock* block = containingBlock();
block->deleteLineBoxTree();
bool madeNewBeforeBlock = false;
if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
pre = block;
block = block->containingBlock();
} else {
pre = block->createAnonymousBlock();
madeNewBeforeBlock = true;
}
RenderBlock* post = block->createAnonymousBlock();
RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
if (madeNewBeforeBlock)
block->insertChildNode(pre, boxFirst);
block->insertChildNode(newBlockBox, boxFirst);
block->insertChildNode(post, boxFirst);
block->setChildrenInline(false);
if (madeNewBeforeBlock) {
RenderObject* o = boxFirst;
while (o) {
RenderObject* no = o;
o = no->nextSibling();
pre->appendChildNode(block->removeChildNode(no));
no->setNeedsLayoutAndPrefWidthsRecalc();
}
}
splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
newBlockBox->setChildrenInline(false);
newBlockBox->addChildToFlow(newChild, 0);
pre->setNeedsLayoutAndPrefWidthsRecalc();
block->setNeedsLayoutAndPrefWidthsRecalc();
post->setNeedsLayoutAndPrefWidthsRecalc();
}
void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
{
paintLines(paintInfo, tx, ty);
}
void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel)
{
for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
rects.append(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height()));
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText())
curr->absoluteRects(rects, tx + curr->xPos(), ty + curr->yPos(), false);
}
if (continuation() && topLevel)
continuation()->absoluteRects(rects,
tx - containingBlock()->xPos() + continuation()->xPos(),
ty - containingBlock()->yPos() + continuation()->yPos(),
topLevel);
}
bool RenderInline::requiresLayer()
{
return isRelPositioned() || style()->opacity() < 1.0f;
}
int RenderInline::width() const
{
int leftSide = 0;
int rightSide = 0;
for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
if (curr == firstLineBox() || curr->xPos() < leftSide)
leftSide = curr->xPos();
if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide)
rightSide = curr->xPos() + curr->width();
}
return rightSide - leftSide;
}
int RenderInline::height() const
{
ASSERT(!firstLineBox() == !lastLineBox()); if (firstLineBox() && lastLineBox())
return lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
return 0;
}
int RenderInline::offsetLeft() const
{
int x = RenderFlow::offsetLeft();
if (firstLineBox())
x += firstLineBox()->xPos();
return x;
}
int RenderInline::offsetTop() const
{
int y = RenderFlow::offsetTop();
if (firstLineBox())
y += firstLineBox()->yPos();
return y;
}
const char* RenderInline::renderName() const
{
if (isRelPositioned())
return "RenderInline (relative positioned)";
if (isAnonymous())
return "RenderInline (generated)";
return "RenderInline";
}
bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
int x, int y, int tx, int ty, HitTestAction hitTestAction)
{
return hitTestLines(request, result, x, y, tx, ty, hitTestAction);
}
VisiblePosition RenderInline::positionForCoordinates(int x, int y)
{
RenderBlock* cb = containingBlock();
int parentBlockX = cb->xPos() + x;
int parentBlockY = cb->yPos() + y;
for (RenderObject* c = continuation(); c; c = c->continuation()) {
RenderObject* contBlock = c;
if (c->isInline())
contBlock = c->containingBlock();
if (c->isInline() || c->firstChild())
return c->positionForCoordinates(parentBlockX - contBlock->xPos(), parentBlockY - contBlock->yPos());
}
return RenderFlow::positionForCoordinates(x, y);
}
}