mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This removes the bulk of core/editing/*. The following files remain, because they might be useful yet: EditingBoundary.h FindOptions.h htmlediting.cpp htmlediting.h PlainTextRange.cpp PlainTextRange.h PositionWithAffinity.cpp PositionWithAffinity.h RenderedPosition.cpp RenderedPosition.h TextAffinity.h TextGranularity.h TextIterator.cpp TextIterator.h VisiblePosition.cpp VisiblePosition.h VisibleSelection.cpp VisibleSelection.h VisibleUnits.cpp VisibleUnits.h In addition to remove obviously editing-related stuff like "ApplyBlockElementCommand.cpp" and "InsertLineBreakCommand.cpp", this also removes the DOM side of selection, all the caret management and painting code, composition support (IME) including the relevant events, spelling checker support, and the undo stack. Outside the core/editing/* directory, I also deleted the EditorClient, SpellCheckerClient, and EmptyClients classes. The other changes outside of editing/ are mostly just about removing mentions of the selection or carets. I tried to leave the code for _painting_ selections and composition runs, though that code is mostly disconnected now.
739 lines
21 KiB
C++
739 lines
21 KiB
C++
/*
|
|
* Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
|
|
* 1999 Lars Knoll <knoll@kde.org>
|
|
* 1999 Antti Koivisto <koivisto@kde.org>
|
|
* 2000 Dirk Mueller <mueller@kde.org>
|
|
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
|
|
* (C) 2006 Graham Dennis (graham.dennis@gmail.com)
|
|
* (C) 2006 Alexey Proskuryakov (ap@nypop.com)
|
|
* Copyright (C) 2009 Google Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "sky/engine/core/frame/FrameView.h"
|
|
|
|
#include "gen/sky/platform/RuntimeEnabledFeatures.h"
|
|
#include "sky/engine/core/css/resolver/StyleResolver.h"
|
|
#include "sky/engine/core/dom/DocumentMarkerController.h"
|
|
#include "sky/engine/core/frame/FrameHost.h"
|
|
#include "sky/engine/core/frame/LocalFrame.h"
|
|
#include "sky/engine/core/frame/Settings.h"
|
|
#include "sky/engine/core/loader/FrameLoaderClient.h"
|
|
#include "sky/engine/core/page/ChromeClient.h"
|
|
#include "sky/engine/core/page/FocusController.h"
|
|
#include "sky/engine/core/page/Page.h"
|
|
#include "sky/engine/core/rendering/RenderLayer.h"
|
|
#include "sky/engine/core/rendering/RenderView.h"
|
|
#include "sky/engine/core/rendering/style/RenderStyle.h"
|
|
#include "sky/engine/platform/ScriptForbiddenScope.h"
|
|
#include "sky/engine/platform/TraceEvent.h"
|
|
#include "sky/engine/platform/fonts/FontCache.h"
|
|
#include "sky/engine/platform/geometry/FloatRect.h"
|
|
#include "sky/engine/platform/graphics/GraphicsContext.h"
|
|
#include "sky/engine/platform/text/TextStream.h"
|
|
#include "sky/engine/wtf/CurrentTime.h"
|
|
#include "sky/engine/wtf/TemporaryChange.h"
|
|
|
|
namespace blink {
|
|
|
|
double FrameView::s_currentFrameTimeStamp = 0.0;
|
|
bool FrameView::s_inPaintContents = false;
|
|
|
|
FrameView::FrameView(LocalFrame* frame)
|
|
: m_frame(frame)
|
|
, m_hasPendingLayout(false)
|
|
, m_layoutSubtreeRoot(0)
|
|
, m_inSynchronousPostLayout(false)
|
|
, m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
|
|
, m_isTransparent(false)
|
|
, m_baseBackgroundColor(Color::white)
|
|
, m_mediaType("screen")
|
|
, m_overflowStatusDirty(true)
|
|
, m_viewportRenderer(0)
|
|
, m_hasSoftwareFilters(false)
|
|
, m_visibleContentScaleFactor(1)
|
|
, m_inputEventsScaleFactorForEmulation(1)
|
|
, m_layoutSizeFixedToFrameSize(true)
|
|
{
|
|
ASSERT(m_frame);
|
|
init();
|
|
}
|
|
|
|
PassRefPtr<FrameView> FrameView::create(LocalFrame* frame)
|
|
{
|
|
RefPtr<FrameView> view = adoptRef(new FrameView(frame));
|
|
return view.release();
|
|
}
|
|
|
|
PassRefPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
|
|
{
|
|
RefPtr<FrameView> view = adoptRef(new FrameView(frame));
|
|
view->Widget::setFrameRect(IntRect(view->location(), initialSize));
|
|
view->setLayoutSizeInternal(initialSize);
|
|
return view.release();
|
|
}
|
|
|
|
FrameView::~FrameView()
|
|
{
|
|
if (m_postLayoutTasksTimer.isActive())
|
|
m_postLayoutTasksTimer.stop();
|
|
|
|
ASSERT(m_frame);
|
|
ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
|
|
}
|
|
|
|
void FrameView::reset()
|
|
{
|
|
m_hasPendingLayout = false;
|
|
m_layoutSubtreeRoot = 0;
|
|
m_layoutSchedulingEnabled = true;
|
|
m_inPerformLayout = false;
|
|
m_inSynchronousPostLayout = false;
|
|
m_layoutCount = 0;
|
|
m_nestedLayoutCount = 0;
|
|
m_postLayoutTasksTimer.stop();
|
|
m_firstLayout = true;
|
|
m_firstLayoutCallbackPending = false;
|
|
m_lastViewportSize = IntSize();
|
|
m_lastPaintTime = 0;
|
|
m_isPainting = false;
|
|
}
|
|
|
|
void FrameView::init()
|
|
{
|
|
reset();
|
|
|
|
m_size = LayoutSize();
|
|
}
|
|
|
|
void FrameView::prepareForDetach()
|
|
{
|
|
// FIXME(sky): Remove
|
|
}
|
|
|
|
void FrameView::clear()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
bool FrameView::didFirstLayout() const
|
|
{
|
|
return !m_firstLayout;
|
|
}
|
|
|
|
void FrameView::setFrameRect(const IntRect& newRect)
|
|
{
|
|
IntRect oldRect = frameRect();
|
|
if (newRect == oldRect)
|
|
return;
|
|
|
|
Widget::setFrameRect(newRect);
|
|
}
|
|
|
|
Page* FrameView::page() const
|
|
{
|
|
return frame().page();
|
|
}
|
|
|
|
RenderView* FrameView::renderView() const
|
|
{
|
|
return frame().contentRenderer();
|
|
}
|
|
|
|
IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const
|
|
{
|
|
FloatSize scaledSize = unscaledVisibleContentSize();
|
|
if (scale)
|
|
scaledSize.scale(1 / scale);
|
|
|
|
IntPoint clampedOffset = offset;
|
|
clampedOffset = clampedOffset.shrunkTo(
|
|
IntPoint(size()) - expandedIntSize(scaledSize));
|
|
return clampedOffset;
|
|
}
|
|
|
|
void FrameView::recalcOverflowAfterStyleChange()
|
|
{
|
|
RenderView* renderView = this->renderView();
|
|
RELEASE_ASSERT(renderView);
|
|
if (!renderView->needsOverflowRecalcAfterStyleChange())
|
|
return;
|
|
|
|
renderView->recalcOverflowAfterStyleChange();
|
|
}
|
|
|
|
RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
|
|
{
|
|
return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
|
|
}
|
|
|
|
void FrameView::performPreLayoutTasks()
|
|
{
|
|
TRACE_EVENT0("blink", "FrameView::performPreLayoutTasks");
|
|
|
|
// Don't schedule more layouts, we're in one.
|
|
TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
|
|
|
|
if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
|
|
// This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
|
|
m_inSynchronousPostLayout = true;
|
|
performPostLayoutTasks();
|
|
m_inSynchronousPostLayout = false;
|
|
}
|
|
|
|
Document* document = m_frame->document();
|
|
if (wasViewportResized()) {
|
|
document->notifyResizeForViewportUnits();
|
|
document->mediaQueryAffectingValueChanged();
|
|
|
|
// TODO(esprehn): This is way too much work, it rebuilds the entire sheet list
|
|
// and does a full document recalc.
|
|
document->styleResolverChanged();
|
|
}
|
|
|
|
document->updateRenderTreeIfNeeded();
|
|
}
|
|
|
|
void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
|
|
{
|
|
TRACE_EVENT0("blink", "FrameView::performLayout");
|
|
|
|
ScriptForbiddenScope forbidScript;
|
|
|
|
ASSERT(!isInPerformLayout());
|
|
|
|
TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
|
|
|
|
// performLayout is the actual guts of layout().
|
|
// FIXME: The 300 other lines in layout() probably belong in other helper functions
|
|
// so that a single human could understand what layout() is actually doing.
|
|
rootForThisLayout->layout();
|
|
}
|
|
|
|
void FrameView::scheduleOrPerformPostLayoutTasks()
|
|
{
|
|
if (m_postLayoutTasksTimer.isActive())
|
|
return;
|
|
|
|
if (!m_inSynchronousPostLayout) {
|
|
m_inSynchronousPostLayout = true;
|
|
// Calls resumeScheduledEvents()
|
|
performPostLayoutTasks();
|
|
m_inSynchronousPostLayout = false;
|
|
}
|
|
|
|
if (!m_postLayoutTasksTimer.isActive() && (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_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
|
|
if (needsLayout())
|
|
layout();
|
|
}
|
|
}
|
|
|
|
void FrameView::layout(bool allowSubtree)
|
|
{
|
|
// We should never layout a Document which is not in a LocalFrame.
|
|
ASSERT(m_frame);
|
|
ASSERT(m_frame->view() == this);
|
|
|
|
ScriptForbiddenScope forbidScript;
|
|
|
|
if (isInPerformLayout() || !m_frame->document()->isActive())
|
|
return;
|
|
|
|
TRACE_EVENT0("blink", "FrameView::layout");
|
|
TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout");
|
|
|
|
// Protect the view from being deleted during layout (in recalcStyle)
|
|
RefPtr<FrameView> protector(this);
|
|
|
|
m_hasPendingLayout = false;
|
|
|
|
RELEASE_ASSERT(!isPainting());
|
|
|
|
if (!allowSubtree && isSubtreeLayout()) {
|
|
m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
|
|
m_layoutSubtreeRoot = 0;
|
|
}
|
|
|
|
performPreLayoutTasks();
|
|
|
|
// If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
|
|
// so there's no point to continuing to layout
|
|
if (protector->hasOneRef())
|
|
return;
|
|
|
|
Document* document = m_frame->document();
|
|
bool inSubtreeLayout = isSubtreeLayout();
|
|
RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView();
|
|
if (!rootForThisLayout) {
|
|
// FIXME: Do we need to set m_size here?
|
|
ASSERT_NOT_REACHED();
|
|
return;
|
|
}
|
|
|
|
FontCachePurgePreventer fontCachePurgePreventer;
|
|
RenderLayer* layer;
|
|
{
|
|
TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
|
|
|
|
m_nestedLayoutCount++;
|
|
|
|
if (!inSubtreeLayout) {
|
|
if (m_firstLayout) {
|
|
m_firstLayout = false;
|
|
m_firstLayoutCallbackPending = true;
|
|
m_lastViewportSize = layoutSize();
|
|
}
|
|
|
|
m_size = LayoutSize(layoutSize());
|
|
}
|
|
|
|
layer = rootForThisLayout->enclosingLayer();
|
|
|
|
performLayout(rootForThisLayout, inSubtreeLayout);
|
|
|
|
m_layoutSubtreeRoot = 0;
|
|
} // Reset m_layoutSchedulingEnabled to its previous value.
|
|
|
|
layer->updateLayerPositionsAfterLayout();
|
|
|
|
m_layoutCount++;
|
|
|
|
ASSERT(!rootForThisLayout->needsLayout());
|
|
|
|
scheduleOrPerformPostLayoutTasks();
|
|
|
|
m_nestedLayoutCount--;
|
|
if (m_nestedLayoutCount)
|
|
return;
|
|
|
|
#if ENABLE(ASSERT)
|
|
// Post-layout assert that nobody was re-marked as needing layout during layout.
|
|
document->renderView()->assertSubtreeIsLaidOut();
|
|
#endif
|
|
}
|
|
|
|
void FrameView::setMediaType(const AtomicString& mediaType)
|
|
{
|
|
ASSERT(m_frame->document());
|
|
m_frame->document()->mediaQueryAffectingValueChanged();
|
|
m_mediaType = mediaType;
|
|
}
|
|
|
|
AtomicString FrameView::mediaType() const
|
|
{
|
|
// See if we have an override type.
|
|
String overrideType;
|
|
if (!overrideType.isNull())
|
|
return AtomicString(overrideType);
|
|
return m_mediaType;
|
|
}
|
|
|
|
// FIXME(sky): remove
|
|
IntSize FrameView::layoutSize() const
|
|
{
|
|
return m_layoutSize;
|
|
}
|
|
|
|
void FrameView::setLayoutSize(const IntSize& size)
|
|
{
|
|
ASSERT(!layoutSizeFixedToFrameSize());
|
|
|
|
setLayoutSizeInternal(size);
|
|
}
|
|
|
|
HostWindow* FrameView::hostWindow() const
|
|
{
|
|
return frame().page();
|
|
}
|
|
|
|
void FrameView::contentsResized()
|
|
{
|
|
setNeedsLayout();
|
|
}
|
|
|
|
void FrameView::scheduleRelayout()
|
|
{
|
|
ASSERT(m_frame->view() == this);
|
|
|
|
if (isSubtreeLayout()) {
|
|
m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
|
|
m_layoutSubtreeRoot = 0;
|
|
}
|
|
if (!m_layoutSchedulingEnabled)
|
|
return;
|
|
if (!needsLayout())
|
|
return;
|
|
if (!m_frame->document()->isActive())
|
|
return;
|
|
|
|
if (m_hasPendingLayout)
|
|
return;
|
|
m_hasPendingLayout = true;
|
|
|
|
m_frame->document()->scheduleVisualUpdate();
|
|
}
|
|
|
|
static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
|
|
{
|
|
for (RenderObject* r = descendant; r; r = r->container()) {
|
|
if (r == ancestor)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
|
|
{
|
|
ASSERT(m_frame->view() == this);
|
|
|
|
if (!m_frame->document()->isActive())
|
|
return;
|
|
|
|
RenderView* renderView = this->renderView();
|
|
if (renderView && renderView->needsLayout()) {
|
|
if (relayoutRoot)
|
|
relayoutRoot->markContainingBlocksForLayout(false);
|
|
return;
|
|
}
|
|
|
|
if (layoutPending() || !m_layoutSchedulingEnabled) {
|
|
if (m_layoutSubtreeRoot != relayoutRoot) {
|
|
if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
|
|
// Keep the current root
|
|
relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
|
|
ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
|
|
} else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
|
|
// Re-root at relayoutRoot
|
|
m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
|
|
m_layoutSubtreeRoot = relayoutRoot;
|
|
ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
|
|
} else {
|
|
// Just do a full relayout
|
|
if (isSubtreeLayout())
|
|
m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
|
|
m_layoutSubtreeRoot = 0;
|
|
relayoutRoot->markContainingBlocksForLayout(false);
|
|
}
|
|
}
|
|
} else if (m_layoutSchedulingEnabled) {
|
|
m_layoutSubtreeRoot = relayoutRoot;
|
|
ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
|
|
m_hasPendingLayout = true;
|
|
|
|
m_frame->document()->scheduleVisualUpdate();
|
|
}
|
|
}
|
|
|
|
bool FrameView::layoutPending() const
|
|
{
|
|
// FIXME: This should check Document::lifecycle instead.
|
|
return m_hasPendingLayout;
|
|
}
|
|
|
|
bool FrameView::isInPerformLayout() const
|
|
{
|
|
return m_inPerformLayout;
|
|
}
|
|
|
|
bool FrameView::needsLayout() const
|
|
{
|
|
RenderView* renderView = this->renderView();
|
|
return layoutPending()
|
|
|| (renderView && renderView->needsLayout())
|
|
|| isSubtreeLayout();
|
|
}
|
|
|
|
void FrameView::setNeedsLayout()
|
|
{
|
|
if (RenderView* renderView = this->renderView())
|
|
renderView->setNeedsLayout();
|
|
}
|
|
|
|
bool FrameView::isTransparent() const
|
|
{
|
|
return m_isTransparent;
|
|
}
|
|
|
|
void FrameView::setTransparent(bool isTransparent)
|
|
{
|
|
m_isTransparent = isTransparent;
|
|
}
|
|
|
|
Color FrameView::baseBackgroundColor() const
|
|
{
|
|
return m_baseBackgroundColor;
|
|
}
|
|
|
|
void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
|
|
{
|
|
m_baseBackgroundColor = backgroundColor;
|
|
}
|
|
|
|
void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
|
|
{
|
|
// FIXME(sky): simplify
|
|
setTransparent(transparent);
|
|
setBaseBackgroundColor(backgroundColor);
|
|
}
|
|
|
|
void FrameView::flushAnyPendingPostLayoutTasks()
|
|
{
|
|
ASSERT(!isInPerformLayout());
|
|
if (m_postLayoutTasksTimer.isActive())
|
|
performPostLayoutTasks();
|
|
}
|
|
|
|
void FrameView::performPostLayoutTasks()
|
|
{
|
|
// FIXME: We can reach here, even when the page is not active!
|
|
// http/tests/inspector/elements/html-link-import.html and many other
|
|
// tests hit that case.
|
|
// We should ASSERT(isActive()); or at least return early if we can!
|
|
ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
|
|
TRACE_EVENT0("blink", "FrameView::performPostLayoutTasks");
|
|
RefPtr<FrameView> protect(this);
|
|
|
|
m_postLayoutTasksTimer.stop();
|
|
|
|
ASSERT(m_frame->document());
|
|
if (m_nestedLayoutCount <= 1) {
|
|
if (m_firstLayoutCallbackPending)
|
|
m_firstLayoutCallbackPending = false;
|
|
}
|
|
|
|
sendResizeEventIfNeeded();
|
|
}
|
|
|
|
bool FrameView::wasViewportResized()
|
|
{
|
|
return layoutSize() != m_lastViewportSize;
|
|
}
|
|
|
|
void FrameView::sendResizeEventIfNeeded()
|
|
{
|
|
}
|
|
|
|
void FrameView::postLayoutTimerFired(Timer<FrameView>*)
|
|
{
|
|
performPostLayoutTasks();
|
|
}
|
|
|
|
IntRect FrameView::windowClipRect() const
|
|
{
|
|
ASSERT(m_frame->view() == this);
|
|
|
|
if (paintsEntireContents())
|
|
return IntRect(IntPoint(), size());
|
|
|
|
// Set our clip rect to be our contents.
|
|
IntRect clipRect = contentsToWindow(visibleContentRect());
|
|
return clipRect;
|
|
}
|
|
|
|
bool FrameView::isActive() const
|
|
{
|
|
Page* page = frame().page();
|
|
return page && page->focusController().isActive();
|
|
}
|
|
|
|
void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
|
|
{
|
|
if (m_visibleContentScaleFactor == visibleContentScaleFactor)
|
|
return;
|
|
m_visibleContentScaleFactor = visibleContentScaleFactor;
|
|
}
|
|
|
|
void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
|
|
{
|
|
m_inputEventsOffsetForEmulation = offset;
|
|
m_inputEventsScaleFactorForEmulation = contentScaleFactor;
|
|
}
|
|
|
|
IntSize FrameView::inputEventsOffsetForEmulation() const
|
|
{
|
|
return m_inputEventsOffsetForEmulation;
|
|
}
|
|
|
|
float FrameView::inputEventsScaleFactor() const
|
|
{
|
|
float pageScale = visibleContentScaleFactor();
|
|
return pageScale * m_inputEventsScaleFactorForEmulation;
|
|
}
|
|
|
|
void FrameView::paint(GraphicsContext* context, const IntRect& rect)
|
|
{
|
|
#ifndef NDEBUG
|
|
bool fillWithRed;
|
|
if (isTransparent())
|
|
fillWithRed = false; // Transparent, don't fill with red.
|
|
else
|
|
fillWithRed = true;
|
|
|
|
if (fillWithRed)
|
|
context->fillRect(rect, Color(0xFF, 0, 0));
|
|
#endif
|
|
|
|
RenderView* renderView = this->renderView();
|
|
if (!renderView) {
|
|
WTF_LOG_ERROR("called FrameView::paint with nil renderer");
|
|
return;
|
|
}
|
|
|
|
RELEASE_ASSERT(!needsLayout());
|
|
|
|
bool isTopLevelPainter = !s_inPaintContents;
|
|
s_inPaintContents = true;
|
|
|
|
FontCachePurgePreventer fontCachePurgePreventer;
|
|
|
|
ASSERT(!m_isPainting);
|
|
m_isPainting = true;
|
|
|
|
#if ENABLE(ASSERT)
|
|
renderView->assertSubtreeIsLaidOut();
|
|
RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*renderView);
|
|
#endif
|
|
|
|
LayerPaintingInfo paintingInfo(renderView->layer(),
|
|
pixelSnappedIntRect(renderView->viewRect()), LayoutSize());
|
|
renderView->paintLayer(context, paintingInfo);
|
|
|
|
m_isPainting = false;
|
|
m_lastPaintTime = currentTime();
|
|
|
|
if (isTopLevelPainter) {
|
|
// Everything that happens after paintContents completions is considered
|
|
// to be part of the next frame.
|
|
s_currentFrameTimeStamp = currentTime();
|
|
s_inPaintContents = false;
|
|
}
|
|
}
|
|
|
|
bool FrameView::isPainting() const
|
|
{
|
|
return m_isPainting;
|
|
}
|
|
|
|
void FrameView::updateLayoutAndStyleForPainting()
|
|
{
|
|
// Updating layout can run script, which can tear down the FrameView.
|
|
RefPtr<FrameView> protector(this);
|
|
|
|
updateLayoutAndStyleIfNeededRecursive();
|
|
}
|
|
|
|
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.
|
|
// Mac actually tests for intersection with the dirty region and tries not to
|
|
// update layout for frames that are outside the dirty region. Not only does this seem
|
|
// pointless (since those frames will have set a zero timer to layout anyway), but
|
|
// it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
|
|
// region but then become included later by the second frame adding rects to the dirty region
|
|
// when it lays out.
|
|
|
|
m_frame->document()->updateRenderTreeIfNeeded();
|
|
|
|
if (needsLayout())
|
|
layout();
|
|
|
|
// These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
|
|
ASSERT(!needsLayout());
|
|
|
|
#if ENABLE(ASSERT)
|
|
m_frame->document()->renderView()->assertRendererLaidOut();
|
|
#endif
|
|
|
|
}
|
|
|
|
void FrameView::forceLayout(bool allowSubtree)
|
|
{
|
|
layout(allowSubtree);
|
|
}
|
|
|
|
IntRect FrameView::convertFromRenderer(const RenderObject& renderer, const IntRect& rendererRect) const
|
|
{
|
|
return pixelSnappedIntRect(enclosingLayoutRect(renderer.localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
|
|
}
|
|
|
|
IntRect FrameView::convertToRenderer(const RenderObject& renderer, const IntRect& viewRect) const
|
|
{
|
|
IntRect rect = viewRect;
|
|
// FIXME: we don't have a way to map an absolute rect down to a local quad, so just
|
|
// move the rect for now.
|
|
rect.setLocation(roundedIntPoint(renderer.absoluteToLocal(rect.location(), UseTransforms)));
|
|
return rect;
|
|
}
|
|
|
|
IntPoint FrameView::convertFromRenderer(const RenderObject& renderer, const IntPoint& rendererPoint) const
|
|
{
|
|
return roundedIntPoint(renderer.localToAbsolute(rendererPoint, UseTransforms));
|
|
}
|
|
|
|
IntPoint FrameView::convertToRenderer(const RenderObject& renderer, const IntPoint& viewPoint) const
|
|
{
|
|
return roundedIntPoint(renderer.absoluteToLocal(viewPoint, UseTransforms));
|
|
}
|
|
|
|
bool FrameView::isVerticalDocument() const
|
|
{
|
|
// FIXME(sky): Remove
|
|
return true;
|
|
}
|
|
|
|
bool FrameView::isFlippedDocument() const
|
|
{
|
|
// FIXME(sky): Remove
|
|
return false;
|
|
}
|
|
|
|
void FrameView::setLayoutSizeInternal(const IntSize& size)
|
|
{
|
|
if (m_layoutSize == size)
|
|
return;
|
|
|
|
m_layoutSize = size;
|
|
contentsResized();
|
|
}
|
|
|
|
void FrameView::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial)
|
|
{
|
|
RenderObject* root = layoutRoot();
|
|
isPartial = true;
|
|
if (!root) {
|
|
isPartial = false;
|
|
root = m_frame->contentRenderer();
|
|
}
|
|
|
|
needsLayoutObjects = 0;
|
|
totalObjects = 0;
|
|
|
|
for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
|
|
++totalObjects;
|
|
if (o->needsLayout())
|
|
++needsLayoutObjects;
|
|
}
|
|
}
|
|
|
|
} // namespace blink
|