#include "config.h"
#include "RenderLayer.h"
#include "AffineTransform.h"
#include "CString.h"
#include "CSSPropertyNames.h"
#include "CSSStyleSelector.h"
#include "Document.h"
#include "EventHandler.h"
#include "EventNames.h"
#include "FloatQuad.h"
#include "FocusController.h"
#include "Frame.h"
#include "FrameView.h"
#include "FrameTree.h"
#include "GraphicsContext.h"
#include "HTMLMarqueeElement.h"
#include "HTMLNames.h"
#include "HitTestRequest.h"
#include "HitTestResult.h"
#include "OverflowEvent.h"
#include "Page.h"
#include "PlatformMouseEvent.h"
#include "PlatformScrollBar.h"
#include "RenderArena.h"
#include "RenderInline.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "SelectionController.h"
#ifndef NDEBUG
#include "TextStream.h"
#include "RenderTreeAsText.h"
#endif
#if ENABLE(SVG)
#include "SVGNames.h"
#endif
#define MIN_INTERSECT_FOR_REVEAL 32
using namespace std;
namespace WebCore {
using namespace EventNames;
using namespace HTMLNames;
#ifndef NDEBUG
static bool inRenderLayerDestroy;
#endif
const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterIfNeeded = { RenderLayer::noScroll, RenderLayer::alignCenter, RenderLayer::alignToClosestEdge };
const RenderLayer::ScrollAlignment RenderLayer::gAlignToEdgeIfNeeded = { RenderLayer::noScroll, RenderLayer::alignToClosestEdge, RenderLayer::alignToClosestEdge };
const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterAlways = { RenderLayer::alignCenter, RenderLayer::alignCenter, RenderLayer::alignCenter };
const RenderLayer::ScrollAlignment RenderLayer::gAlignTopAlways = { RenderLayer::alignTop, RenderLayer::alignTop, RenderLayer::alignTop };
const RenderLayer::ScrollAlignment RenderLayer::gAlignBottomAlways = { RenderLayer::alignBottom, RenderLayer::alignBottom, RenderLayer::alignBottom };
const int MinimumWidthWhileResizing = 100;
const int MinimumHeightWhileResizing = 40;
void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
{
return renderArena->allocate(sz);
}
void ClipRects::operator delete(void* ptr, size_t sz)
{
*(size_t *)ptr = sz;
}
void ClipRects::destroy(RenderArena* renderArena)
{
delete this;
renderArena->free(*(size_t *)this, this);
}
#pragma mark -
RenderLayer::RenderLayer(RenderObject* object)
: m_object(object)
, m_parent(0)
, m_previous(0)
, m_next(0)
, m_first(0)
, m_last(0)
, m_relX(0)
, m_relY(0)
, m_x(0)
, m_y(0)
, m_width(0)
, m_height(0)
, m_scrollX(0)
, m_scrollY(0)
, m_scrollOriginX(0)
, m_scrollLeftOverflow(0)
, m_scrollWidth(0)
, m_scrollHeight(0)
, m_inResizeMode(false)
, m_posZOrderList(0)
, m_negZOrderList(0)
, m_overflowList(0)
, m_clipRects(0)
, m_scrollDimensionsDirty(true)
, m_zOrderListsDirty(true)
, m_overflowListDirty(true)
, m_isOverflowOnly(shouldBeOverflowOnly())
, m_usedTransparency(false)
, m_inOverflowRelayout(false)
, m_needsFullRepaint(false)
, m_overflowStatusDirty(true)
, m_visibleContentStatusDirty(true)
, m_hasVisibleContent(false)
, m_visibleDescendantStatusDirty(false)
, m_hasVisibleDescendant(false)
, m_styleChangePending(false)
#if ENABLE(HW_COMP)
, m_forceCompositingLayer(false)
, m_isSimpleContainerCompositingLayer(false)
, m_simpleCompositingLayerStatusDirty(true)
, m_hasCompositingDescendant(false)
, m_compositingContentOffsetDirty(true)
, m_rebuildingLayerTree(false)
#endif
, m_marquee(0)
, m_staticX(0)
, m_staticY(0)
#if ENABLE(HW_COMP)
, m_transformOriginX(0.5f)
, m_transformOriginY(0.5f)
, m_transformOriginZ(0)
, m_layer(0)
, m_contentsLayer(0)
, m_clippingLayer(0)
#if PROFILE_LAYER_REBUILD
, m_rootLayerUpdateCount(0)
#endif // PROFILE_LAYER_REBUILD
#endif
{
if (!object->firstChild() && object->style()) {
m_visibleContentStatusDirty = false;
m_hasVisibleContent = object->style()->visibility() == VISIBLE;
}
}
RenderLayer::~RenderLayer()
{
if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
if (Frame* frame = renderer()->document()->frame())
frame->eventHandler()->resizeLayerDestroyed();
}
destroyScrollbar(HorizontalScrollbar);
destroyScrollbar(VerticalScrollbar);
delete m_posZOrderList;
delete m_negZOrderList;
delete m_overflowList;
delete m_marquee;
#if ENABLE(HW_COMP)
m_object = 0;
destroyCompositingLayer();
#endif
ASSERT(!m_clipRects);
}
void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
{
if (doFullRepaint) {
m_object->repaint();
#if ENABLE(HW_COMP)
checkForRepaint = false;
if (!inCompositingMode())
doFullRepaint = false;
#else
checkForRepaint = doFullRepaint = false;
#endif
}
updateLayerPosition();
positionOverflowControls();
updateVisibilityStatus();
updateTransform();
if (m_hasVisibleContent) {
RenderView* view = m_object->view();
ASSERT(view);
ASSERT(!view->layoutState());
IntRect newRect = m_object->absoluteClippedOverflowRect();
IntRect newOutlineBox = m_object->absoluteOutlineBox();
if (checkForRepaint) {
if (view && !view->printing()) {
if (m_needsFullRepaint) {
view->repaintViewRectangle(m_repaintRect);
if (newRect != m_repaintRect)
view->repaintViewRectangle(newRect);
} else
m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox);
}
}
m_repaintRect = newRect;
m_outlineBox = newOutlineBox;
} else {
m_repaintRect = IntRect();
m_outlineBox = IntRect();
}
m_needsFullRepaint = false;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(doFullRepaint, checkForRepaint);
#if ENABLE(HW_COMP)
if (hasCompositingLayer())
updateCompositingLayerPosition();
#endif
if (m_marquee)
m_marquee->updateMarqueePosition();
}
void RenderLayer::updateTransform()
{
#if !ENABLE(HW_COMP)
bool hasTransform = renderer()->hasTransform();
bool hadTransform = m_transform;
if (hasTransform != hadTransform) {
if (hasTransform)
m_transform.set(new AffineTransform);
else
m_transform.clear();
}
if (hasTransform) {
Transform3D transform3D;
renderer()->style()->applyTransform(transform3D, renderer()->borderBox().size(), true);
m_transform.set(new AffineTransform(transform3D.affineTransform()));
}
#endif
}
void RenderLayer::setHasVisibleContent(bool b)
{
if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
return;
m_visibleContentStatusDirty = false;
m_hasVisibleContent = b;
if (m_hasVisibleContent) {
m_repaintRect = renderer()->absoluteClippedOverflowRect();
m_outlineBox = renderer()->absoluteOutlineBox();
if (!isOverflowOnly()) {
dirtyStackingContextZOrderList();
}
}
if (parent())
parent()->childVisibilityChanged(m_hasVisibleContent);
}
void RenderLayer::dirtyVisibleContentStatus()
{
m_visibleContentStatusDirty = true;
if (parent())
parent()->dirtyVisibleDescendantStatus();
}
void RenderLayer::childVisibilityChanged(bool newVisibility)
{
if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
return;
if (newVisibility) {
RenderLayer* l = this;
while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
l->m_hasVisibleDescendant = true;
l = l->parent();
}
} else
dirtyVisibleDescendantStatus();
}
void RenderLayer::dirtyVisibleDescendantStatus()
{
RenderLayer* l = this;
while (l && !l->m_visibleDescendantStatusDirty) {
l->m_visibleDescendantStatusDirty = true;
l = l->parent();
}
}
void RenderLayer::updateVisibilityStatus()
{
if (m_visibleDescendantStatusDirty) {
m_hasVisibleDescendant = false;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
child->updateVisibilityStatus();
if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
m_hasVisibleDescendant = true;
break;
}
}
m_visibleDescendantStatusDirty = false;
}
if (m_visibleContentStatusDirty) {
if (m_object->style()->visibility() == VISIBLE)
m_hasVisibleContent = true;
else {
m_hasVisibleContent = false;
RenderObject* r = m_object->firstChild();
while (r) {
if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
m_hasVisibleContent = true;
break;
}
if (r->firstChild() && !r->hasLayer())
r = r->firstChild();
else if (r->nextSibling())
r = r->nextSibling();
else {
do {
r = r->parent();
if (r==m_object)
r = 0;
} while (r && !r->nextSibling());
if (r)
r = r->nextSibling();
}
}
}
m_visibleContentStatusDirty = false;
}
}
void RenderLayer::updateLayerPosition()
{
clearClipRect();
int x = m_object->xPos();
int y = m_object->yPos() - m_object->borderTopExtra();
if (!m_object->isPositioned() && m_object->parent()) {
RenderObject* curr = m_object->parent();
while (curr && !curr->hasLayer()) {
if (!curr->isTableRow()) {
x += curr->xPos();
y += curr->yPos();
}
curr = curr->parent();
}
y += curr->borderTopExtra();
if (curr->isTableRow()) {
x -= curr->xPos();
y -= curr->yPos();
}
}
m_relX = m_relY = 0;
if (m_object->isRelPositioned()) {
m_relX = static_cast<RenderBox*>(m_object)->relativePositionOffsetX();
m_relY = static_cast<RenderBox*>(m_object)->relativePositionOffsetY();
x += m_relX; y += m_relY;
}
if (m_object->isPositioned() && enclosingPositionedAncestor()) {
RenderLayer* positionedParent = enclosingPositionedAncestor();
positionedParent->subtractScrollOffset(x, y);
if (m_object->isPositioned()) {
IntSize offset = static_cast<RenderBox*>(m_object)->offsetForPositionedInContainer(positionedParent->renderer());
x += offset.width();
y += offset.height();
}
} else if (parent())
parent()->subtractScrollOffset(x, y);
setPos(x,y);
setWidth(m_object->width());
setHeight(m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra());
if (!m_object->hasOverflowClip()) {
if (m_object->overflowWidth() > m_object->width())
setWidth(m_object->overflowWidth());
if (m_object->overflowHeight() > m_object->height())
setHeight(m_object->overflowHeight());
}
}
#if !ENABLE(HW_COMP)
Transform3D RenderLayer::currentTransform() const
{
Transform3D t;
const TransformOperations& transformOps = m_object->style()->transform();
for (unsigned i = 0; i < transformOps.size(); ++i)
transformOps[i].get()->apply(t, IntSize(renderer()->width(), renderer()->height()));
return t;
}
float RenderLayer::currentOpacity() const
{
return renderer()->opacity();
}
#endif
RenderLayer *RenderLayer::stackingContext() const
{
RenderLayer* curr = parent();
for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isRoot() &&
#if ENABLE(HW_COMP)
!curr->isStackingContext();
#else
curr->m_object->style()->hasAutoZIndex();
#endif
curr = curr->parent()) { };
return curr;
}
RenderLayer*
RenderLayer::enclosingPositionedAncestor() const
{
RenderLayer* curr = parent();
for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned() && !curr->m_object->hasTransform();
curr = curr->parent()) { };
return curr;
}
RenderLayer*
RenderLayer::enclosingDocumentLayer() const
{
RenderLayer* curr = const_cast<RenderLayer*>(this);
for ( ; curr && !curr->isDocumentLayer();
curr = curr->parent()) { }
return curr;
}
bool
RenderLayer::isTransparent() const
{
#if ENABLE(SVG)
if (m_object->node()->namespaceURI() == SVGNames::svgNamespaceURI)
return false;
#endif
return m_object->isTransparent();
}
bool
RenderLayer::isTransparentForDrawing() const
{
#if ENABLE(HW_COMP)
return isTransparent() && !hasCompositingLayer();
#else
return isTransparent();
#endif
}
RenderLayer*
RenderLayer::transparentAncestor()
{
if (hasCompositingLayer())
return 0;
RenderLayer* curr = parent();
for ( ; curr && !curr->hasCompositingLayer() && !curr->isTransparentForDrawing(); curr = curr->parent());
return curr;
}
static IntRect transparencyClipBox(const AffineTransform& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer)
{
#if !ENABLE(HW_COMP)
AffineTransform* t = l->transform();
if (t) {
int x = 0;
int y = 0;
l->convertToLayerCoords(rootLayer, x, y);
AffineTransform transform;
transform.translate(x, y);
transform = *t * transform;
transform = transform * enclosingTransform;
IntRect clipRect = transform.mapRect(l->boundingBox(l));
for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling())
clipRect.unite(transparencyClipBox(transform, curr, l));
return clipRect;
}
#endif
IntRect clipRect = l->boundingBox(rootLayer);
for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling())
clipRect.unite(transparencyClipBox(enclosingTransform, curr, rootLayer));
return clipRect;
}
void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer)
{
if (p->paintingDisabled() || (isTransparentForDrawing() && m_usedTransparency))
return;
RenderLayer* ancestor = transparentAncestor();
if (ancestor)
ancestor->beginTransparencyLayers(p, rootLayer);
if (isTransparentForDrawing()) {
m_usedTransparency = true;
p->save();
p->clip(transparencyClipBox(AffineTransform(), this, rootLayer));
p->beginTransparencyLayer(renderer()->opacity());
}
}
void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
{
return renderArena->allocate(sz);
}
void RenderLayer::operator delete(void* ptr, size_t sz)
{
ASSERT(inRenderLayerDestroy);
*(size_t *)ptr = sz;
}
void RenderLayer::destroy(RenderArena* renderArena)
{
#ifndef NDEBUG
inRenderLayerDestroy = true;
#endif
delete this;
#ifndef NDEBUG
inRenderLayerDestroy = false;
#endif
renderArena->free(*(size_t *)this, this);
}
void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
{
RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
if (prevSibling) {
child->setPreviousSibling(prevSibling);
prevSibling->setNextSibling(child);
} else
setFirstChild(child);
if (beforeChild) {
beforeChild->setPreviousSibling(child);
child->setNextSibling(beforeChild);
} else
setLastChild(child);
child->setParent(this);
if (child->isOverflowOnly())
dirtyOverflowList();
if (!child->isOverflowOnly() || child->firstChild()) {
child->dirtyStackingContextZOrderList();
}
child->updateVisibilityStatus();
if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
childVisibilityChanged(true);
#if ENABLE(HW_COMP)
if (isDocumentLayer() && hasCompositingLayer()) {
parentInRootLayer();
}
m_simpleCompositingLayerStatusDirty = true;
#endif
}
RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
#if ENABLE(HW_COMP)
unparentChildsLayer(oldChild);
#endif
if (oldChild->previousSibling())
oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
if (oldChild->nextSibling())
oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
if (m_first == oldChild)
m_first = oldChild->nextSibling();
if (m_last == oldChild)
m_last = oldChild->previousSibling();
if (oldChild->isOverflowOnly())
dirtyOverflowList();
if (!oldChild->isOverflowOnly() || oldChild->firstChild()) {
oldChild->dirtyStackingContextZOrderList();
}
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
oldChild->setParent(0);
oldChild->updateVisibilityStatus();
if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
childVisibilityChanged(false);
return oldChild;
}
void RenderLayer::removeOnlyThisLayer()
{
if (!m_parent)
return;
#if ENABLE(HW_COMP)
if (hasCompositingLayer()) {
RenderLayer* compLayer = enclosingCompositingAncestor();
if (compLayer) {
IntRect dummyRect;
IntRect ancestorRect = calculateCompositingLayerBounds(compLayer, dummyRect);
compLayer->setNeedsRepaintInRect(ancestorRect);
}
}
#endif
clearClipRects();
RenderLayer* parent = m_parent;
RenderLayer* nextSib = nextSibling();
parent->removeChild(this);
RenderLayer* current = m_first;
while (current) {
RenderLayer* next = current->nextSibling();
removeChild(current);
parent->addChild(current, nextSib);
current->updateLayerPositions();
current = next;
}
destroy(renderer()->renderArena());
}
void RenderLayer::insertOnlyThisLayer()
{
if (!m_parent && renderer()->parent()) {
RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
if (parentLayer)
parentLayer->addChild(this,
renderer()->parent()->findNextLayer(parentLayer, renderer()));
}
for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(m_parent, this);
clearClipRects();
}
void
RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
{
if (ancestorLayer == this)
return;
if (m_object->style()->position() == FixedPosition) {
int xOff, yOff;
m_object->absolutePosition(xOff, yOff, true);
x += xOff;
y += yOff;
return;
}
RenderLayer* parentLayer;
if (m_object->style()->position() == AbsolutePosition)
parentLayer = enclosingPositionedAncestor();
else
parentLayer = parent();
if (!parentLayer) return;
parentLayer->convertToLayerCoords(ancestorLayer, x, y);
x += xPos();
y += yPos();
}
void
RenderLayer::scrollOffset(int& x, int& y)
{
x += scrollXOffset() + m_scrollLeftOverflow;
y += scrollYOffset();
}
void
RenderLayer::subtractScrollOffset(int& x, int& y)
{
x -= scrollXOffset() + m_scrollLeftOverflow;
y -= scrollYOffset();
}
void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
{
if (renderer()->style()->overflowX() != OMARQUEE) {
if (x < 0) x = 0;
if (y < 0) y = 0;
int maxX = scrollWidth() - m_object->clientWidth();
int maxY = scrollHeight() - m_object->clientHeight();
if (x > maxX) x = maxX;
if (y > maxY) y = maxY;
static int purpleCaretWidth = 3;
if (adjustForPurpleCaretWhenScrolling()) {
if (x > maxX - purpleCaretWidth) {
x += purpleCaretWidth;
if (x <= purpleCaretWidth)
x = 0;
}
else if (x < m_scrollX - purpleCaretWidth) {
x -= purpleCaretWidth;
}
}
}
m_scrollX = x - m_scrollOriginX;
m_scrollY = y;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(false, false);
RenderView* view = renderer()->view();
ASSERT(view);
if (view) {
#if ENABLE(DASHBOARD_SUPPORT)
view->frameView()->updateDashboardRegions();
#endif
#if ENABLE(TOUCH_EVENTS)
if (m_object->document()->touchEventListeners().size() > 0)
m_object->document()->setTouchEventListenersDirty(true);
#endif
view->updateWidgetPositions();
}
if (repaint)
m_object->repaint();
if (updateScrollbars) {
if (m_hBar)
m_hBar->setValue(scrollXOffset());
if (m_vBar)
m_vBar->setValue(m_scrollY);
}
if (view)
if (FrameView* frameView = view->frameView())
frameView->scheduleEvent(new Event(scrollEvent, true, false), EventTargetNodeCast(renderer()->element()), true);
}
void RenderLayer::scrollRectToVisible(const IntRect &rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
RenderLayer* parentLayer = 0;
IntRect newRect = rect;
int xOffset = 0, yOffset = 0;
FrameView* frameView = m_object->document()->view();
if (frameView)
frameView->pauseScheduledEvents();
bool restrictedByLineClamp = false;
if (m_object->parent()) {
parentLayer = m_object->parent()->enclosingLayer();
restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0;
}
if (m_object->hasOverflowClip() && !restrictedByLineClamp) {
int x, y;
m_object->absolutePosition(x, y);
x += m_object->borderLeft();
y += m_object->borderTop();
IntRect layerBounds = IntRect(x + scrollXOffset(), y + scrollYOffset(), m_object->clientWidth(), m_object->clientHeight());
IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
xOffset = r.x() - x;
yOffset = r.y() - y;
xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset));
yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset));
if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) {
int diffX = scrollXOffset();
int diffY = scrollYOffset();
scrollToOffset(xOffset, yOffset);
diffX = scrollXOffset() - diffX;
diffY = scrollYOffset() - diffY;
newRect.setX(rect.x() - diffX);
newRect.setY(rect.y() - diffY);
}
} else if (!parentLayer) {
if (frameView) {
if (m_object->document() && m_object->document()->ownerElement() && m_object->document()->ownerElement()->renderer()) {
IntRect viewRect = enclosingIntRect(frameView->visibleContentRect());
IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
xOffset = r.x();
yOffset = r.y();
xOffset = max(0, min(frameView->contentsWidth(), xOffset));
yOffset = max(0, min(frameView->contentsHeight(), yOffset));
frameView->setContentsPos(xOffset, yOffset);
parentLayer = m_object->document()->ownerElement()->renderer()->enclosingLayer();
newRect.setX(rect.x() - frameView->contentsX() + frameView->x());
newRect.setY(rect.y() - frameView->contentsY() + frameView->y());
} else {
IntRect viewRect = enclosingIntRect(frameView->visibleContentRectConsideringExternalScrollers());
IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
frameView->scrollRectIntoViewRecursively(r);
}
}
}
if (parentLayer)
parentLayer->scrollRectToVisible(newRect, alignX, alignY);
if (frameView)
frameView->resumeScheduledEvents();
}
IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
ScrollBehavior scrollX;
IntRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
int intersectWidth = intersection(visibleRect, exposeRectX).width();
if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
scrollX = getVisibleBehavior(alignX);
else if (intersectWidth == visibleRect.width()) {
scrollX = getVisibleBehavior(alignX);
if (scrollX == alignCenter)
scrollX = noScroll;
} else if (intersectWidth > 0)
scrollX = getPartialBehavior(alignX);
else
scrollX = getHiddenBehavior(alignX);
if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width())
scrollX = alignRight;
int x;
if (scrollX == noScroll)
x = visibleRect.x();
else if (scrollX == alignRight)
x = exposeRect.right() - visibleRect.width();
else if (scrollX == alignCenter)
x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
else
x = exposeRect.x();
ScrollBehavior scrollY;
IntRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
int intersectHeight = intersection(visibleRect, exposeRectY).height();
if (intersectHeight == exposeRect.height())
scrollY = getVisibleBehavior(alignY);
else if (intersectHeight == visibleRect.height()) {
scrollY = getVisibleBehavior(alignY);
if (scrollY == alignCenter)
scrollY = noScroll;
} else if (intersectHeight > 0)
scrollY = getPartialBehavior(alignY);
else
scrollY = getHiddenBehavior(alignY);
if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height())
scrollY = alignBottom;
int y;
if (scrollY == noScroll)
y = visibleRect.y();
else if (scrollY == alignBottom)
y = exposeRect.bottom() - visibleRect.height();
else if (scrollY == alignCenter)
y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
else
y = exposeRect.y();
return IntRect(IntPoint(x, y), visibleRect.size());
}
void RenderLayer::autoscroll()
{
Frame* frame = renderer()->document()->frame();
if (!frame)
return;
FrameView* frameView = frame->view();
if (!frameView)
return;
frame->eventHandler()->updateSelectionForMouseDrag();
IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), gAlignToEdgeIfNeeded, gAlignToEdgeIfNeeded);
}
void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset)
{
if (!inResizeMode() || !m_object->hasOverflowClip())
return;
Element* element = static_cast<Element*>(m_object->node()->shadowAncestorNode());
RenderBox* renderer = static_cast<RenderBox*>(element->renderer());
EResize resize = renderer->style()->resize();
if (resize == RESIZE_NONE)
return;
Document* document = element->document();
if (!document->frame()->eventHandler()->mousePressed())
return;
IntSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos()));
IntSize currentSize = IntSize(renderer->width(), renderer->height());
IntSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
element->setMinimumSizeForResizing(minimumSize);
IntSize difference = (currentSize + newOffset - oldOffset).expandedTo(minimumSize) - currentSize;
CSSStyleDeclaration* style = element->style();
bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
ExceptionCode ec;
if (difference.width()) {
if (element && element->isControl()) {
style->setProperty(CSS_PROP_MARGIN_LEFT, String::number(renderer->marginLeft()) + "px", false, ec);
style->setProperty(CSS_PROP_MARGIN_RIGHT, String::number(renderer->marginRight()) + "px", false, ec);
}
int baseWidth = renderer->width() - (isBoxSizingBorder ? 0
: renderer->borderLeft() + renderer->paddingLeft() + renderer->borderRight() + renderer->paddingRight());
style->setProperty(CSS_PROP_WIDTH, String::number(baseWidth + difference.width()) + "px", false, ec);
}
if (difference.height()) {
if (element && element->isControl()) {
style->setProperty(CSS_PROP_MARGIN_TOP, String::number(renderer->marginTop()) + "px", false, ec);
style->setProperty(CSS_PROP_MARGIN_BOTTOM, String::number(renderer->marginBottom()) + "px", false, ec);
}
int baseHeight = renderer->height() - (isBoxSizingBorder ? 0
: renderer->borderTop() + renderer->paddingTop() + renderer->borderBottom() + renderer->paddingBottom());
style->setProperty(CSS_PROP_HEIGHT, String::number(baseHeight + difference.height()) + "px", false, ec);
}
document->updateLayout();
}
PlatformScrollbar* RenderLayer::horizontalScrollbarWidget() const
{
if (m_hBar && m_hBar->isWidget())
return static_cast<PlatformScrollbar*>(m_hBar.get());
return 0;
}
PlatformScrollbar* RenderLayer::verticalScrollbarWidget() const
{
if (m_vBar && m_vBar->isWidget())
return static_cast<PlatformScrollbar*>(m_vBar.get());
return 0;
}
void RenderLayer::valueChanged(Scrollbar*)
{
bool needUpdate = false;
int newX = scrollXOffset();
int newY = m_scrollY;
if (m_hBar) {
newX = m_hBar->value();
if (newX != scrollXOffset())
needUpdate = true;
}
if (m_vBar) {
newY = m_vBar->value();
if (newY != m_scrollY)
needUpdate = true;
}
if (needUpdate)
scrollToOffset(newX, newY, false);
}
IntRect RenderLayer::windowClipRect() const
{
RenderView* view = renderer()->view();
ASSERT(view);
FrameView* frameView = view->frameView();
if (!frameView)
return IntRect();
return frameView->windowClipRectForLayer(this, false);
}
bool RenderLayer::isActive() const
{
Page* page = renderer()->document()->frame()->page();
return page && page->focusController()->isActive();
}
PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
{
if (Scrollbar::hasPlatformScrollbars()) {
RefPtr<PlatformScrollbar> widget = new PlatformScrollbar(this, orientation, RegularScrollbar);
m_object->document()->view()->addChild(widget.get());
return widget.release();
}
return 0;
}
void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
{
RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
if (scrollbar) {
if (scrollbar->isWidget())
static_cast<PlatformScrollbar*>(scrollbar.get())->removeFromParent();
scrollbar->setClient(0);
scrollbar = 0;
}
}
void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
{
if (hasScrollbar == (m_hBar != 0))
return;
if (hasScrollbar)
m_hBar = createScrollbar(HorizontalScrollbar);
else
destroyScrollbar(HorizontalScrollbar);
#if ENABLE(DASHBOARD_SUPPORT)
if (m_object->document()->hasDashboardRegions())
m_object->document()->setDashboardRegionsDirty(true);
#endif
}
void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
{
if (hasScrollbar == (m_vBar != 0))
return;
if (hasScrollbar)
m_vBar = createScrollbar(VerticalScrollbar);
else
destroyScrollbar(VerticalScrollbar);
#if ENABLE(DASHBOARD_SUPPORT)
if (m_object->document()->hasDashboardRegions())
m_object->document()->setDashboardRegionsDirty(true);
#endif
}
int RenderLayer::verticalScrollbarWidth() const
{
if (!m_vBar)
return 0;
return m_vBar->width();
}
int RenderLayer::horizontalScrollbarHeight() const
{
if (!m_hBar)
return 0;
return m_hBar->height();
}
IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& p) const
{
int x = width();
int y = height();
convertToLayerCoords(root(), x, y);
return p - IntPoint(x, y);
}
static IntRect scrollCornerRect(RenderObject* renderer, const IntRect& absBounds)
{
int resizerWidth = PlatformScrollbar::verticalScrollbarWidth();
int resizerHeight = PlatformScrollbar::horizontalScrollbarHeight();
return IntRect(absBounds.right() - resizerWidth - renderer->style()->borderRightWidth(),
absBounds.bottom() - resizerHeight - renderer->style()->borderBottomWidth(), resizerWidth, resizerHeight);
}
void RenderLayer::positionOverflowControls()
{
if (!m_hBar && !m_vBar && (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE))
return;
int x = 0;
int y = 0;
convertToLayerCoords(root(), x, y);
IntRect absBounds(x, y, m_object->width(), m_object->height());
IntRect resizeControlRect;
if (m_object->style()->resize() != RESIZE_NONE)
resizeControlRect = scrollCornerRect(m_object, absBounds);
int resizeControlSize = max(resizeControlRect.height(), 0);
if (m_vBar)
m_vBar->setRect(IntRect(absBounds.right() - m_object->borderRight() - m_vBar->width(),
absBounds.y() + m_object->borderTop(),
m_vBar->width(),
absBounds.height() - (m_object->borderTop() + m_object->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)));
resizeControlSize = max(resizeControlRect.width(), 0);
if (m_hBar)
m_hBar->setRect(IntRect(absBounds.x() + m_object->borderLeft(),
absBounds.bottom() - m_object->borderBottom() - m_hBar->height(),
absBounds.width() - (m_object->borderLeft() + m_object->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
m_hBar->height()));
}
int RenderLayer::scrollWidth()
{
if (m_scrollDimensionsDirty)
computeScrollDimensions();
return m_scrollWidth;
}
int RenderLayer::scrollHeight()
{
if (m_scrollDimensionsDirty)
computeScrollDimensions();
return m_scrollHeight;
}
void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
{
m_scrollDimensionsDirty = false;
bool ltr = m_object->style()->direction() == LTR;
int clientWidth = m_object->clientWidth();
int clientHeight = m_object->clientHeight();
m_scrollLeftOverflow = ltr ? 0 : min(0, m_object->leftmostPosition(true, false) - m_object->borderLeft());
int rightPos = ltr ?
m_object->rightmostPosition(true, false) - m_object->borderLeft() :
clientWidth - m_scrollLeftOverflow;
int bottomPos = m_object->lowestPosition(true, false) - m_object->borderTop();
m_scrollWidth = max(rightPos, clientWidth);
m_scrollHeight = max(bottomPos, clientHeight);
m_scrollOriginX = ltr ? 0 : m_scrollWidth - clientWidth;
if (needHBar)
*needHBar = rightPos > clientWidth;
if (needVBar)
*needVBar = bottomPos > clientHeight;
}
void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
{
if (m_overflowStatusDirty) {
m_horizontalOverflow = horizontalOverflow;
m_verticalOverflow = verticalOverflow;
m_overflowStatusDirty = false;
return;
}
bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
if (horizontalOverflowChanged || verticalOverflowChanged) {
m_horizontalOverflow = horizontalOverflow;
m_verticalOverflow = verticalOverflow;
if (FrameView* frameView = m_object->document()->view())
frameView->scheduleEvent(new OverflowEvent(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
EventTargetNodeCast(m_object->element()), true);
}
}
void
RenderLayer::updateScrollInfoAfterLayout()
{
m_scrollDimensionsDirty = true;
bool horizontalOverflow, verticalOverflow;
computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
if (m_object->style()->overflowX() != OMARQUEE) {
int newX = max(0, min(scrollXOffset(), scrollWidth() - m_object->clientWidth()));
int newY = max(0, min(m_scrollY, scrollHeight() - m_object->clientHeight()));
setAdjustForPurpleCaretWhenScrolling(true);
if (newX != scrollXOffset() || newY != m_scrollY) {
RenderView* view = m_object->view();
ASSERT(view);
if (view)
view->disableLayoutState();
scrollToOffset(newX, newY);
if (view)
view->enableLayoutState();
}
setAdjustForPurpleCaretWhenScrolling(false);
}
bool haveHorizontalBar = m_hBar;
bool haveVerticalBar = m_vBar;
if (m_object->style()->overflowX() == OSCROLL)
m_hBar->setEnabled(horizontalOverflow);
if (m_object->style()->overflowY() == OSCROLL)
m_vBar->setEnabled(verticalOverflow);
if (m_object->style()->overflowX() == OHIDDEN && haveHorizontalBar)
setHasHorizontalScrollbar(false);
if (m_object->style()->overflowY() == OHIDDEN && haveVerticalBar)
setHasVerticalScrollbar(false);
bool scrollbarsChanged = (m_object->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
(m_object->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
if (scrollbarsChanged) {
if (m_object->hasAutoHorizontalScrollbar())
setHasHorizontalScrollbar(horizontalOverflow);
if (m_object->hasAutoVerticalScrollbar())
setHasVerticalScrollbar(verticalOverflow);
#if ENABLE(DASHBOARD_SUPPORT)
if (m_object->document()->hasDashboardRegions())
m_object->document()->setDashboardRegionsDirty(true);
#endif
m_object->repaint();
if (m_object->style()->overflowX() == OAUTO || m_object->style()->overflowY() == OAUTO) {
if (!m_inOverflowRelayout) {
m_inOverflowRelayout = true;
m_object->setNeedsLayout(true);
if (m_object->isRenderBlock())
static_cast<RenderBlock*>(m_object)->layoutBlock(true);
else
m_object->layout();
m_inOverflowRelayout = false;
}
}
}
if (m_hBar && m_object->hasAutoHorizontalScrollbar())
m_hBar->setEnabled(true);
if (m_vBar && m_object->hasAutoVerticalScrollbar())
m_vBar->setEnabled(true);
if (m_hBar) {
int clientWidth = m_object->clientWidth();
int pageStep = (clientWidth-PAGE_KEEP);
if (pageStep < 0) pageStep = clientWidth;
m_hBar->setSteps(LINE_STEP, pageStep);
m_hBar->setProportion(clientWidth, m_scrollWidth);
m_hBar->setValue(scrollXOffset());
}
if (m_vBar) {
int clientHeight = m_object->clientHeight();
int pageStep = (clientHeight-PAGE_KEEP);
if (pageStep < 0) pageStep = clientHeight;
m_vBar->setSteps(LINE_STEP, pageStep);
m_vBar->setProportion(clientHeight, m_scrollHeight);
}
if (m_object->element() && m_object->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
updateOverflowStatus(horizontalOverflow, verticalOverflow);
}
void RenderLayer::paintOverflowControls(GraphicsContext* p, int tx, int ty, const IntRect& damageRect)
{
if (!m_object->hasOverflowClip())
return;
positionOverflowControls();
if (m_hBar)
m_hBar->paint(p, damageRect);
if (m_vBar)
m_vBar->paint(p, damageRect);
IntRect paddingBox(m_object->xPos() + m_object->borderLeft() + tx,
m_object->yPos() + m_object->borderTop() + ty,
m_object->width() - m_object->borderLeft() - m_object->borderRight(),
m_object->height() - m_object->borderTop() - m_object->borderBottom());
IntRect hCorner;
if (m_hBar && paddingBox.width() - m_hBar->width() > 0) {
hCorner = IntRect(paddingBox.x() + m_hBar->width(),
paddingBox.y() + paddingBox.height() - m_hBar->height(),
paddingBox.width() - m_hBar->width(),
m_hBar->height());
if (hCorner.intersects(damageRect))
p->fillRect(hCorner, Color::white);
}
if (m_vBar && paddingBox.height() - m_vBar->height() > 0) {
IntRect vCorner(paddingBox.x() + paddingBox.width() - m_vBar->width(),
paddingBox.y() + m_vBar->height(),
m_vBar->width(),
paddingBox.height() - m_vBar->height());
if (vCorner != hCorner && vCorner.intersects(damageRect))
p->fillRect(vCorner, Color::white);
}
if (m_object->style()->resize() != RESIZE_NONE) {
IntRect absBounds(m_object->xPos() + tx, m_object->yPos() + ty, m_object->width(), m_object->height());
IntRect scrollCorner = scrollCornerRect(m_object, absBounds);
if (!scrollCorner.intersects(damageRect))
return;
static Image* resizeCornerImage;
if (!resizeCornerImage)
resizeCornerImage = Image::loadPlatformResource("textAreaResizeCorner");
IntPoint imagePoint(scrollCorner.right() - resizeCornerImage->width(), scrollCorner.bottom() - resizeCornerImage->height());
p->drawImage(resizeCornerImage, imagePoint);
if (m_hBar || m_vBar) {
p->save();
scrollCorner.setSize(IntSize(scrollCorner.width() + 1, scrollCorner.height() + 1));
p->setStrokeColor(Color(makeRGB(217, 217, 217)));
p->setStrokeThickness(1.0f);
p->setFillColor(Color::transparent);
p->drawRect(scrollCorner);
p->restore();
}
}
}
bool RenderLayer::isPointInResizeControl(const IntPoint& point)
{
if (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE)
return false;
int x = 0;
int y = 0;
convertToLayerCoords(root(), x, y);
IntRect absBounds(x, y, m_object->width(), m_object->height());
return scrollCornerRect(m_object, absBounds).contains(point);
}
bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
{
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
return false;
int x = 0;
int y = 0;
convertToLayerCoords(root(), x, y);
IntRect absBounds(x, y, renderer()->width(), renderer()->height());
IntRect resizeControlRect;
if (renderer()->style()->resize() != RESIZE_NONE) {
resizeControlRect = scrollCornerRect(renderer(), absBounds);
if (resizeControlRect.contains(result.point()))
return true;
}
int resizeControlSize = max(resizeControlRect.height(), 0);
if (m_vBar) {
IntRect vBarRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(), absBounds.y() + renderer()->borderTop(), m_vBar->width(), absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
if (vBarRect.contains(result.point())) {
result.setScrollbar(verticalScrollbarWidget());
return true;
}
}
resizeControlSize = max(resizeControlRect.width(), 0);
if (m_hBar) {
IntRect hBarRect(absBounds.x() + renderer()->borderLeft(), absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(), absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height());
if (hBarRect.contains(result.point())) {
result.setScrollbar(horizontalScrollbarWidget());
return true;
}
}
return false;
}
bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
{
bool didHorizontalScroll = false;
bool didVerticalScroll = false;
if (m_hBar) {
if (granularity == ScrollByDocument) {
didHorizontalScroll = m_hBar->scroll(ScrollLeft, ScrollByDocument, multiplier);
} else
didHorizontalScroll = m_hBar->scroll(direction, granularity, multiplier);
}
if (m_vBar)
didVerticalScroll = m_vBar->scroll(direction, granularity, multiplier);
return (didHorizontalScroll || didVerticalScroll);
}
void
RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintRestriction paintRestriction, RenderObject *paintingRoot)
{
#if ENABLE(HW_COMP)
if (!hasCompositingLayer()
|| isDocumentLayer()
)
#endif
{
paintLayer(this, p, damageRect, false, paintRestriction, paintingRoot);
}
}
static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
{
if (paintDirtyRect == clipRect)
return;
p->save();
p->clip(clipRect);
}
static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
{
if (paintDirtyRect == clipRect)
return;
p->restore();
}
void
RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction,
RenderObject *paintingRoot)
{
#if ENABLE(HW_COMP)
if (hasCompositingLayer()
&& !isDocumentLayer()
)
return;
#endif
ASSERT(renderer());
if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot())
return;
if (!m_object->opacity())
return;
if (isTransparentForDrawing())
haveTransparency = true;
#if !ENABLE(HW_COMP)
if (m_transform && rootLayer != this) {
if (!m_transform->isInvertible())
return;
if (haveTransparency)
parent()->beginTransparencyLayers(p, rootLayer);
parent()->calculateClipRects(rootLayer);
IntRect clipRect = parent()->clipRects()->overflowClipRect();
clipRect.intersect(paintDirtyRect);
setClip(p, paintDirtyRect, clipRect);
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
AffineTransform transform;
transform.translate(x, y);
transform = *m_transform * transform;
p->save();
p->concatCTM(transform);
paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot);
p->restore();
restoreClip(p, paintDirtyRect, clipRect);
return;
}
#endif // !ENABLE(HW_COMP)
IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
calculateRects(rootLayer, rootLayer , paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
int x = layerBounds.x();
int y = layerBounds.y();
int tx = x - renderer()->xPos();
int ty = y - renderer()->yPos() + renderer()->borderTopExtra();
#if ENABLE(HW_COMP)
if (inCompositingMode()) {
if (isStackingContext() && (m_zOrderListsDirty || m_overflowListDirty))
{
#ifndef NDEBUG
fprintf(stderr, "RenderLayer %p paintLayer has to eagerly update z-order lists\n", this);
#endif
updateLayers();
}
}
else {
updateZOrderLists();
updateOverflowList();
}
#else
updateZOrderLists();
updateOverflowList();
#endif
bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
RenderObject *paintingRootForRenderer = 0;
if (paintingRoot && !m_object->isDescendantOf(paintingRoot))
paintingRootForRenderer = paintingRoot;
bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent;
if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
if (haveTransparency)
beginTransparencyLayers(p, rootLayer);
setClip(p, paintDirtyRect, damageRect);
RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
renderer()->paint(paintInfo, tx, ty);
paintOverflowControls(p, tx, ty, damageRect);
restoreClip(p, paintDirtyRect, damageRect);
}
if (m_negZOrderList)
for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it)
it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot);
if (shouldPaint && !clipRectToApply.isEmpty()) {
if (haveTransparency)
beginTransparencyLayers(p, rootLayer);
setClip(p, paintDirtyRect, clipRectToApply);
RenderObject::PaintInfo paintInfo(p, clipRectToApply,
selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
forceBlackText, paintingRootForRenderer, 0);
renderer()->paint(paintInfo, tx, ty);
if (!selectionOnly) {
paintInfo.phase = PaintPhaseFloat;
renderer()->paint(paintInfo, tx, ty);
paintInfo.phase = PaintPhaseForeground;
renderer()->paint(paintInfo, tx, ty);
paintInfo.phase = PaintPhaseChildOutlines;
renderer()->paint(paintInfo, tx, ty);
}
restoreClip(p, paintDirtyRect, clipRectToApply);
}
if (!outlineRect.isEmpty()) {
RenderObject::PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
setClip(p, paintDirtyRect, outlineRect);
renderer()->paint(paintInfo, tx, ty);
restoreClip(p, paintDirtyRect, outlineRect);
}
if (m_overflowList)
for (Vector<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it)
it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot);
if (m_posZOrderList)
for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it)
it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot);
if (haveTransparency && m_usedTransparency) {
p->endTransparencyLayer();
p->restore();
m_usedTransparency = false;
}
}
static inline IntRect frameVisibleRect(RenderObject* renderer)
{
FrameView* frameView = renderer->document()->view();
if (!frameView)
return IntRect();
return enclosingIntRect(frameView->visibleContentRect());
}
bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
{
renderer()->document()->updateLayout();
IntRect boundsRect(m_x, m_y, width(), height());
boundsRect.intersect(frameVisibleRect(renderer()));
RenderLayer* insideLayer = hitTestLayer(this, request, result, boundsRect, result.point());
Node* node = result.innerNode();
while (node) {
if (node->isLink() && !result.URLElement() && !node->hasTagName(imgTag))
result.setURLElement(static_cast<Element*>(node));
node = node->eventParentNode();
}
updateHoverActiveState(request, result);
return insideLayer;
}
Node* RenderLayer::enclosingElement() const
{
for (RenderObject* r = renderer(); r; r = r->parent()) {
if (Node* e = r->element())
return e;
}
ASSERT_NOT_REACHED();
return 0;
}
RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, const IntRect& hitTestRect, const IntPoint& hitTestPoint)
{
#if !ENABLE(HW_COMP)
if (m_transform && rootLayer != this) {
if (!m_transform->isInvertible())
return 0;
parent()->calculateClipRects(rootLayer);
IntRect clipRect = parent()->clipRects()->overflowClipRect();
if (!clipRect.contains(hitTestPoint))
return 0;
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
AffineTransform transform;
transform.translate(x, y);
transform = *m_transform * transform;
return hitTestLayer(this, request, result, transform.inverse().mapRect(hitTestRect), transform.inverse().mapPoint(hitTestPoint));
}
#endif
IntRect layerBounds;
IntRect bgRect;
IntRect fgRect;
IntRect outlineRect;
calculateRects(rootLayer, rootLayer , hitTestRect, layerBounds, bgRect, fgRect, outlineRect);
#if ENABLE(HW_COMP)
if (inCompositingMode()) {
ASSERT(!isStackingContext() || !m_zOrderListsDirty);
ASSERT(!isStackingContext() || !m_overflowListDirty);
}
else {
updateZOrderLists();
updateOverflowList();
}
#else
updateZOrderLists();
updateOverflowList();
#endif
RenderLayer* insideLayer = 0;
#if ENABLE(HW_COMP)
if (isDocumentLayer() && hasCompositingLayer()) {
return hitTestRootLayer(rootLayer, request, result, hitTestRect, result.point());
}
#endif
if (m_posZOrderList) {
for (int i = m_posZOrderList->size() - 1; i >= 0; --i) {
RenderLayer* curLayer = m_posZOrderList->at(i);
#if ENABLE(HW_COMP)
if (!curLayer->hasCompositingLayer())
#endif
{
insideLayer = curLayer->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
if (insideLayer)
return insideLayer;
}
}
}
if (m_overflowList) {
for (int i = m_overflowList->size() - 1; i >= 0; --i) {
RenderLayer* curLayer = m_overflowList->at(i);
#if ENABLE(HW_COMP)
if (!curLayer->hasCompositingLayer())
#endif
{
insideLayer = curLayer->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
if (insideLayer)
return insideLayer;
}
}
}
if (fgRect.contains(hitTestPoint) &&
renderer()->hitTest(request, result, hitTestPoint,
layerBounds.x() - renderer()->xPos(),
layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
HitTestDescendants)) {
if (!result.innerNode() || !result.innerNonSharedNode()) {
Node* e = enclosingElement();
if (!result.innerNode())
result.setInnerNode(e);
if (!result.innerNonSharedNode())
result.setInnerNonSharedNode(e);
}
return this;
}
if (m_negZOrderList) {
for (int i = m_negZOrderList->size() - 1; i >= 0; --i) {
RenderLayer* curLayer = m_negZOrderList->at(i);
#if ENABLE(HW_COMP)
if (!curLayer->hasCompositingLayer())
#endif
{
insideLayer = curLayer->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
if (insideLayer)
return insideLayer;
}
}
}
if (bgRect.contains(hitTestPoint) &&
renderer()->hitTest(request, result, hitTestPoint,
layerBounds.x() - renderer()->xPos(),
layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
HitTestSelf)) {
if (!result.innerNode() || !result.innerNonSharedNode()) {
Node* e = enclosingElement();
if (!result.innerNode())
result.setInnerNode(e);
if (!result.innerNonSharedNode())
result.setInnerNonSharedNode(e);
}
return this;
}
if ((request.active || request.mouseUp) && renderer()->isRenderView()) {
renderer()->updateHitTestResult(result, hitTestPoint);
return this;
}
return 0;
}
void RenderLayer::updateClipRectsRelativeToLayer(const RenderLayer* inAncestorLayer, ClipRects& ioClipRects, bool& outHasClip) const
{
outHasClip = false;
if (m_object->style()->position() == FixedPosition) {
ioClipRects.posClipRect() = ioClipRects.fixedClipRect();
ioClipRects.overflowClipRect() = ioClipRects.fixedClipRect();
ioClipRects.setFixed(true);
}
else if (m_object->style()->position() == RelativePosition)
ioClipRects.posClipRect() = ioClipRects.overflowClipRect();
else if (m_object->style()->position() == AbsolutePosition)
ioClipRects.overflowClipRect() = ioClipRects.posClipRect();
if (m_object->hasOverflowClip() || m_object->hasClip()) {
int x = 0;
int y = 0;
convertToLayerCoords(inAncestorLayer, x, y);
RenderView* view = renderer()->view();
ASSERT(view);
if (view && ioClipRects.fixed() && inAncestorLayer->renderer() == view) {
x -= view->frameView()->contentsX();
y -= view->frameView()->contentsY();
}
if (m_object->hasOverflowClip()) {
IntRect newOverflowClip = m_object->getOverflowClipRect(x, y);
ioClipRects.overflowClipRect().intersect(newOverflowClip);
if (m_object->isPositioned() || m_object->isRelPositioned())
ioClipRects.posClipRect().intersect(newOverflowClip);
}
if (m_object->hasClip()) {
IntRect newPosClip = m_object->getClipRect(x, y);
ioClipRects.posClipRect().intersect(newPosClip);
ioClipRects.overflowClipRect().intersect(newPosClip);
ioClipRects.fixedClipRect().intersect(newPosClip);
}
outHasClip = true;
}
}
void RenderLayer::computeClipRectsFromAncestor(const RenderLayer* inAncestorLayer, ClipRects& outClipRects, bool& outIsClipped,
const RenderLayer** outNearestClippingAncestor ) const
{
ClipRects curClipRects(IntRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX));
bool isClipped = false;
if (outNearestClippingAncestor)
*outNearestClippingAncestor = 0;
const RenderLayer* curLayer = parent();
while (curLayer)
{
bool hasClip;
curLayer->updateClipRectsRelativeToLayer(inAncestorLayer, curClipRects, hasClip);
isClipped |= hasClip;
if (hasClip && outNearestClippingAncestor && !*outNearestClippingAncestor)
*outNearestClippingAncestor = curLayer;
if (curLayer == inAncestorLayer)
break;
curLayer = curLayer->parent();
}
ASSERT(curLayer == inAncestorLayer);
outIsClipped = isClipped;
outClipRects = curClipRects;
}
void RenderLayer::calculateClipRects(const RenderLayer* rootLayer)
{
if (m_clipRects)
return;
if (rootLayer == this || !parent()) {
m_clipRects = new (m_object->renderArena()) ClipRects(IntRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX));
m_clipRects->ref();
return;
}
parent()->calculateClipRects(rootLayer);
ClipRects curClipRects(*parent()->clipRects());
bool hasClip;
updateClipRectsRelativeToLayer(rootLayer, curClipRects, hasClip);
if (curClipRects == *(parent()->clipRects()))
m_clipRects = parent()->clipRects();
else
m_clipRects = new (m_object->renderArena()) ClipRects(curClipRects);
m_clipRects->ref();
}
void RenderLayer::calculateRects(const RenderLayer* rootLayer, const RenderLayer* rootLayerForClipping,
const IntRect& paintDirtyRect, IntRect& layerBounds,
IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect) const
{
if (rootLayer != this && rootLayerForClipping != this && parent()) {
parent()->calculateClipRects(rootLayerForClipping);
backgroundRect = m_object->style()->position() == FixedPosition ? parent()->clipRects()->fixedClipRect() :
(m_object->isPositioned() ? parent()->clipRects()->posClipRect() :
parent()->clipRects()->overflowClipRect());
RenderView* view = renderer()->view();
ASSERT(view);
if (view && parent()->clipRects()->fixed() && rootLayer->renderer() == view)
backgroundRect.move(view->frameView()->contentsX(), view->frameView()->contentsY());
backgroundRect.intersect(paintDirtyRect);
} else
backgroundRect = paintDirtyRect;
foregroundRect = backgroundRect;
outlineRect = backgroundRect;
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
layerBounds = IntRect(x,y,width(),height());
if (m_object->hasOverflowClip() || m_object->hasClip()) {
if (m_object->hasOverflowClip())
foregroundRect.intersect(m_object->getOverflowClipRect(x,y));
if (m_object->hasClip()) {
IntRect newPosClip = m_object->getClipRect(x,y);
backgroundRect.intersect(newPosClip);
foregroundRect.intersect(newPosClip);
outlineRect.intersect(newPosClip);
}
if (ShadowData* boxShadow = renderer()->style()->boxShadow()) {
IntRect shadowRect = layerBounds;
shadowRect.move(boxShadow->x, boxShadow->y);
shadowRect.inflate(boxShadow->blur);
shadowRect.unite(layerBounds);
backgroundRect.intersect(shadowRect);
} else
backgroundRect.intersect(layerBounds);
}
}
IntRect RenderLayer::childrenClipRect() const
{
RenderLayer* rootLayer = renderer()->document()->renderer()->layer();
IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
calculateRects(rootLayer, rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
return foregroundRect;
}
IntRect RenderLayer::selfClipRect() const
{
RenderLayer* rootLayer = renderer()->document()->renderer()->layer();
IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
calculateRects(rootLayer, rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
return backgroundRect;
}
bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const
{
if (renderer()->isRenderView() || renderer()->isRoot())
return true;
RenderView* view = renderer()->view();
ASSERT(view);
if (view && !renderer()->isInlineFlow()) {
IntRect b = layerBounds;
b.inflate(view->maximalOutlineSize());
if (b.intersects(damageRect))
return true;
}
return boundingBox(rootLayer).intersects(damageRect);
}
IntRect RenderLayer::localBoundingBox() const
{
IntRect result;
if (renderer()->isInlineFlow()) {
RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
InlineFlowBox* firstBox = inlineFlow->firstLineBox();
if (!firstBox)
return result;
int top = firstBox->root()->topOverflow();
int bottom = inlineFlow->lastLineBox()->root()->bottomOverflow();
int left = firstBox->xPos();
for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox())
left = min(left, curr->xPos());
result = IntRect(m_x + left, m_y + (top - renderer()->yPos()), width(), bottom - top);
} else if (renderer()->isTableRow()) {
for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
if (child->isTableCell()) {
IntRect bbox = child->borderBox();
bbox.move(0, child->borderTopExtra());
result.unite(bbox);
IntRect overflowRect = renderer()->overflowRect(false);
overflowRect.move(0, child->borderTopExtra());
if (bbox != overflowRect)
result.unite(overflowRect);
}
}
result.move(m_x, m_y);
} else {
IntRect bbox = renderer()->borderBox();
result = bbox;
IntRect overflowRect = renderer()->overflowRect(false);
if (bbox != overflowRect)
result.unite(overflowRect);
result.move(m_x, m_y + renderer()->borderTopExtra());
}
RenderView* view = renderer()->view();
ASSERT(view);
if (view)
result.inflate(view->maximalOutlineSize());
return result;
}
IntRect RenderLayer::absoluteBoundingBox() const
{
return boundingBox(root());
}
IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const
{
IntRect result = localBoundingBox();
int absX = 0, absY = 0;
convertToLayerCoords(rootLayer, absX, absY);
result.move(absX - m_x, absY - m_y);
return result;
}
void RenderLayer::clearClipRects()
{
if (!m_clipRects)
return;
clearClipRect();
for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
l->clearClipRects();
}
void RenderLayer::clearClipRect()
{
if (m_clipRects) {
m_clipRects->deref(m_object->renderArena());
m_clipRects = 0;
}
}
static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
{
if (!obj1 || !obj2)
return 0;
for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
if (currObj1 == currObj2)
return currObj1;
return 0;
}
void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
{
if (request.readonly)
return;
Document* doc = renderer()->document();
Node* activeNode = doc->activeNode();
if (activeNode && !request.active) {
for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
if (curr->element() && !curr->isText())
curr->element()->setInActiveChain(false);
}
doc->setActiveNode(0);
} else {
Node* newActiveNode = result.innerNode();
if (!activeNode && newActiveNode && request.active) {
for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
if (curr->element() && !curr->isText()) {
curr->element()->setInActiveChain(true);
}
}
doc->setActiveNode(newActiveNode);
}
}
bool mustBeInActiveChain = request.active && request.mouseMove;
RefPtr<Node> oldHoverNode = doc->hoverNode();
Node* newHoverNode = result.innerNode();
doc->setHoverNode(newHoverNode);
RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
if (oldHoverObj != newHoverObj) {
for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
curr->element()->setActive(false);
curr->element()->setHovered(false);
}
}
}
for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
curr->element()->setActive(request.active);
curr->element()->setHovered(true);
}
}
}
static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
{
return first->zIndex() < second->zIndex();
}
void RenderLayer::dirtyZOrderLists(bool inScheduleUpdate )
{
#if ENABLE(HW_COMP)
ASSERT(!m_rebuildingLayerTree);
#endif
if (m_posZOrderList)
m_posZOrderList->clear();
if (m_negZOrderList)
m_negZOrderList->clear();
m_zOrderListsDirty = true;
#if ENABLE(HW_COMP)
if (inScheduleUpdate && inCompositingMode())
renderer()->scheduleLayerUpdate();
#endif
}
void RenderLayer::dirtyStackingContextZOrderList(bool inScheduleUpdate )
{
#if ENABLE(HW_COMP)
ASSERT(!m_rebuildingLayerTree);
#endif
RenderLayer* sc = stackingContext();
if (sc)
sc->dirtyZOrderLists(inScheduleUpdate);
}
void RenderLayer::dirtyOverflowList()
{
if (m_overflowList)
m_overflowList->clear();
m_overflowListDirty = true;
#if ENABLE(HW_COMP)
if (inCompositingMode())
renderer()->scheduleLayerUpdate();
#endif
}
void RenderLayer::updateZOrderLists()
{
if (!isStackingContext() || !m_zOrderListsDirty)
return;
ASSERT(!m_posZOrderList || m_posZOrderList->size() == 0);
ASSERT(!m_negZOrderList || m_negZOrderList->size() == 0);
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->collectLayers(m_posZOrderList, m_negZOrderList);
if (m_posZOrderList)
std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
if (m_negZOrderList)
std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
m_zOrderListsDirty = false;
}
void RenderLayer::updateOverflowList()
{
if (!m_overflowListDirty)
return;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
if (child->isOverflowOnly()) {
if (!m_overflowList)
m_overflowList = new Vector<RenderLayer*>;
m_overflowList->append(child);
}
}
m_overflowListDirty = false;
}
void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer)
{
updateVisibilityStatus();
if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) {
Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
if (!buffer)
buffer = new Vector<RenderLayer*>;
buffer->append(this);
}
if (m_hasVisibleDescendant && !isStackingContext())
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->collectLayers(posBuffer, negBuffer);
}
void RenderLayer::repaintIncludingDescendants()
{
m_object->repaint();
for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
curr->repaintIncludingDescendants();
}
void RenderLayer::repaintAbsoluteRectIncludingDescendants(const IntRect& r)
{
#if ENABLE(HW_COMP)
if (inCompositingMode()) {
RenderLayer* compLayer = enclosingCompositingLayer();
IntRect layerRect(r);
int x = 0, y = 0;
convertToLayerCoords(root(), x, y);
layerRect.move(-x, -y);
compLayer->repaintCompositingLayerRect(layerRect, true);
}
#endif
}
bool RenderLayer::shouldBeOverflowOnly() const
{
return renderer()->hasOverflowClip() &&
!renderer()->isPositioned() &&
!renderer()->isRelPositioned() &&
!isTransparent();
}
void RenderLayer::setStyleChangePending(bool inPending)
{
m_styleChangePending = inPending;
}
void RenderLayer::styleChanged(RenderStyle::Diff inDiff, bool hasOldStyle)
{
bool isOverflowOnly = shouldBeOverflowOnly();
if (isOverflowOnly != m_isOverflowOnly) {
m_isOverflowOnly = isOverflowOnly;
RenderLayer* p = parent();
if (p)
p->dirtyOverflowList();
dirtyStackingContextZOrderList();
}
if (m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) {
if (!m_marquee)
m_marquee = new Marquee(this);
m_marquee->updateMarqueeStyle();
}
else if (m_marquee) {
delete m_marquee;
m_marquee = 0;
}
#if ENABLE(HW_COMP)
updateCompositingLayer(hasOldStyle, true, inDiff >= RenderStyle::Repaint);
#endif
if (inDiff == RenderStyle::RecompositeLayer) {
#if ENABLE(TOUCH_EVENTS)
if (m_object->document()->touchEventListeners().size() > 0)
m_object->document()->setTouchEventListenersDirty(true);
#endif
}
}
void RenderLayer::suspendMarquees()
{
if (m_marquee)
m_marquee->suspend();
for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
curr->suspendMarquees();
}
#if !ENABLE(HW_COMP)
bool RenderLayer::startAnimation(double beginTime, int index)
{
return false;
}
bool RenderLayer::startTransition(double beginTime, int property, RenderStyle* toStyle)
{
return false
}
void RenderLayer::setAnimationStartTime(double t)
{
}
void RenderLayer::setTransitionStartTime(int property, double t)
{
}
void RenderLayer::animationFinished(const String& name, int index, bool reset)
{
}
void RenderLayer::transitionFinished(int property)
{
}
#endif
FloatPoint RenderLayer::convertToPage(const FloatPoint& inPoint)
{
#if ENABLE(HW_COMP)
RenderLayer* compLayer = enclosingCompositingLayer();
if (compLayer) {
FloatPoint compLayerPoint(inPoint);
if (compLayer != this) {
int myX, myY;
renderer()->absolutePosition(myX, myY);
int compLayerX, compLayerY;
compLayer->renderer()->absolutePosition(compLayerX, compLayerY);
compLayerPoint.move(myX - compLayerX, myY - compLayerY);
}
return compLayer->convertToPageUsingCompositingLayer(compLayerPoint);
}
#endif
int myX, myY;
m_object->absolutePosition(myX, myY);
return FloatPoint((float)myX + inPoint.x(), (float)myY + inPoint.y());
}
FloatPoint RenderLayer::convertFromPage(const FloatPoint& inPoint)
{
#if ENABLE(HW_COMP)
RenderLayer* compLayer = enclosingCompositingLayer();
if (compLayer) {
FloatPoint compLayerPoint(compLayer->convertFromPageUsingCompositingLayer(inPoint));
if (compLayer != this) {
int myX, myY;
renderer()->absolutePosition(myX, myY);
int compLayerX, compLayerY;
compLayer->renderer()->absolutePosition(compLayerX, compLayerY);
compLayerPoint.move(compLayerX - myX, compLayerY - myY);
}
return compLayerPoint;
}
#endif
int myX, myY;
m_object->absolutePosition(myX, myY);
return FloatPoint(inPoint.x() - (float)myX, inPoint.y() - (float)myY);
}
void RenderLayer::convertQuadToPage(FloatQuad& ioQuad)
{
#if ENABLE(HW_COMP)
RenderLayer* compLayer = enclosingCompositingLayer();
if (compLayer) {
if (compLayer != this) {
int myX, myY;
renderer()->absolutePosition(myX, myY);
int compLayerX, compLayerY;
compLayer->renderer()->absolutePosition(compLayerX, compLayerY);
ioQuad.move(myX - compLayerX, myY - compLayerY);
}
compLayer->convertQuadToPageUsingCompositingLayer(ioQuad);
return;
}
#endif
int myX, myY;
m_object->absolutePosition(myX, myY);
ioQuad.move(myX, myY);
}
#pragma mark -
Marquee::Marquee(RenderLayer* l)
: m_layer(l), m_currentLoop(0)
, m_totalLoops(0)
, m_timer(this, &Marquee::timerFired)
, m_start(0), m_end(0), m_speed(0), m_reset(false)
, m_suspended(false), m_stopped(false), m_direction(MAUTO)
{
}
int Marquee::marqueeSpeed() const
{
int result = m_layer->renderer()->style()->marqueeSpeed();
Node* elt = m_layer->renderer()->element();
if (elt && elt->hasTagName(marqueeTag)) {
HTMLMarqueeElement* marqueeElt = static_cast<HTMLMarqueeElement*>(elt);
result = max(result, marqueeElt->minimumDelay());
}
return result;
}
EMarqueeDirection Marquee::direction() const
{
EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection();
TextDirection dir = m_layer->renderer()->style()->direction();
if (result == MAUTO)
result = MBACKWARD;
if (result == MFORWARD)
result = (dir == LTR) ? MRIGHT : MLEFT;
if (result == MBACKWARD)
result = (dir == LTR) ? MLEFT : MRIGHT;
Length increment = m_layer->renderer()->style()->marqueeIncrement();
if (increment.isNegative())
result = static_cast<EMarqueeDirection>(-result);
return result;
}
bool Marquee::isHorizontal() const
{
return direction() == MLEFT || direction() == MRIGHT;
}
int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
{
RenderObject* o = m_layer->renderer();
RenderStyle* s = o->style();
if (isHorizontal()) {
bool ltr = s->direction() == LTR;
int clientWidth = o->clientWidth();
int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false);
if (ltr)
contentWidth += (o->paddingRight() - o->borderLeft());
else {
contentWidth = o->width() - contentWidth;
contentWidth += (o->paddingLeft() - o->borderRight());
}
if (dir == MRIGHT) {
if (stopAtContentEdge)
return max(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
else
return ltr ? contentWidth : clientWidth;
}
else {
if (stopAtContentEdge)
return min(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
else
return ltr ? -clientWidth : -contentWidth;
}
}
else {
int contentHeight = m_layer->renderer()->lowestPosition(true, false) -
m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom();
int clientHeight = m_layer->renderer()->clientHeight();
if (dir == MUP) {
if (stopAtContentEdge)
return min(contentHeight - clientHeight, 0);
else
return -clientHeight;
}
else {
if (stopAtContentEdge)
return max(contentHeight - clientHeight, 0);
else
return contentHeight;
}
}
}
void Marquee::start()
{
if (m_timer.isActive() || m_layer->renderer()->style()->marqueeIncrement().isZero())
return;
FrameView* frameView = m_layer->renderer()->document()->view();
if (frameView)
frameView->pauseScheduledEvents();
if (!m_suspended && !m_stopped) {
if (isHorizontal())
m_layer->scrollToOffset(m_start, 0, false, false);
else
m_layer->scrollToOffset(0, m_start, false, false);
}
else {
m_suspended = false;
m_stopped = false;
}
m_timer.startRepeating(speed() * 0.001);
if (frameView)
frameView->resumeScheduledEvents();
}
void Marquee::suspend()
{
m_timer.stop();
m_suspended = true;
}
void Marquee::stop()
{
m_timer.stop();
m_stopped = true;
}
void Marquee::updateMarqueePosition()
{
bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
if (activate) {
EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
m_start = computePosition(direction(), behavior == MALTERNATE);
m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
if (!m_stopped)
start();
}
}
void Marquee::updateMarqueeStyle()
{
RenderStyle* s = m_layer->renderer()->style();
if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops))
m_currentLoop = 0;
m_totalLoops = s->marqueeLoopCount();
m_direction = s->marqueeDirection();
if (m_layer->renderer()->isHTMLMarquee()) {
if (m_totalLoops <= 0 && s->marqueeBehavior() == MSLIDE)
m_totalLoops = 1;
if (isHorizontal() && m_layer->renderer()->childrenInline()) {
s->setWhiteSpace(NOWRAP);
s->setTextAlign(TAAUTO);
}
}
if (isHorizontal()) {
if (s->height().isFixed() && s->height().value() < s->fontSize())
s->setHeight(Length(s->fontSize(),Fixed));
} else if (s->height().isAuto()) s->setHeight(Length(200, Fixed));
if (speed() != marqueeSpeed()) {
m_speed = marqueeSpeed();
if (m_timer.isActive())
m_timer.startRepeating(speed() * 0.001);
}
bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
if (activate && !m_timer.isActive())
m_layer->renderer()->setNeedsLayout(true);
else if (!activate && m_timer.isActive())
m_timer.stop();
}
void Marquee::timerFired(Timer<Marquee>*)
{
if (m_layer->renderer()->needsLayout())
return;
if (m_reset) {
m_reset = false;
if (isHorizontal())
m_layer->scrollToXOffset(m_start);
else
m_layer->scrollToYOffset(m_start);
return;
}
RenderStyle* s = m_layer->renderer()->style();
int endPoint = m_end;
int range = m_end - m_start;
int newPos;
if (range == 0)
newPos = m_end;
else {
bool addIncrement = direction() == MUP || direction() == MLEFT;
bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2;
if (isReversed) {
endPoint = m_start;
range = -range;
addIncrement = !addIncrement;
}
bool positive = range > 0;
int clientSize = (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight());
int increment = max(1, abs(m_layer->renderer()->style()->marqueeIncrement().calcValue(clientSize)));
int currentPos = (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset());
newPos = currentPos + (addIncrement ? increment : -increment);
if (positive)
newPos = min(newPos, endPoint);
else
newPos = max(newPos, endPoint);
}
if (newPos == endPoint) {
m_currentLoop++;
if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops)
m_timer.stop();
else if (s->marqueeBehavior() != MALTERNATE)
m_reset = true;
}
if (isHorizontal())
m_layer->scrollToXOffset(newPos);
else
m_layer->scrollToYOffset(newPos);
}
}