#include "AXObjectCache.h"
#include "CSSStyleSelector.h"
+#include "CachedResourceLoader.h"
#include "Chrome.h"
#include "ChromeClient.h"
-#include "DocLoader.h"
#include "EventHandler.h"
#include "FloatRect.h"
#include "FocusController.h"
#include "HTMLFrameElement.h"
#include "HTMLFrameSetElement.h"
#include "HTMLNames.h"
-#include "InspectorTimelineAgent.h"
+#include "HTMLPlugInImageElement.h"
+#include "InspectorInstrumentation.h"
#include "OverflowEvent.h"
#include "RenderEmbeddedObject.h"
+#include "RenderLayer.h"
#include "RenderPart.h"
#include "RenderScrollbar.h"
#include "RenderScrollbarPart.h"
double FrameView::sCurrentPaintTimeStamp = 0.0;
+// REPAINT_THROTTLING now chooses default values for throttling parameters.
+// Should be removed when applications start using runtime configuration.
#if ENABLE(REPAINT_THROTTLING)
// Normal delay
-static const double deferredRepaintDelay = 0.025;
+double FrameView::s_deferredRepaintDelay = 0.025;
// Negative value would mean that first few repaints happen without a delay
-static const double initialDeferredRepaintDelayDuringLoading = 0;
+double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0;
// The delay grows on each repaint to this maximum value
-static const double maxDeferredRepaintDelayDuringLoading = 2.5;
+double FrameView::s_maxDeferredRepaintDelayDuringLoading = 2.5;
// On each repaint the delay increses by this amount
-static const double deferredRepaintDelayIncrementDuringLoading = 0.5;
+double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0.5;
#else
// FIXME: Repaint throttling could be good to have on all platform.
// The balance between CPU use and repaint frequency will need some tuning for desktop.
// More hooks may be needed to reset the delay on things like GIF and CSS animations.
-static const double deferredRepaintDelay = 0;
-static const double initialDeferredRepaintDelayDuringLoading = 0;
-static const double maxDeferredRepaintDelayDuringLoading = 0;
-static const double deferredRepaintDelayIncrementDuringLoading = 0;
+double FrameView::s_deferredRepaintDelay = 0;
+double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0;
+double FrameView::s_maxDeferredRepaintDelayDuringLoading = 0;
+double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0;
#endif
// The maximum number of updateWidgets iterations that should be done before returning.
, m_fixedObjectCount(0)
, m_layoutTimer(this, &FrameView::layoutTimerFired)
, m_layoutRoot(0)
+ , m_hasPendingPostLayoutTasks(false)
+ , m_inSynchronousPostLayout(false)
, m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
, m_isTransparent(false)
, m_baseBackgroundColor(Color::white)
FrameView::~FrameView()
{
- if (m_postLayoutTasksTimer.isActive()) {
+ if (m_hasPendingPostLayoutTasks) {
m_postLayoutTasksTimer.stop();
m_scheduledEvents.clear();
m_enqueueEvents = 0;
m_delayedLayout = false;
m_doFullRepaint = true;
m_layoutSchedulingEnabled = true;
- m_midLayout = false;
+ m_inLayout = false;
+ m_inSynchronousPostLayout = false;
+ m_hasPendingPostLayoutTasks = false;
m_layoutCount = 0;
m_nestedLayoutCount = 0;
m_postLayoutTasksTimer.stop();
m_deferringRepaints = 0;
m_repaintCount = 0;
m_repaintRects.clear();
- m_deferredRepaintDelay = initialDeferredRepaintDelayDuringLoading;
+ m_deferredRepaintDelay = s_initialDeferredRepaintDelayDuringLoading;
m_deferredRepaintTimer.stop();
m_lastPaintTime = 0;
m_paintBehavior = PaintBehaviorNormal;
return;
Scrollbar* horizontalBar = horizontalScrollbar();
- if (horizontalBar && horizontalBar->isCustomScrollbar() && !toRenderScrollbar(horizontalBar)->owningRenderer()->isRenderPart())
+ if (horizontalBar && horizontalBar->isCustomScrollbar())
setHasHorizontalScrollbar(false);
Scrollbar* verticalBar = verticalScrollbar();
- if (verticalBar && verticalBar->isCustomScrollbar() && !toRenderScrollbar(verticalBar)->owningRenderer()->isRenderPart())
+ if (verticalBar && verticalBar->isCustomScrollbar())
setHasVerticalScrollbar(false);
if (m_scrollCorner) {
renderer->repaintRectangle(repaintRect);
}
+void FrameView::setFrameRect(const IntRect& newRect)
+{
+ IntRect oldRect = frameRect();
+ if (newRect == oldRect)
+ return;
+
+ ScrollView::setFrameRect(newRect);
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* root = m_frame->contentRenderer()) {
+ if (root->usesCompositing())
+ root->compositor()->frameViewDidChangeSize();
+ }
+#endif
+}
+
void FrameView::setMarginWidth(int w)
{
// make it update the rendering area when set
ScrollbarMode vMode;
scrollbarModes(hMode, vMode);
if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
- m_canHaveScrollbars = false;
+ setCanHaveScrollbars(false);
else
- m_canHaveScrollbars = true;
+ setCanHaveScrollbars(true);
}
PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
// If we have an owning iframe/frame element, then it can set the custom scrollbar also.
RenderPart* frameRenderer = m_frame->ownerRenderer();
if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR))
- return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer);
+ return RenderScrollbar::createCustomScrollbar(this, orientation, 0, m_frame.get());
// Nobody set a custom style, so we just use a native scrollbar.
return ScrollView::createScrollbar(orientation);
m_viewportRenderer = o;
}
+void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode)
+{
+ if (m_canHaveScrollbars) {
+ hMode = ScrollbarAuto;
+ vMode = ScrollbarAuto;
+ } else {
+ hMode = ScrollbarAlwaysOff;
+ vMode = ScrollbarAlwaysOff;
+ }
+
+ if (!m_layoutRoot) {
+ Document* document = m_frame->document();
+ Node* documentElement = document->documentElement();
+ RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0;
+ Node* body = document->body();
+ if (body && body->renderer()) {
+ if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) {
+#if !defined(ANDROID_FLATTEN_IFRAME) && !defined(ANDROID_FLATTEN_FRAMESET)
+ body->renderer()->setChildNeedsLayout(true);
+ vMode = ScrollbarAlwaysOff;
+ hMode = ScrollbarAlwaysOff;
+#endif
+ } else if (body->hasTagName(bodyTag)) {
+ // It's sufficient to just check the X overflow,
+ // since it's illegal to have visible in only one direction.
+ RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
+ applyOverflowToViewport(o, hMode, vMode);
+ }
+ } else if (rootRenderer) {
+#if ENABLE(SVG)
+ if (documentElement->isSVGElement()) {
+ if (!m_firstLayout && (m_size.width() != layoutWidth() || m_size.height() != layoutHeight()))
+ rootRenderer->setChildNeedsLayout(true);
+ } else
+ applyOverflowToViewport(rootRenderer, hMode, vMode);
+#else
+ applyOverflowToViewport(rootRenderer, hMode, vMode);
+#endif
+ }
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (m_firstLayout && !document->ownerElement())
+ printf("Elapsed time before first layout: %d\n", document->elapsedTime());
+#endif
+ }
+
+ HTMLFrameOwnerElement* owner = m_frame->ownerElement();
+ if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
+ hMode = ScrollbarAlwaysOff;
+ vMode = ScrollbarAlwaysOff;
+ }
+}
+
#if USE(ACCELERATED_COMPOSITING)
void FrameView::updateCompositingLayers()
{
// This call will make sure the cached hasAcceleratedCompositing is updated from the pref
view->compositor()->cacheAcceleratedCompositingFlags();
-
- if (!view->usesCompositing())
- return;
-
view->compositor()->updateCompositingLayers(CompositingUpdateAfterLayoutOrStyleChange);
}
void FrameView::enterCompositingMode()
{
#if USE(ACCELERATED_COMPOSITING)
- if (RenderView* view = m_frame->contentRenderer())
- return view->compositor()->enableCompositingMode();
+ if (RenderView* view = m_frame->contentRenderer()) {
+ view->compositor()->enableCompositingMode();
+ if (!needsLayout())
+ view->compositor()->scheduleCompositingLayerUpdate();
+ }
#endif
}
if (!contentRenderer)
return true; // We don't want to keep trying to update layers if we have no renderer.
- if (m_layoutTimer.isActive()) {
- // Don't sync layers if there's a layout pending.
+ // If we sync compositing layers when a layout is pending, we may cause painting of compositing
+ // layer content to occur before layout has happened, which will cause paintContents() to bail.
+ if (needsLayout())
return false;
- }
if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer())
rootLayer->syncCompositingState();
void FrameView::layout(bool allowSubtree)
{
- if (m_midLayout)
+ if (m_inLayout)
return;
m_layoutTimer.stop();
if (isPainting())
return;
-#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent())
- timelineAgent->willLayout();
-#endif
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
if (!allowSubtree && m_layoutRoot) {
m_layoutRoot->markContainingBlocksForLayout(false);
}
ASSERT(m_frame->view() == this);
- // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
- // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful
- // failure instead.
- if (m_frame->view() != this)
- return;
Document* document = m_frame->document();
m_layoutSchedulingEnabled = false;
- if (!m_nestedLayoutCount && m_postLayoutTasksTimer.isActive()) {
+ if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_hasPendingPostLayoutTasks) {
// This is a new top-level layout. If there are any remaining tasks from the previous
// layout, finish them now.
+ m_inSynchronousPostLayout = true;
m_postLayoutTasksTimer.stop();
performPostLayoutTasks();
+ m_inSynchronousPostLayout = false;
}
// Viewport-dependent media queries may cause us to need completely different style information.
// Check that here.
if (document->styleSelector()->affectedByViewportChange())
- document->updateStyleSelector();
+ document->styleSelectorChanged(RecalcStyleImmediately);
// Always ensure our style info is up-to-date. This can happen in situations where
// the layout beats any sort of style recalc update that needs to occur.
- if (m_frame->needsReapplyStyles())
- m_frame->reapplyStyles();
- else if (document->childNeedsStyleRecalc())
- document->recalcStyle();
+ document->updateStyleIfNeeded();
bool subtree = m_layoutRoot;
ScrollbarMode hMode;
ScrollbarMode vMode;
- if (m_canHaveScrollbars) {
- hMode = ScrollbarAuto;
- vMode = ScrollbarAuto;
- } else {
- hMode = ScrollbarAlwaysOff;
- vMode = ScrollbarAlwaysOff;
- }
-
- if (!subtree) {
- Node* documentElement = document->documentElement();
- RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0;
- Node* body = document->body();
- if (body && body->renderer()) {
- if (body->hasTagName(framesetTag) && !m_frame->settings()->frameFlatteningEnabled()) {
- body->renderer()->setChildNeedsLayout(true);
- vMode = ScrollbarAlwaysOff;
- hMode = ScrollbarAlwaysOff;
- } else if (body->hasTagName(bodyTag)) {
- if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox()->stretchesToViewHeight())
- body->renderer()->setChildNeedsLayout(true);
- // It's sufficient to just check the X overflow,
- // since it's illegal to have visible in only one direction.
- RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
- applyOverflowToViewport(o, hMode, vMode);
- }
- } else if (rootRenderer) {
-#if ENABLE(SVG)
- if (documentElement->isSVGElement()) {
- if (!m_firstLayout && (m_size.width() != layoutWidth() || m_size.height() != layoutHeight()))
- rootRenderer->setChildNeedsLayout(true);
- } else
- applyOverflowToViewport(rootRenderer, hMode, vMode);
-#else
- applyOverflowToViewport(rootRenderer, hMode, vMode);
-#endif
- }
-#ifdef INSTRUMENT_LAYOUT_SCHEDULING
- if (m_firstLayout && !document->ownerElement())
- printf("Elapsed time before first layout: %d\n", document->elapsedTime());
-#endif
- }
+
+ calculateScrollbarModesForLayout(hMode, vMode);
m_doFullRepaint = !subtree && (m_firstLayout || toRenderView(root)->printing());
m_size = IntSize(layoutWidth(), layoutHeight());
- if (oldSize != m_size)
+ if (oldSize != m_size) {
m_doFullRepaint = true;
+ if (!m_firstLayout) {
+ RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
+ RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
+ if (bodyRenderer && bodyRenderer->stretchesToViewport())
+ bodyRenderer->setChildNeedsLayout(true);
+ else if (rootRenderer && rootRenderer->stretchesToViewport())
+ rootRenderer->setChildNeedsLayout(true);
+ }
+ }
}
RenderLayer* layer = root->enclosingLayer();
view->disableLayoutState();
}
- m_midLayout = true;
+ m_inLayout = true;
beginDeferredRepaints();
root->layout();
endDeferredRepaints();
- m_midLayout = false;
+ m_inLayout = false;
if (subtree) {
RenderView* view = root->view();
- view->popLayoutState();
+ view->popLayoutState(root);
if (disableLayoutState)
view->enableLayoutState();
}
m_layoutRoot = 0;
- m_frame->selection()->setNeedsLayout();
+ m_frame->selection()->setCaretRectNeedsUpdate();
m_frame->selection()->updateAppearance();
m_layoutSchedulingEnabled = true;
m_layoutCount++;
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
if (AXObjectCache::accessibilityEnabled())
root->document()->axObjectCache()->postNotification(root, AXObjectCache::AXLayoutComplete, true);
#endif
updateOverflowStatus(layoutWidth() < contentsWidth(),
layoutHeight() < contentsHeight());
- if (!m_postLayoutTasksTimer.isActive()) {
- // Calls resumeScheduledEvents()
- performPostLayoutTasks();
+ if (!m_hasPendingPostLayoutTasks) {
+ if (!m_inSynchronousPostLayout) {
+ m_inSynchronousPostLayout = true;
+ // Calls resumeScheduledEvents()
+ performPostLayoutTasks();
+ m_inSynchronousPostLayout = false;
+ }
- if (!m_postLayoutTasksTimer.isActive() && needsLayout()) {
- // Post-layout widget updates or an event handler made us need layout again.
- // Lay out again, but this time defer widget updates and event dispatch until after
- // we return.
+ if (!m_hasPendingPostLayoutTasks && (needsLayout() || m_inSynchronousPostLayout)) {
+ // If we need layout or are already in a synchronous call to postLayoutTasks(),
+ // defer widget updates and event dispatch until after we return. postLayoutTasks()
+ // can make us need to update again, and we can get stuck in a nasty cycle unless
+ // we call it through the timer here.
+ m_hasPendingPostLayoutTasks = true;
m_postLayoutTasksTimer.startOneShot(0);
- pauseScheduledEvents();
- layout();
+ if (needsLayout()) {
+ pauseScheduledEvents();
+ layout();
+ }
}
} else {
resumeScheduledEvents();
ASSERT(m_enqueueEvents);
}
-#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent())
- timelineAgent->didLayout();
-#endif
+ InspectorInstrumentation::didLayout(cookie);
m_nestedLayoutCount--;
}
void FrameView::addFixedObject()
{
+ if (!m_fixedObjectCount && platformWidget())
+ setCanBlitOnScroll(false);
++m_fixedObjectCount;
}
{
ASSERT(m_fixedObjectCount > 0);
--m_fixedObjectCount;
+ if (!m_fixedObjectCount)
+ setCanBlitOnScroll(!useSlowRepaints());
+}
+
+bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
+{
+ const size_t fixedObjectThreshold = 5;
+
+ RenderBlock::PositionedObjectsListHashSet* positionedObjects = 0;
+ if (RenderView* root = m_frame->contentRenderer())
+ positionedObjects = root->positionedObjects();
+
+ if (!positionedObjects || positionedObjects->isEmpty()) {
+ hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
+ return true;
+ }
+
+ // Get the rects of the fixed objects visible in the rectToScroll
+ Vector<IntRect, fixedObjectThreshold> subRectToUpdate;
+ bool updateInvalidatedSubRect = true;
+ RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
+ for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
+ RenderBox* renderBox = *it;
+ if (renderBox->style()->position() != FixedPosition)
+ continue;
+ IntRect updateRect = renderBox->layer()->repaintRectIncludingDescendants();
+ updateRect = contentsToWindow(updateRect);
+
+ updateRect.intersect(rectToScroll);
+ if (!updateRect.isEmpty()) {
+ if (subRectToUpdate.size() >= fixedObjectThreshold) {
+ updateInvalidatedSubRect = false;
+ break;
+ }
+ subRectToUpdate.append(updateRect);
+ }
+ }
+
+ // Scroll the view
+ if (updateInvalidatedSubRect) {
+ // 1) scroll
+ hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
+
+ // 2) update the area of fixed objects that has been invalidated
+ size_t fixObjectsCount = subRectToUpdate.size();
+ for (size_t i = 0; i < fixObjectsCount; ++i) {
+ IntRect updateRect = subRectToUpdate[i];
+ IntRect scrolledRect = updateRect;
+ scrolledRect.move(scrollDelta);
+ updateRect.unite(scrolledRect);
+ updateRect.intersect(rectToScroll);
+ hostWindow()->invalidateContentsAndWindow(updateRect, false);
+ }
+ return true;
+ }
+
+ // the number of fixed objects exceed the threshold, we cannot use the fast path
+ return false;
}
+void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
+ if (frameRenderer->containerForRepaint()) {
+ IntRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
+ frameRenderer->borderTop() + frameRenderer->paddingTop(),
+ visibleWidth(), visibleHeight());
+ frameRenderer->repaintRectangle(rect);
+ return;
+ }
+ }
+#endif
+
+ ScrollView::scrollContentsSlowPath(updateRect);
+}
+
+// Note that this gets called at painting time.
void FrameView::setIsOverlapped(bool isOverlapped)
{
if (isOverlapped == m_isOverlapped)
#if USE(ACCELERATED_COMPOSITING)
// Overlap can affect compositing tests, so if it changes, we need to trigger
- // a recalcStyle in the parent document.
+ // a layer update in the parent document.
if (hasCompositedContent()) {
- if (Element* ownerElement = m_frame->document()->ownerElement())
- ownerElement->setNeedsStyleRecalc(SyntheticStyleChange);
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ if (RenderView* parentView = parentFrame->contentRenderer()) {
+ RenderLayerCompositor* compositor = parentView->compositor();
+ compositor->setCompositingLayersNeedRebuild();
+ compositor->scheduleCompositingLayerUpdate();
+ }
+ }
}
#endif
}
#ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR
// TODO(andreip): check with Grace if this is correct.
- android::WebFrame::getWebFrame(m_frame.get())->setUserInitiatedClick(true);
+ android::WebFrame::getWebFrame(m_frame.get())->setUserInitiatedAction(true);
#endif
maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
#ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR
- android::WebFrame::getWebFrame(m_frame.get())->setUserInitiatedClick(false);
+ android::WebFrame::getWebFrame(m_frame.get())->setUserInitiatedAction(false);
#endif
return true;
}
m_inProgrammaticScroll = wasInProgrammaticScroll;
}
+void FrameView::scrollPositionChangedViaPlatformWidget()
+{
+ repaintFixedElementsAfterScrolling();
+ scrollPositionChanged();
+}
+
void FrameView::scrollPositionChanged()
{
frame()->eventHandler()->sendScrollEvent();
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* root = m_frame->contentRenderer()) {
+ if (root->usesCompositing())
+ root->compositor()->frameViewDidScroll(scrollPosition());
+ }
+#endif
+}
+
+void FrameView::repaintFixedElementsAfterScrolling()
+{
// For fixed position elements, update widget positions and compositing layers after scrolling,
// but only if we're not inside of layout.
if (!m_nestedLayoutCount && hasFixedObjects()) {
root->updateWidgetPositions();
root->layer()->updateRepaintRectsAfterScroll();
#if USE(ACCELERATED_COMPOSITING)
- if (root->usesCompositing())
- root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll);
+ root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll);
#endif
}
}
-
-#if USE(ACCELERATED_COMPOSITING)
- if (RenderView* root = m_frame->contentRenderer()) {
- if (root->usesCompositing())
- root->compositor()->updateContentLayerScrollPosition(scrollPosition());
- }
-#endif
}
HostWindow* FrameView::hostWindow() const
return;
Document* document = m_frame->document();
- if (document && (document->parsing() || document->docLoader()->requestCount()))
+ if (document && (document->parsing() || document->cachedResourceLoader()->requestCount()))
return;
m_deferredRepaintTimer.stop();
void FrameView::updateDeferredRepaintDelay()
{
Document* document = m_frame->document();
- if (!document || (!document->parsing() && !document->docLoader()->requestCount())) {
- m_deferredRepaintDelay = deferredRepaintDelay;
+ if (!document || (!document->parsing() && !document->cachedResourceLoader()->requestCount())) {
+ m_deferredRepaintDelay = s_deferredRepaintDelay;
return;
}
- if (m_deferredRepaintDelay < maxDeferredRepaintDelayDuringLoading) {
- m_deferredRepaintDelay += deferredRepaintDelayIncrementDuringLoading;
- if (m_deferredRepaintDelay > maxDeferredRepaintDelayDuringLoading)
- m_deferredRepaintDelay = maxDeferredRepaintDelayDuringLoading;
+ if (m_deferredRepaintDelay < s_maxDeferredRepaintDelayDuringLoading) {
+ m_deferredRepaintDelay += s_deferredRepaintDelayIncrementDuringLoading;
+ if (m_deferredRepaintDelay > s_maxDeferredRepaintDelayDuringLoading)
+ m_deferredRepaintDelay = s_maxDeferredRepaintDelayDuringLoading;
}
}
// When frame flattening is enabled, the contents of the frame affects layout of the parent frames.
// Also invalidate parent frame starting from the owner element of this frame.
- if (m_frame->settings()->frameFlatteningEnabled() && m_frame->ownerRenderer()) {
+ if (m_frame->settings() && m_frame->settings()->frameFlatteningEnabled() && m_frame->ownerRenderer()) {
if (m_frame->ownerElement()->hasTagName(iframeTag) || m_frame->ownerElement()->hasTagName(frameTag))
m_frame->ownerRenderer()->setNeedsLayout(true, true);
}
if (!m_frame)
return false;
RenderView* root = m_frame->contentRenderer();
- Document* document = m_frame->document();
return layoutPending()
|| (root && root->needsLayout())
|| m_layoutRoot
- || (document && document->childNeedsStyleRecalc()) // can occur when using WebKit ObjC interface
- || m_frame->needsReapplyStyles()
|| (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
}
void FrameView::unscheduleRelayout()
{
+ m_postLayoutTasksTimer.stop();
+
if (!m_layoutTimer.isActive())
return;
m_maintainScrollPositionAnchor = anchorNode;
}
+void FrameView::updateWidget(RenderEmbeddedObject* object)
+{
+ ASSERT(!object->node() || object->node()->isElementNode());
+ Element* ownerElement = static_cast<Element*>(object->node());
+ // The object may have already been destroyed (thus node cleared),
+ // but FrameView holds a manual ref, so it won't have been deleted.
+ ASSERT(m_widgetUpdateSet->contains(object));
+ if (!ownerElement)
+ return;
+
+ // No need to update if it's already crashed or known to be missing.
+ if (object->pluginCrashedOrWasMissing())
+ return;
+
+ // FIXME: This could turn into a real virtual dispatch if we defined
+ // updateWidget(bool) on HTMLElement.
+ if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag))
+ static_cast<HTMLPlugInImageElement*>(ownerElement)->updateWidget(false);
+ // FIXME: It is not clear that Media elements need or want this updateWidget() call.
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ else if (ownerElement->hasTagName(videoTag) || ownerElement->hasTagName(audioTag))
+ static_cast<HTMLMediaElement*>(ownerElement)->updateWidget(false);
+#endif
+ else
+ ASSERT_NOT_REACHED();
+
+ // Caution: it's possible the object was destroyed again, since loading a
+ // plugin may run any arbitrary javascript.
+ object->updateWidgetPosition();
+}
+
bool FrameView::updateWidgets()
{
if (m_nestedLayoutCount > 1 || !m_widgetUpdateSet || m_widgetUpdateSet->isEmpty())
for (size_t i = 0; i < size; ++i) {
RenderEmbeddedObject* object = objects[i];
-
- // The object may have been destroyed, but our manual ref() keeps the object from being deleted.
- object->updateWidget(false);
- object->updateWidgetPosition();
-
+ updateWidget(object);
m_widgetUpdateSet->remove(object);
}
void FrameView::performPostLayoutTasks()
{
+ m_hasPendingPostLayoutTasks = false;
+
if (m_firstLayoutCallbackPending) {
m_firstLayoutCallbackPending = false;
m_frame->loader()->didFirstLayout();
// Set our clip rect to be our contents.
IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents));
- if (!m_frame || !m_frame->document()->ownerElement())
+ if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
return clipRect;
// Take our owner element and get the clip rect from the enclosing layer.
IntSize offset = scrollOffset();
ScrollView::valueChanged(bar);
if (offset != scrollOffset())
- frame()->eventHandler()->sendScrollEvent();
+ scrollPositionChanged();
+ frame()->loader()->client()->didChangeScrollOffset();
+}
+
+void FrameView::valueChanged(const IntSize& scrollDelta)
+{
+ ScrollView::valueChanged(scrollDelta);
+ frame()->eventHandler()->sendScrollEvent();
frame()->loader()->client()->didChangeScrollOffset();
}
void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
{
- tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch);
+ tickmarks = frame()->document()->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch);
}
IntRect FrameView::windowResizerRect() const
if (!frame())
return;
-#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent())
- timelineAgent->willPaint(rect);
-#endif
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_frame.get(), rect);
Document* document = frame()->document();
fillWithRed = true;
if (fillWithRed)
- p->fillRect(rect, Color(0xFF, 0, 0), DeviceColorSpace);
+ p->fillRect(rect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
#endif
bool isTopLevelPainter = !sCurrentPaintTimeStamp;
RenderView* contentRenderer = frame()->contentRenderer();
if (!contentRenderer) {
- LOG_ERROR("called Frame::paint with nil renderer");
+ LOG_ERROR("called FrameView::paint with nil renderer");
return;
}
PaintBehavior oldPaintBehavior = m_paintBehavior;
if (m_paintBehavior == PaintBehaviorNormal)
- document->invalidateRenderedRectsForMarkersInRect(rect);
+ document->markers()->invalidateRenderedRectsForMarkersInRect(rect);
if (document->printing())
m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
if (isTopLevelPainter)
sCurrentPaintTimeStamp = 0;
-#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent())
- timelineAgent->didPaint();
-#endif
+ InspectorInstrumentation::didPaint(cookie);
}
void FrameView::setPaintBehavior(PaintBehavior behavior)
m_nodeToDraw = node;
}
-void FrameView::layoutIfNeededRecursive()
+void FrameView::updateLayoutAndStyleIfNeededRecursive()
{
// We have to crawl our entire tree looking for any FrameViews that need
// layout and make sure they are up to date.
// region but then become included later by the second frame adding rects to the dirty region
// when it lays out.
+ m_frame->document()->updateStyleIfNeeded();
+
if (needsLayout())
layout();
for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
Widget* widget = (*current).get();
if (widget->isFrameView())
- static_cast<FrameView*>(widget)->layoutIfNeededRecursive();
+ static_cast<FrameView*>(widget)->updateLayoutAndStyleIfNeededRecursive();
}
- // layoutIfNeededRecursive is called when we need to make sure layout is up-to-date before
+ // updateLayoutAndStyleIfNeededRecursive is called when we need to make sure style and layout are up-to-date before
// painting, so we need to flush out any deferred repaints too.
flushDeferredRepaints();
}
void FrameView::forceLayout(bool allowSubtree)
{
layout(allowSubtree);
- // We cannot unschedule a pending relayout, since the force can be called with
- // a tiny rectangle from a drawRect update. By unscheduling we in effect
- // "validate" and stop the necessary full repaint from occurring. Basically any basic
- // append/remove DHTML is broken by this call. For now, I have removed the optimization
- // until we have a better invalidation stategy. -dwh
- //unscheduleRelayout();
}
-void FrameView::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool _adjustViewSize)
+void FrameView::forceLayoutForPagination(const FloatSize& pageSize, float maximumShrinkFactor, Frame::AdjustViewSizeOrNot shouldAdjustViewSize)
{
// Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
// the state of things before and after the layout
RenderView *root = toRenderView(m_frame->document()->renderer());
if (root) {
- // This magic is basically copied from khtmlview::print
- int pageW = (int)ceilf(minPageWidth);
+ int pageW = ceilf(pageSize.width());
root->setWidth(pageW);
+ root->setPageHeight(pageSize.height());
root->setNeedsLayoutAndPrefWidthsRecalc();
forceLayout();
- // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
- // maximum page width, we will lay out to the maximum page width and clip extra content.
+ // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
+ // page width when shrunk, we will lay out at maximum shrink and clip extra content.
// FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
// implementation should not do this!
int rightmostPos = root->rightmostPosition();
- if (rightmostPos > minPageWidth) {
- pageW = std::min(rightmostPos, (int)ceilf(maxPageWidth));
+ if (rightmostPos > pageSize.width()) {
+ pageW = std::min<int>(rightmostPos, ceilf(pageSize.width() * maximumShrinkFactor));
+ if (pageSize.height())
+ root->setPageHeight(pageW / pageSize.width() * pageSize.height());
root->setWidth(pageW);
root->setNeedsLayoutAndPrefWidthsRecalc();
forceLayout();
+ int docHeight = root->bottomLayoutOverflow();
+ root->clearLayoutOverflow();
+ root->addLayoutOverflow(IntRect(0, 0, pageW, docHeight)); // This is how we clip in case we overflow again.
}
}
- if (_adjustViewSize)
+ if (shouldAdjustViewSize)
adjustViewSize();
}
-void FrameView::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/)
+void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/)
{
RenderView* root = m_frame->contentRenderer();
if (root) {
GraphicsContext context((PlatformGraphicsContext*)0);
root->setTruncatedAt((int)floorf(oldBottom));
IntRect dirtyRect(0, (int)floorf(oldTop), root->rightLayoutOverflow(), (int)ceilf(oldBottom - oldTop));
+ root->setPrintRect(dirtyRect);
root->layer()->paint(&context, dirtyRect);
*newBottom = root->bestTruncatedAt();
if (*newBottom == 0)
*newBottom = oldBottom;
+ root->setPrintRect(IntRect());
} else
*newBottom = oldBottom;
}
return parentPoint;
}
+// Normal delay
+void FrameView::setRepaintThrottlingDeferredRepaintDelay(double p)
+{
+ s_deferredRepaintDelay = p;
+}
+
+// Negative value would mean that first few repaints happen without a delay
+void FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(double p)
+{
+ s_initialDeferredRepaintDelayDuringLoading = p;
+}
+
+// The delay grows on each repaint to this maximum value
+void FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(double p)
+{
+ s_maxDeferredRepaintDelayDuringLoading = p;
+}
+
+// On each repaint the delay increases by this amount
+void FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(double p)
+{
+ s_deferredRepaintDelayIncrementDuringLoading = p;
+}
+
} // namespace WebCore