| /** |
| * This file is part of the HTML widget for KDE. |
| * |
| * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| * Copyright (C) 2000 Dirk Mueller (mueller@kde.org) |
| * Copyright (C) 2004, 2006 Apple Computer, Inc. |
| * |
| * 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 "config.h" |
| #include "RenderWidget.h" |
| |
| #include "AXObjectCache.h" |
| #include "Document.h" |
| #include "Element.h" |
| #include "Event.h" |
| #include "EventNames.h" |
| #include "FrameView.h" |
| #include "GraphicsContext.h" |
| #include "RenderLayer.h" |
| #include "RenderView.h" |
| |
| using namespace std; |
| |
| namespace WebCore { |
| |
| using namespace EventNames; |
| |
| static HashMap<const Widget*, RenderWidget*>& widgetRendererMap() |
| { |
| static HashMap<const Widget*, RenderWidget*>* staticWidgetRendererMap = new HashMap<const Widget*, RenderWidget*>; |
| return *staticWidgetRendererMap; |
| } |
| |
| RenderWidget::RenderWidget(Node* node) |
| : RenderReplaced(node) |
| , m_widget(0) |
| , m_refCount(0) |
| { |
| // a replaced element doesn't support being anonymous |
| ASSERT(node); |
| m_view = node->document()->view(); |
| |
| view()->addWidget(this); |
| |
| // Reference counting is used to prevent the widget from being |
| // destroyed while inside the Widget code, which might not be |
| // able to handle that. |
| ref(); |
| } |
| |
| void RenderWidget::destroy() |
| { |
| // We can't call the base class's destroy because we don't |
| // want to unconditionally delete ourselves (we're ref-counted). |
| // So the code below includes copied and pasted contents of |
| // both RenderBox::destroy() and RenderObject::destroy(). |
| // Fix originally made for <rdar://problem/4228818>. |
| |
| if (RenderView* v = view()) |
| v->removeWidget(this); |
| |
| document()->axObjectCache()->remove(this); |
| |
| remove(); |
| |
| if (m_widget) { |
| if (m_view) |
| m_view->removeChild(m_widget); |
| widgetRendererMap().remove(m_widget); |
| } |
| |
| // removes from override size map |
| if (hasOverrideSize()) |
| setOverrideSize(-1); |
| |
| RenderLayer* layer = m_layer; |
| RenderArena* arena = renderArena(); |
| |
| if (layer) |
| layer->clearClipRect(); |
| |
| setNode(0); |
| deref(arena); |
| |
| if (layer) |
| layer->destroy(arena); |
| } |
| |
| RenderWidget::~RenderWidget() |
| { |
| ASSERT(m_refCount <= 0); |
| deleteWidget(); |
| } |
| |
| void RenderWidget::resizeWidget(Widget* widget, int w, int h) |
| { |
| if (element() && (widget->width() != w || widget->height() != h)) { |
| RenderArena* arena = ref(); |
| element()->ref(); |
| widget->resize(w, h); |
| element()->deref(); |
| deref(arena); |
| } |
| } |
| |
| void RenderWidget::setWidget(Widget* widget) |
| { |
| if (widget != m_widget) { |
| if (m_widget) { |
| widgetRendererMap().remove(m_widget); |
| deleteWidget(); |
| } |
| m_widget = widget; |
| if (m_widget) { |
| widgetRendererMap().add(m_widget, this); |
| // if we've already received a layout, apply the calculated space to the |
| // widget immediately, but we have to have really been full constructed (with a non-null |
| // style pointer). |
| if (!needsLayout() && style()) |
| resizeWidget(m_widget, |
| m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(), |
| m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom()); |
| if (style()) { |
| if (style()->visibility() != VISIBLE) |
| m_widget->hide(); |
| else |
| m_widget->show(); |
| } |
| m_view->addChild(m_widget); |
| } |
| } |
| } |
| |
| void RenderWidget::layout() |
| { |
| ASSERT(needsLayout()); |
| |
| setNeedsLayout(false); |
| } |
| |
| void RenderWidget::setStyle(RenderStyle* newStyle) |
| { |
| RenderReplaced::setStyle(newStyle); |
| if (m_widget) { |
| if (style()->visibility() != VISIBLE) |
| m_widget->hide(); |
| else |
| m_widget->show(); |
| } |
| } |
| |
| void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) |
| { |
| if (!shouldPaint(paintInfo, tx, ty)) |
| return; |
| |
| tx += m_x; |
| ty += m_y; |
| |
| if (hasBoxDecorations() && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline) |
| paintBoxDecorations(paintInfo, tx, ty); |
| |
| if (!m_view || paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE) |
| return; |
| |
| #if PLATFORM(MAC) |
| if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) |
| paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true); |
| #endif |
| |
| if (m_widget) { |
| // Move the widget if necessary. We normally move and resize widgets during layout, but sometimes |
| // widgets can move without layout occurring (most notably when you scroll a document that |
| // contains fixed positioned elements). |
| m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop()); |
| |
| // Tell the widget to paint now. This is the only time the widget is allowed |
| // to paint itself. That way it will composite properly with z-indexed layers. |
| m_widget->paint(paintInfo.context, paintInfo.rect); |
| } |
| |
| // Paint a partially transparent wash over selected widgets. |
| if (isSelected() && !document()->printing()) |
| paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor()); |
| } |
| |
| void RenderWidget::deref(RenderArena *arena) |
| { |
| if (--m_refCount <= 0) |
| arenaDelete(arena, this); |
| } |
| |
| void RenderWidget::updateWidgetPosition() |
| { |
| if (!m_widget) |
| return; |
| |
| int x; |
| int y; |
| absolutePosition(x, y); |
| x += borderLeft() + paddingLeft(); |
| y += borderTop() + paddingTop(); |
| |
| int width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); |
| int height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); |
| |
| IntRect newBounds(x, y, width, height); |
| IntRect oldBounds(m_widget->frameGeometry()); |
| if (newBounds != oldBounds) { |
| // The widget changed positions. Update the frame geometry. |
| if (checkForRepaintDuringLayout()) { |
| RenderView* v = view(); |
| if (!v->printing()) { |
| v->repaintViewRectangle(oldBounds); |
| v->repaintViewRectangle(newBounds); |
| } |
| } |
| |
| RenderArena* arena = ref(); |
| element()->ref(); |
| m_widget->setFrameGeometry(newBounds); |
| element()->deref(); |
| deref(arena); |
| } |
| } |
| |
| void RenderWidget::setSelectionState(SelectionState state) |
| { |
| if (selectionState() != state) { |
| RenderReplaced::setSelectionState(state); |
| if (m_widget) |
| m_widget->setIsSelected(isSelected()); |
| } |
| } |
| |
| void RenderWidget::deleteWidget() |
| { |
| delete m_widget; |
| } |
| |
| RenderWidget* RenderWidget::find(const Widget* widget) |
| { |
| return widgetRendererMap().get(widget); |
| } |
| |
| } // namespace WebCore |