#include "config.h"
#include "RenderRuby.h"
#include "RenderIterator.h"
#include "RenderRubyRun.h"
#include "RenderStyle.h"
#include "StyleInheritedData.h"
#include <wtf/RefPtr.h>
namespace WebCore {
static inline bool isAnonymousRubyInlineBlock(const RenderObject* object)
{
ASSERT(!object
|| !object->parent()->isRuby()
|| object->isRubyRun()
|| (object->isInline() && (object->isBeforeContent() || object->isAfterContent()))
|| (object->isAnonymous() && object->isRenderBlock() && object->style().display() == INLINE_BLOCK));
return object
&& object->parent()->isRuby()
&& object->isRenderBlock()
&& !object->isRubyRun();
}
static inline bool isRubyBeforeBlock(const RenderObject* object)
{
return isAnonymousRubyInlineBlock(object)
&& !object->previousSibling()
&& object->firstChildSlow()
&& object->firstChildSlow()->style().styleType() == BEFORE;
}
static inline bool isRubyAfterBlock(const RenderObject* object)
{
return isAnonymousRubyInlineBlock(object)
&& !object->nextSibling()
&& object->firstChildSlow()
&& object->firstChildSlow()->style().styleType() == AFTER;
}
static inline RenderBlock* rubyBeforeBlock(const RenderElement* ruby)
{
RenderObject* child = ruby->firstChild();
return isRubyBeforeBlock(child) ? toRenderBlock(child) : 0;
}
static inline RenderBlock* rubyAfterBlock(const RenderElement* ruby)
{
RenderObject* child = ruby->lastChild();
return isRubyAfterBlock(child) ? toRenderBlock(child) : 0;
}
static RenderBlock* createAnonymousRubyInlineBlock(RenderObject& ruby)
{
RenderBlock* newBlock = new RenderBlockFlow(ruby.document(), RenderStyle::createAnonymousStyleWithDisplay(&ruby.style(), INLINE_BLOCK));
newBlock->initializeStyle();
return newBlock;
}
static RenderRubyRun* lastRubyRun(const RenderElement* ruby)
{
RenderObject* child = ruby->lastChild();
if (child && !child->isRubyRun())
child = child->previousSibling();
ASSERT(!child || child->isRubyRun() || child->isBeforeContent() || child == rubyBeforeBlock(ruby));
return child && child->isRubyRun() ? toRenderRubyRun(child) : 0;
}
static inline RenderRubyRun& findRubyRunParent(RenderObject& child)
{
return *lineageOfType<RenderRubyRun>(child).first();
}
RenderRubyAsInline::RenderRubyAsInline(Element& element, PassRef<RenderStyle> style)
: RenderInline(element, WTF::move(style))
{
}
RenderRubyAsInline::~RenderRubyAsInline()
{
}
void RenderRubyAsInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderInline::styleDidChange(diff, oldStyle);
propagateStyleToAnonymousChildren(PropagateToAllChildren);
}
void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild)
{
if (child->isBeforeContent()) {
if (child->isInline()) {
RenderInline::addChild(child, firstChild());
} else {
RenderBlock* beforeBlock = rubyBeforeBlock(this);
if (!beforeBlock) {
beforeBlock = createAnonymousRubyInlineBlock(*this);
RenderInline::addChild(beforeBlock, firstChild());
}
beforeBlock->addChild(child);
}
return;
}
if (child->isAfterContent()) {
if (child->isInline()) {
RenderInline::addChild(child);
} else {
RenderBlock* afterBlock = rubyAfterBlock(this);
if (!afterBlock) {
afterBlock = createAnonymousRubyInlineBlock(*this);
RenderInline::addChild(afterBlock);
}
afterBlock->addChild(child);
}
return;
}
if (child->isRubyRun()) {
RenderInline::addChild(child, beforeChild);
return;
}
if (beforeChild && !isAfterContent(beforeChild)) {
ASSERT(!beforeChild->isRubyRun());
RenderElement* run = beforeChild->parent();
while (run && !run->isRubyRun())
run = run->parent();
if (run) {
run->addChild(child, beforeChild);
return;
}
ASSERT_NOT_REACHED(); }
RenderRubyRun* lastRun = lastRubyRun(this);
if (!lastRun || lastRun->hasRubyText()) {
lastRun = RenderRubyRun::staticCreateRubyRun(this);
RenderInline::addChild(lastRun, beforeChild);
}
lastRun->addChild(child);
}
RenderObject* RenderRubyAsInline::removeChild(RenderObject& child)
{
if (child.parent() == this) {
ASSERT(child.isRubyRun() || child.isBeforeContent() || child.isAfterContent() || isAnonymousRubyInlineBlock(&child));
return RenderInline::removeChild(child);
}
if (isAnonymousRubyInlineBlock(child.parent())) {
ASSERT(child.isBeforeContent() || child.isAfterContent());
RenderObject* next = child.parent()->removeChild(child);
removeChild(*child.parent());
return next;
}
RenderRubyRun& run = findRubyRunParent(child);
return run.removeChild(child);
}
RenderRubyAsBlock::RenderRubyAsBlock(Element& element, PassRef<RenderStyle> style)
: RenderBlockFlow(element, WTF::move(style))
{
}
RenderRubyAsBlock::~RenderRubyAsBlock()
{
}
void RenderRubyAsBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBlockFlow::styleDidChange(diff, oldStyle);
propagateStyleToAnonymousChildren(PropagateToAllChildren);
}
void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
{
if (child->isBeforeContent()) {
if (child->isInline()) {
RenderBlockFlow::addChild(child, firstChild());
} else {
RenderBlock* beforeBlock = rubyBeforeBlock(this);
if (!beforeBlock) {
beforeBlock = createAnonymousRubyInlineBlock(*this);
RenderBlockFlow::addChild(beforeBlock, firstChild());
}
beforeBlock->addChild(child);
}
return;
}
if (child->isAfterContent()) {
if (child->isInline()) {
RenderBlockFlow::addChild(child);
} else {
RenderBlock* afterBlock = rubyAfterBlock(this);
if (!afterBlock) {
afterBlock = createAnonymousRubyInlineBlock(*this);
RenderBlockFlow::addChild(afterBlock);
}
afterBlock->addChild(child);
}
return;
}
if (child->isRubyRun()) {
RenderBlockFlow::addChild(child, beforeChild);
return;
}
if (beforeChild && !isAfterContent(beforeChild)) {
ASSERT(!beforeChild->isRubyRun());
RenderElement* run = beforeChild->parent();
while (run && !run->isRubyRun())
run = run->parent();
if (run) {
run->addChild(child, beforeChild);
return;
}
ASSERT_NOT_REACHED(); }
RenderRubyRun* lastRun = lastRubyRun(this);
if (!lastRun || lastRun->hasRubyText()) {
lastRun = RenderRubyRun::staticCreateRubyRun(this);
RenderBlockFlow::addChild(lastRun, beforeChild);
}
lastRun->addChild(child);
}
RenderObject* RenderRubyAsBlock::removeChild(RenderObject& child)
{
if (child.parent() == this) {
ASSERT(child.isRubyRun() || child.isBeforeContent() || child.isAfterContent() || isAnonymousRubyInlineBlock(&child));
return RenderBlockFlow::removeChild(child);
}
if (isAnonymousRubyInlineBlock(child.parent())) {
ASSERT(child.isBeforeContent() || child.isAfterContent());
RenderObject* next = child.parent()->removeChild(child);
removeChild(*child.parent());
return next;
}
RenderRubyRun& run = findRubyRunParent(child);
return run.removeChild(child);
}
}