From ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- khtml/rendering/render_replaced.cpp | 939 ++++++++++++++++++++++++++++++++++++ 1 file changed, 939 insertions(+) create mode 100644 khtml/rendering/render_replaced.cpp (limited to 'khtml/rendering/render_replaced.cpp') diff --git a/khtml/rendering/render_replaced.cpp b/khtml/rendering/render_replaced.cpp new file mode 100644 index 000000000..a74338e29 --- /dev/null +++ b/khtml/rendering/render_replaced.cpp @@ -0,0 +1,939 @@ +/** + * This file is part of the HTML widget for KDE. + * + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2000-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * Copyright (C) 2004 Germain Garand (germain@ebooksfrance.org) + * + * 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 "render_replaced.h" +#include "render_layer.h" +#include "render_canvas.h" +#include "render_line.h" + +#include "render_arena.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "khtml_ext.h" +#include "khtmlview.h" +#include "xml/dom2_eventsimpl.h" +#include "khtml_part.h" +#include "xml/dom_docimpl.h" +#include + +bool khtml::allowWidgetPaintEvents = false; + +using namespace khtml; +using namespace DOM; + + +RenderReplaced::RenderReplaced(DOM::NodeImpl* node) + : RenderBox(node) +{ + // init RenderObject attributes + setReplaced(true); + + m_intrinsicWidth = 300; + m_intrinsicHeight = 150; +} + +void RenderReplaced::calcMinMaxWidth() +{ + KHTMLAssert( !minMaxKnown()); + +#ifdef DEBUG_LAYOUT + kdDebug( 6040 ) << "RenderReplaced::calcMinMaxWidth() known=" << minMaxKnown() << endl; +#endif + + m_width = calcReplacedWidth(); + m_width = calcBoxWidth( m_width ); + + if ( style()->width().isPercent() || style()->height().isPercent() || + style()->maxWidth().isPercent() || style()->maxHeight().isPercent() || + style()->minWidth().isPercent() || style()->minHeight().isPercent() ) { + m_minWidth = 0; + m_maxWidth = m_width; + } + else + m_minWidth = m_maxWidth = m_width; + + setMinMaxKnown(); +} + +void RenderReplaced::position(InlineBox* box, int /*from*/, int /*len*/, bool /*reverse*/) +{ + setPos( box->xPos(), box->yPos() ); +} + +// ----------------------------------------------------------------------------- + +RenderWidget::RenderWidget(DOM::NodeImpl* node) + : RenderReplaced(node) +{ + m_widget = 0; + // a widget doesn't support being anonymous + assert(!isAnonymous()); + m_view = node->getDocument()->view(); + m_arena.reset(renderArena()); + m_resizePending = false; + m_discardResizes = false; + m_isKHTMLWidget = false; + m_needsMask = false; + + // this is no real reference counting, its just there + // to make sure that we're not deleted while we're recursed + // in an eventFilter of the widget + ref(); +} + +void RenderWidget::detach() +{ + remove(); + deleteInlineBoxes(); + + if ( m_widget ) { + if ( m_view ) { + m_view->setWidgetVisible(this, false); + m_view->removeChild( m_widget ); + } + + m_widget->removeEventFilter( this ); + m_widget->setMouseTracking( false ); + } + + deref(); +} + +RenderWidget::~RenderWidget() +{ + KHTMLAssert( refCount() <= 0 ); + + if(m_widget) { + m_widget->hide(); + m_widget->deleteLater(); + } +} + +class QWidgetResizeEvent : public QEvent +{ +public: + enum { Type = QEvent::User + 0xbee }; + QWidgetResizeEvent( int _w, int _h ) : + QEvent( ( QEvent::Type ) Type ), w( _w ), h( _h ) {} + int w; + int h; +}; + +void RenderWidget::resizeWidget( int w, int h ) +{ + // ugly hack to limit the maximum size of the widget ( as X11 has problems if + // its bigger ) + h = kMin( h, 3072 ); + w = kMin( w, 2000 ); + + if (m_widget->width() != w || m_widget->height() != h) { + m_resizePending = isKHTMLWidget(); + ref(); + element()->ref(); + QApplication::postEvent( this, new QWidgetResizeEvent( w, h ) ); + element()->deref(); + deref(); + } +} + +void RenderWidget::cancelPendingResize() +{ + if (!m_widget) + return; + m_discardResizes = true; + QApplication::sendPostedEvents(this, QWidgetResizeEvent::Type); + m_discardResizes = false; +} + +bool RenderWidget::event( QEvent *e ) +{ + if ( m_widget && (e->type() == (QEvent::Type)QWidgetResizeEvent::Type) ) { + m_resizePending = false; + if (m_discardResizes) + return true; + QWidgetResizeEvent *re = static_cast(e); + m_widget->resize( re->w, re->h ); + repaint(); + } + // eat all events - except if this is a frame (in which case KHTMLView handles it all) + if ( ::qt_cast( m_widget ) ) + return QObject::event( e ); + return true; +} + +void RenderWidget::flushWidgetResizes() //static +{ + QApplication::sendPostedEvents( 0, QWidgetResizeEvent::Type ); +} + +void RenderWidget::setQWidget(QWidget *widget) +{ + if (widget != m_widget) + { + if (m_widget) { + m_widget->removeEventFilter(this); + disconnect( m_widget, SIGNAL( destroyed()), this, SLOT( slotWidgetDestructed())); + m_widget->hide(); + m_widget->deleteLater(); //Might happen due to event on the widget, so be careful + m_widget = 0; + } + m_widget = widget; + if (m_widget) { + connect( m_widget, SIGNAL( destroyed()), this, SLOT( slotWidgetDestructed())); + m_widget->installEventFilter(this); + + if ( (m_isKHTMLWidget = !strcmp(m_widget->name(), "__khtml")) && !::qt_cast(m_widget)) + m_widget->setBackgroundMode( QWidget::NoBackground ); + + if (m_widget->focusPolicy() > QWidget::StrongFocus) + m_widget->setFocusPolicy(QWidget::StrongFocus); + // 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_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), + m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom() ); + } + else + setPos(xPos(), -500000); + } + m_view->setWidgetVisible(this, false); + m_view->addChild( m_widget, 0, -500000); + if ( m_widget ) m_widget->hide(); + m_resizePending = false; + } +} + +void RenderWidget::layout( ) +{ + KHTMLAssert( needsLayout() ); + KHTMLAssert( minMaxKnown() ); + if ( m_widget ) { + resizeWidget( m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), + m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom() ); + if (!isKHTMLWidget() && !isFrame() && !m_needsMask) { + m_needsMask = true; + RenderLayer* rl = enclosingStackingContext(); + RenderLayer* el = enclosingLayer(); + while (rl && el && el != rl) { + if (el->renderer()->style()->position() != STATIC) { + m_needsMask = false; + break; + } + el = el->parent(); + } + if (m_needsMask) { + if (rl) rl->setHasOverlaidWidgets(); + canvas()->setNeedsWidgetMasks(); + } + } + } + + setNeedsLayout(false); +} + +void RenderWidget::updateFromElement() +{ + if (m_widget) { + // Color: + QColor color = style()->color(); + QColor backgroundColor = style()->backgroundColor(); + + if ( color.isValid() || backgroundColor.isValid() ) { + QPalette pal(QApplication::palette(m_widget)); + + int contrast_ = KGlobalSettings::contrast(); + int highlightVal = 100 + (2*contrast_+4)*16/10; + int lowlightVal = 100 + (2*contrast_+4)*10; + + if (backgroundColor.isValid()) { + if (!isKHTMLWidget()) + widget()->setEraseColor(backgroundColor ); + for ( int i = 0; i < QPalette::NColorGroups; ++i ) { + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Background, backgroundColor ); + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Light, backgroundColor.light(highlightVal) ); + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Dark, backgroundColor.dark(lowlightVal) ); + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Mid, backgroundColor.dark(120) ); + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Midlight, backgroundColor.light(110) ); + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Button, backgroundColor ); + pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Base, backgroundColor ); + } + } + if ( color.isValid() ) { + struct ColorSet { + QPalette::ColorGroup cg; + QColorGroup::ColorRole cr; + }; + const struct ColorSet toSet [] = { + { QPalette::Active, QColorGroup::Foreground }, + { QPalette::Active, QColorGroup::ButtonText }, + { QPalette::Active, QColorGroup::Text }, + { QPalette::Inactive, QColorGroup::Foreground }, + { QPalette::Inactive, QColorGroup::ButtonText }, + { QPalette::Inactive, QColorGroup::Text }, + { QPalette::Disabled,QColorGroup::ButtonText }, + { QPalette::NColorGroups, QColorGroup::NColorRoles }, + }; + const ColorSet *set = toSet; + while( set->cg != QPalette::NColorGroups ) { + pal.setColor( set->cg, set->cr, color ); + ++set; + } + + QColor disfg = color; + int h, s, v; + disfg.hsv( &h, &s, &v ); + if (v > 128) + // dark bg, light fg - need a darker disabled fg + disfg = disfg.dark(lowlightVal); + else if (disfg != Qt::black) + // light bg, dark fg - need a lighter disabled fg - but only if !black + disfg = disfg.light(highlightVal); + else + // black fg - use darkgray disabled fg + disfg = Qt::darkGray; + pal.setColor(QPalette::Disabled,QColorGroup::Foreground,disfg); + } + + m_widget->setPalette(pal); + } + else + m_widget->unsetPalette(); + // Border: + QFrame* frame = ::qt_cast(m_widget); + if (frame) { + if (shouldPaintBackgroundOrBorder()) + { + frame->setFrameShape(QFrame::NoFrame); + } + } + + } + + RenderReplaced::updateFromElement(); +} + +void RenderWidget::slotWidgetDestructed() +{ + if (m_view) + m_view->setWidgetVisible(this, false); + m_widget = 0; +} + +void RenderWidget::setStyle(RenderStyle *_style) +{ + RenderReplaced::setStyle(_style); + if(m_widget) + { + m_widget->setFont(style()->font()); + if (style()->visibility() != VISIBLE) { + if (m_view) + m_view->setWidgetVisible(this, false); + m_widget->hide(); + } + } + + // Don't paint borders if the border-style is native + // or borders are not supported on this widget + if (!canHaveBorder() || + (style()->borderLeftStyle() == BNATIVE && + style()->borderRightStyle() == BNATIVE && + style()->borderTopStyle() == BNATIVE && + style()->borderBottomStyle() == BNATIVE)) + { + setShouldPaintBackgroundOrBorder(false); + } +} + +void RenderWidget::paint(PaintInfo& paintInfo, int _tx, int _ty) +{ + _tx += m_x; + _ty += m_y; + + if (shouldPaintBackgroundOrBorder() && + (paintInfo.phase == PaintActionChildBackground || paintInfo.phase == PaintActionChildBackgrounds)) + paintBoxDecorations(paintInfo, _tx, _ty); + + if (!m_widget || !m_view || paintInfo.phase != PaintActionForeground) + return; + + // not visible or not even once layouted + if (style()->visibility() != VISIBLE || m_y <= -500000 || m_resizePending ) + return; + + if ( (_ty > paintInfo.r.bottom()) || (_ty + m_height <= paintInfo.r.top()) || + (_tx + m_width <= paintInfo.r.left()) || (_tx > paintInfo.r.right()) ) + return; + + int xPos = _tx+borderLeft()+paddingLeft(); + int yPos = _ty+borderTop()+paddingTop(); + + bool khtmlw = isKHTMLWidget(); + int childw = m_widget->width(); + int childh = m_widget->height(); + if ( (childw == 2000 || childh == 3072) && m_widget->inherits( "KHTMLView" ) ) { + KHTMLView *vw = static_cast(m_widget); + int cy = m_view->contentsY(); + int ch = m_view->visibleHeight(); + + + int childx = m_view->childX( m_widget ); + int childy = m_view->childY( m_widget ); + + int xNew = xPos; + int yNew = childy; + + // qDebug("cy=%d, ch=%d, childy=%d, childh=%d", cy, ch, childy, childh ); + if ( childh == 3072 ) { + if ( cy + ch > childy + childh ) { + yNew = cy + ( ch - childh )/2; + } else if ( cy < childy ) { + yNew = cy + ( ch - childh )/2; + } +// qDebug("calculated yNew=%d", yNew); + } + yNew = kMin( yNew, yPos + m_height - childh ); + yNew = kMax( yNew, yPos ); + if ( yNew != childy || xNew != childx ) { + if ( vw->contentsHeight() < yNew - yPos + childh ) + vw->resizeContents( vw->contentsWidth(), yNew - yPos + childh ); + vw->setContentsPos( xNew - xPos, yNew - yPos ); + } + xPos = xNew; + yPos = yNew; + } + m_view->setWidgetVisible(this, true); + m_view->addChild(m_widget, xPos, yPos ); + m_widget->show(); + if (khtmlw) + paintWidget(paintInfo, m_widget, xPos, yPos); +} + +#include + +// The PaintBuffer class provides a shared buffer for widget painting. +// +// It will grow to encompass the biggest widget encountered, in order to avoid +// constantly resizing. +// When it grows over maxPixelBuffering, it periodically checks if such a size +// is still needed. If not, it shrinks down to the biggest size < maxPixelBuffering +// that was requested during the overflow lapse. + +class PaintBuffer: public QObject +{ +public: + static const int maxPixelBuffering = 320*200; + static const int leaseTime = 20*1000; + + static QPixmap *grab( QSize s = QSize() ) { + if (!m_inst) + m_inst = new PaintBuffer; + return m_inst->getBuf( s ); + } + static void release() { m_inst->m_grabbed = false; } +protected: + PaintBuffer(): m_overflow(false), m_grabbed(false), + m_timer(0), m_resetWidth(0), m_resetHeight(0) {}; + void timerEvent(QTimerEvent* e) { + assert( m_timer == e->timerId() ); + if (m_grabbed) + return; + m_buf.resize(m_resetWidth, m_resetHeight); + m_resetWidth = m_resetHeight = 0; + killTimer( m_timer ); + m_timer = 0; + } + + QPixmap *getBuf( QSize s ) { + assert( !m_grabbed ); + if (s.isEmpty()) + return 0; + + m_grabbed = true; + bool cur_overflow = false; + + int nw = kMax(m_buf.width(), s.width()); + int nh = kMax(m_buf.height(), s.height()); + + if (!m_overflow && (nw*nh > maxPixelBuffering)) + cur_overflow = true; + + if (nw != m_buf.width() || nh != m_buf.height()) + m_buf.resize(nw, nh); + + if (cur_overflow) { + m_overflow = true; + m_timer = startTimer( leaseTime ); + } else if (m_overflow) { + if( s.width()*s.height() > maxPixelBuffering ) { + killTimer( m_timer ); + m_timer = startTimer( leaseTime ); + } else { + if (s.width() > m_resetWidth) + m_resetWidth = s.width(); + if (s.height() > m_resetHeight) + m_resetHeight = s.height(); + } + } + return &m_buf; + } +private: + static PaintBuffer* m_inst; + QPixmap m_buf; + bool m_overflow; + bool m_grabbed; + int m_timer; + int m_resetWidth; + int m_resetHeight; +}; + +PaintBuffer *PaintBuffer::m_inst = 0; + +static void copyWidget(const QRect& r, QPainter *p, QWidget *widget, int tx, int ty) +{ + if (r.isNull() || r.isEmpty() ) + return; + QRegion blit(r); + QValueVector cw; + QValueVector cr; + + if (widget->children()) { + // build region + QObjectListIterator it = *widget->children(); + for (; it.current(); ++it) { + QWidget* const w = ::qt_cast(it.current()); + if ( w && !w->isTopLevel() && !w->isHidden()) { + QRect r2 = w->geometry(); + blit -= r2; + r2 = r2.intersect( r ); + r2.moveBy(-w->x(), -w->y()); + cr.append(r2); + cw.append(w); + } + } + } + QMemArray br = blit.rects(); + + const int cnt = br.size(); + const bool external = p->device()->isExtDev(); + QPixmap* const pm = PaintBuffer::grab( widget->size() ); + if (!pm) + { + kdWarning(6040) << "Rendering widget [ " << widget->className() << " ] failed due to invalid size." << endl; + return; + } + + // fill background + if ( external ) { + // even hackier! + QPainter pt( pm ); + const QColor c = widget->colorGroup().base(); + for (int i = 0; i < cnt; ++i) + pt.fillRect( br[i], c ); + } else { + QRect dr; + for (int i = 0; i < cnt; ++i ) { + dr = br[i]; + dr.moveBy( tx, ty ); + dr = p->xForm( dr ); + bitBlt(pm, br[i].topLeft(), p->device(), dr); + } + } + + // send paint event + QPainter::redirect(widget, pm); + QPaintEvent e( r, false ); + QApplication::sendEvent( widget, &e ); + QPainter::redirect(widget, 0); + + // transfer result + if ( external ) + for ( int i = 0; i < cnt; ++i ) + p->drawPixmap(QPoint(tx+br[i].x(), ty+br[i].y()), *pm, br[i]); + else + for ( int i = 0; i < cnt; ++i ) + bitBlt(p->device(), p->xForm( QPoint(tx, ty) + br[i].topLeft() ), pm, br[i]); + + // cleanup and recurse + PaintBuffer::release(); + QValueVector::iterator cwit = cw.begin(); + QValueVector::iterator cwitEnd = cw.end(); + QValueVector::const_iterator crit = cr.begin(); + for (; cwit != cwitEnd; ++cwit, ++crit) + copyWidget(*crit, p, *cwit, tx+(*cwit)->x(), ty+(*cwit)->y()); +} + +void RenderWidget::paintWidget(PaintInfo& pI, QWidget *widget, int tx, int ty) +{ + QPainter* const p = pI.p; + allowWidgetPaintEvents = true; + + const bool dsbld = QSharedDoubleBuffer::isDisabled(); + QSharedDoubleBuffer::setDisabled(true); + QRect rr = pI.r; + rr.moveBy(-tx, -ty); + const QRect r = widget->rect().intersect( rr ); + copyWidget(r, p, widget, tx, ty); + QSharedDoubleBuffer::setDisabled(dsbld); + + allowWidgetPaintEvents = false; +} + +bool RenderWidget::eventFilter(QObject* /*o*/, QEvent* e) +{ + // no special event processing if this is a frame (in which case KHTMLView handles it all) + if ( ::qt_cast( m_widget ) ) + return false; + if ( !element() ) return true; + + + static bool directToWidget = false; + if (directToWidget) { + //We're trying to get the event to the widget + //promptly. So get out of here.. + return false; + } + + ref(); + element()->ref(); + + bool filtered = false; + + //kdDebug() << "RenderWidget::eventFilter type=" << e->type() << endl; + switch(e->type()) { + case QEvent::FocusOut: + // First, forward it to the widget, so that Qt gets a precise + // state of the focus before pesky JS can try changing it.. + directToWidget = true; + QApplication::sendEvent(m_widget, e); + directToWidget = false; + filtered = true; //We already delivered it! + + // Don't count popup as a valid reason for losing the focus + // (example: opening the options of a select combobox shouldn't emit onblur) + if ( QFocusEvent::reason() != QFocusEvent::Popup ) + handleFocusOut(); + break; + case QEvent::FocusIn: + //As above, forward to the widget first... + directToWidget = true; + QApplication::sendEvent(m_widget, e); + directToWidget = false; + filtered = true; //We already delivered it! + + //kdDebug(6000) << "RenderWidget::eventFilter captures FocusIn" << endl; + element()->getDocument()->setFocusNode(element()); +// if ( isEditable() ) { +// KHTMLPartBrowserExtension *ext = static_cast( element()->view->part()->browserExtension() ); +// if ( ext ) ext->editableWidgetFocused( m_widget ); +// } + break; + case QEvent::KeyPress: + case QEvent::KeyRelease: + // TODO this seems wrong - Qt events are not correctly translated to DOM ones, + // like in KHTMLView::dispatchKeyEvent() + if (element()->dispatchKeyEvent(static_cast(e),false)) + filtered = true; + break; + + case QEvent::Wheel: + if (widget()->parentWidget() == view()->viewport()) { + // don't allow the widget to react to wheel event unless its + // currently focused. this avoids accidentally changing a select box + // or something while wheeling a webpage. + if (qApp->focusWidget() != widget() && + widget()->focusPolicy() <= QWidget::StrongFocus) { + static_cast(e)->ignore(); + QApplication::sendEvent(view(), e); + filtered = true; + } + } + break; + default: + break; + }; + + element()->deref(); + + // stop processing if the widget gets deleted, but continue in all other cases + if (hasOneRef()) + filtered = true; + deref(); + + return filtered; +} + +void RenderWidget::EventPropagator::sendEvent(QEvent *e) { + switch(e->type()) { + case QEvent::MouseButtonPress: + mousePressEvent(static_cast(e)); + break; + case QEvent::MouseButtonRelease: + mouseReleaseEvent(static_cast(e)); + break; + case QEvent::MouseButtonDblClick: + mouseDoubleClickEvent(static_cast(e)); + break; + case QEvent::MouseMove: + mouseMoveEvent(static_cast(e)); + break; + case QEvent::KeyPress: + keyPressEvent(static_cast(e)); + break; + case QEvent::KeyRelease: + keyReleaseEvent(static_cast(e)); + break; + default: + break; + } +} + +void RenderWidget::ScrollViewEventPropagator::sendEvent(QEvent *e) { + switch(e->type()) { + case QEvent::MouseButtonPress: + viewportMousePressEvent(static_cast(e)); + break; + case QEvent::MouseButtonRelease: + viewportMouseReleaseEvent(static_cast(e)); + break; + case QEvent::MouseButtonDblClick: + viewportMouseDoubleClickEvent(static_cast(e)); + break; + case QEvent::MouseMove: + viewportMouseMoveEvent(static_cast(e)); + break; + case QEvent::KeyPress: + keyPressEvent(static_cast(e)); + break; + case QEvent::KeyRelease: + keyReleaseEvent(static_cast(e)); + break; + default: + break; + } +} + +bool RenderWidget::handleEvent(const DOM::EventImpl& ev) +{ + bool ret = false; + switch(ev.id()) { + case EventImpl::MOUSEDOWN_EVENT: + case EventImpl::MOUSEUP_EVENT: + case EventImpl::MOUSEMOVE_EVENT: { + if (!ev.isMouseEvent()) break; + const MouseEventImpl &me = static_cast(ev); + QMouseEvent* const qme = me.qEvent(); + + int absx = 0; + int absy = 0; + + absolutePosition(absx, absy); + QPoint p(me.clientX() - absx + m_view->contentsX(), + me.clientY() - absy + m_view->contentsY()); + QMouseEvent::Type type; + int button = 0; + int state = 0; + + if (qme) { + button = qme->button(); + state = qme->state(); + type = qme->type(); + } else { + switch(me.id()) { + case EventImpl::MOUSEDOWN_EVENT: + type = QMouseEvent::MouseButtonPress; + break; + case EventImpl::MOUSEUP_EVENT: + type = QMouseEvent::MouseButtonRelease; + break; + case EventImpl::MOUSEMOVE_EVENT: + default: + type = QMouseEvent::MouseMove; + break; + } + switch (me.button()) { + case 0: + button = LeftButton; + break; + case 1: + button = MidButton; + break; + case 2: + button = RightButton; + break; + default: + break; + } + if (me.ctrlKey()) + state |= ControlButton; + if (me.altKey()) + state |= AltButton; + if (me.shiftKey()) + state |= ShiftButton; + if (me.metaKey()) + state |= MetaButton; + } + +// kdDebug(6000) << "sending event to widget " +// << " pos=" << p << " type=" << type +// << " button=" << button << " state=" << state << endl; + QMouseEvent e(type, p, button, state); + QScrollView * sc = ::qt_cast(m_widget); + if (sc && !::qt_cast(m_widget)) + static_cast(sc)->sendEvent(&e); + else + static_cast(m_widget)->sendEvent(&e); + ret = e.isAccepted(); + break; + } + case EventImpl::KEYDOWN_EVENT: + // do nothing; see the mapping table below + break; + case EventImpl::KEYUP_EVENT: { + if (!ev.isKeyRelatedEvent()) break; + + const KeyEventBaseImpl& domKeyEv = static_cast(ev); + if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) break; + + QKeyEvent* const ke = domKeyEv.qKeyEvent(); + static_cast(m_widget)->sendEvent(ke); + ret = ke->isAccepted(); + break; + } + case EventImpl::KEYPRESS_EVENT: { + if (!ev.isKeyRelatedEvent()) break; + + const KeyEventBaseImpl& domKeyEv = static_cast(ev); + if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) break; + + // See KHTMLView::dispatchKeyEvent: autorepeat is just keypress in the DOM + // but it's keyrelease+keypress in Qt. So here we do the inverse mapping as + // the one done in KHTMLView: generate two events for one DOM auto-repeat keypress. + // Similarly, DOM keypress events with non-autorepeat Qt event do nothing here, + // because the matching Qt keypress event was already sent from DOM keydown event. + + // Reverse drawing as the one in KHTMLView: + // DOM: Down Press | Press | Up + // Qt: (nothing) Press | Release(autorepeat) + Press(autorepeat) | Release + // + // Qt::KeyPress is sent for DOM keypress and not DOM keydown to allow + // sites to block a key with onkeypress, #99749 + + QKeyEvent* const ke = domKeyEv.qKeyEvent(); + if (ke->isAutoRepeat()) { + QKeyEvent releaseEv( QEvent::KeyRelease, ke->key(), ke->ascii(), ke->state(), + ke->text(), ke->isAutoRepeat(), ke->count() ); + static_cast(m_widget)->sendEvent(&releaseEv); + } + static_cast(m_widget)->sendEvent(ke); + ret = ke->isAccepted(); + break; + } + case EventImpl::MOUSEOUT_EVENT: { + QEvent moe( QEvent::Leave ); + QApplication::sendEvent(m_widget, &moe); + break; + } + case EventImpl::MOUSEOVER_EVENT: { + QEvent moe( QEvent::Enter ); + QApplication::sendEvent(m_widget, &moe); + view()->part()->resetHoverText(); + break; + } + default: + break; + } + return ret; +} + +void RenderWidget::deref() +{ + if (_ref) _ref--; +// qDebug( "deref(%p): width get count is %d", this, _ref); + if (!_ref) { + khtml::SharedPtr guard(m_arena); //Since delete on us gets called -first-, + //before the arena free + arenaDelete(m_arena.get()); + } +} + +FindSelectionResult RenderReplaced::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset, SelPointState &) +{ +#if 0 + kdDebug(6040) << "RenderReplaced::checkSelectionPoint(_x="<<_x<<",_y="<<_y<<",_tx="<<_tx<<",_ty="<<_ty<<")" << endl + << "xPos: " << xPos() << " yPos: " << yPos() << " width: " << width() << " height: " << height() << endl + << "_ty + yPos: " << (_ty + yPos()) << " + height: " << (_ty + yPos() + height()) << "; _tx + xPos: " << (_tx + xPos()) << " + width: " << (_tx + xPos() + width()) << endl; +#endif + node = element(); + offset = 0; + + if ( _y < _ty + yPos() ) + return SelectionPointBefore; // above -> before + + if ( _y > _ty + yPos() + height() ) { + // below -> after + // Set the offset to the max + offset = 1; + return SelectionPointAfter; + } + if ( _x > _tx + xPos() + width() ) { + // to the right + // ### how to regard bidi in replaced elements? (LS) + offset = 1; + return SelectionPointAfterInLine; + } + + // The Y matches, check if we're on the left + if ( _x < _tx + xPos() ) { + // ### how to regard bidi in replaced elements? (LS) + return SelectionPointBeforeInLine; + } + + offset = _x > _tx + xPos() + width()/2; + return SelectionPointInside; +} + +#ifdef ENABLE_DUMP +void RenderWidget::dump(QTextStream &stream, const QString &ind) const +{ + RenderReplaced::dump(stream,ind); + if ( widget() ) + stream << " color=" << widget()->foregroundColor().name() + << " bg=" << widget()->backgroundColor().name(); + else + stream << " null widget"; +} +#endif + +#include "render_replaced.moc" + -- cgit v1.2.1