📄 render_replaced.cpp
字号:
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<QWidget*> cw; QValueVector<QRect> cr; if (widget->children()) { // build region QObjectListIterator it = *widget->children(); for (; it.current(); ++it) { QWidget* const w = ::qt_cast<QWidget *>(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<QRect> 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<QWidget*>::iterator cwit = cw.begin(); QValueVector<QWidget*>::iterator cwitEnd = cw.end(); QValueVector<QRect>::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);#ifdef Q_WS_QWS // This breaks the widget z-order, but it allows the view to work without // the WPaintUnclipped hack allowWidgetPaintEvents = true;#else allowWidgetPaintEvents = false;#endif}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<KHTMLView *>( m_widget ) ) return false; if ( !element() ) return true; ref(); element()->ref(); bool filtered = false; //kdDebug() << "RenderWidget::eventFilter type=" << e->type() << endl; switch(e->type()) { case QEvent::FocusOut: // 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: //kdDebug(6000) << "RenderWidget::eventFilter captures FocusIn" << endl; element()->getDocument()->setFocusNode(element());// if ( isEditable() ) {// KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>( 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<QKeyEvent*>(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<QWheelEvent*>(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<QMouseEvent *>(e)); break; case QEvent::MouseButtonRelease: mouseReleaseEvent(static_cast<QMouseEvent *>(e)); break; case QEvent::MouseButtonDblClick: mouseDoubleClickEvent(static_cast<QMouseEvent *>(e)); break; case QEvent::MouseMove: mouseMoveEvent(static_cast<QMouseEvent *>(e)); break; case QEvent::KeyPress: keyPressEvent(static_cast<QKeyEvent *>(e)); break; case QEvent::KeyRelease: keyReleaseEvent(static_cast<QKeyEvent *>(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: { const MouseEventImpl &me = static_cast<const MouseEventImpl &>(ev); QMouseEvent* const qme = me.qEvent(); int absx = 0; int absy = 0; absolutePosition(absx, absy); const 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); static_cast<EventPropagator *>(m_widget)->sendEvent(&e); ret = e.isAccepted(); break; } case EventImpl::KEYDOWN_EVENT: // do nothing; see the mapping table below break; case EventImpl::KEYUP_EVENT: { QKeyEvent* const ke = static_cast<const TextEventImpl &>(ev).qKeyEvent(); static_cast<EventPropagator *>(m_widget)->sendEvent(ke); ret = ke->isAccepted(); break; } case EventImpl::KEYPRESS_EVENT: { // 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 = static_cast<const TextEventImpl &>(ev).qKeyEvent(); if (ke->isAutoRepeat()) { QKeyEvent releaseEv( QEvent::KeyRelease, ke->key(), ke->ascii(), ke->state(), ke->text(), ke->isAutoRepeat(), ke->count() ); static_cast<EventPropagator *>(m_widget)->sendEvent(&releaseEv); } static_cast<EventPropagator *>(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) arenaDelete(renderArena());}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_DUMPvoid 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"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -