File indexing completed on 2024-11-10 09:39:04
0001 /** 0002 * This file is part of the HTML widget for KDE. 0003 * 0004 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) 0005 * (C) 2000-2003 Dirk Mueller (mueller@kde.org) 0006 * (C) 2003 Apple Computer, Inc. 0007 * (C) 2004-2006 Germain Garand (germain@ebooksfrance.org) 0008 * 0009 * This library is free software; you can redistribute it and/or 0010 * modify it under the terms of the GNU Library General Public 0011 * License as published by the Free Software Foundation; either 0012 * version 2 of the License, or (at your option) any later version. 0013 * 0014 * This library is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 * Library General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU Library General Public License 0020 * along with this library; see the file COPYING.LIB. If not, write to 0021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 * Boston, MA 02110-1301, USA. 0023 * 0024 */ 0025 #include "render_replaced.h" 0026 #include "render_layer.h" 0027 #include "render_canvas.h" 0028 #include "render_line.h" 0029 #include "rendering/render_position.h" 0030 0031 #include "render_arena.h" 0032 0033 #include <assert.h> 0034 #include <QWidget> 0035 #include <QPainter> 0036 #include <QActionEvent> 0037 #include <QApplication> 0038 #include <QLineEdit> 0039 #include <QComboBox> 0040 #include <QCheckBox> 0041 #include <QRadioButton> 0042 #include <kurlrequester.h> 0043 #include <QVector> 0044 #include <QMatrix> 0045 #include <QPaintEngine> 0046 0047 #include "khtml_ext.h" 0048 #include "khtmlview.h" 0049 #include "xml/dom2_eventsimpl.h" 0050 #include "khtml_part.h" 0051 #include "xml/dom_docimpl.h" 0052 #include "xml/dom_position.h" 0053 #include "misc/helper.h" 0054 #include "misc/paintbuffer.h" 0055 #include "css/cssvalues.h" 0056 0057 #include <kcolorscheme.h> 0058 #include "khtml_debug.h" 0059 0060 //#define IN_PLACE_WIDGET_PAINTING 0061 0062 bool khtml::allowWidgetPaintEvents = false; 0063 0064 using namespace khtml; 0065 using namespace DOM; 0066 0067 RenderReplaced::RenderReplaced(DOM::NodeImpl *node) 0068 : RenderBox(node) 0069 { 0070 // init RenderObject attributes 0071 setReplaced(true); 0072 0073 m_intrinsicWidth = 300; 0074 m_intrinsicHeight = 150; 0075 } 0076 0077 void RenderReplaced::calcMinMaxWidth() 0078 { 0079 KHTMLAssert(!minMaxKnown()); 0080 0081 #ifdef DEBUG_LAYOUT 0082 // qCDebug(KHTML_LOG) << "RenderReplaced::calcMinMaxWidth() known=" << minMaxKnown(); 0083 #endif 0084 0085 m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight(); 0086 0087 if (style()->width().isPercent() || style()->height().isPercent() || 0088 style()->maxWidth().isPercent() || style()->maxHeight().isPercent() || 0089 style()->minWidth().isPercent() || style()->minHeight().isPercent()) { 0090 m_minWidth = 0; 0091 m_maxWidth = m_width; 0092 } else { 0093 m_minWidth = m_maxWidth = m_width; 0094 } 0095 0096 setMinMaxKnown(); 0097 } 0098 0099 FindSelectionResult RenderReplaced::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl *&node, int &offset, SelPointState &) 0100 { 0101 #if 0 0102 // qCDebug(KHTML_LOG) << "RenderReplaced::checkSelectionPoint(_x="<<_x<<",_y="<<_y<<",_tx="<<_tx<<",_ty="<<_ty<<")" << endl 0103 << "xPos: " << xPos() << " yPos: " << yPos() << " width: " << width() << " height: " << height() << endl 0104 << "_ty + yPos: " << (_ty + yPos()) << " + height: " << (_ty + yPos() + height()) << "; _tx + xPos: " << (_tx + xPos()) << " + width: " << (_tx + xPos() + width()); 0105 #endif 0106 node = element(); 0107 offset = 0; 0108 0109 if (_y < _ty + yPos()) { 0110 return SelectionPointBefore; // above -> before 0111 } 0112 0113 if (_y > _ty + yPos() + height()) { 0114 // below -> after 0115 // Set the offset to the max 0116 offset = 1; 0117 return SelectionPointAfter; 0118 } 0119 if (_x > _tx + xPos() + width()) { 0120 // to the right 0121 // ### how to regard bidi in replaced elements? (LS) 0122 offset = 1; 0123 return SelectionPointAfterInLine; 0124 } 0125 0126 // The Y matches, check if we're on the left 0127 if (_x < _tx + xPos()) { 0128 // ### how to regard bidi in replaced elements? (LS) 0129 return SelectionPointBeforeInLine; 0130 } 0131 0132 offset = _x > _tx + xPos() + width() / 2; 0133 return SelectionPointInside; 0134 } 0135 0136 long RenderReplaced::caretMinOffset() const 0137 { 0138 return 0; 0139 } 0140 0141 // Returns 1 since a replaced element can have the caret positioned 0142 // at its beginning (0), or at its end (1). 0143 long RenderReplaced::caretMaxOffset() const 0144 { 0145 return 1; 0146 } 0147 0148 unsigned long RenderReplaced::caretMaxRenderedOffset() const 0149 { 0150 return 1; 0151 } 0152 0153 RenderPosition RenderReplaced::positionForCoordinates(int _x, int _y) 0154 { 0155 InlineBox *box = placeHolderBox(); 0156 if (!box) { 0157 return RenderPosition(element(), 0); 0158 } 0159 0160 RootInlineBox *root = box->root(); 0161 0162 int absx, absy; 0163 containingBlock()->absolutePosition(absx, absy); 0164 0165 int top = absy + root->topOverflow(); 0166 int bottom = root->nextRootBox() ? absy + root->nextRootBox()->topOverflow() : absy + root->bottomOverflow(); 0167 0168 if (_y < top) { 0169 return RenderPosition(element(), caretMinOffset()); // coordinates are above 0170 } 0171 0172 if (_y >= bottom) { 0173 return RenderPosition(element(), caretMaxOffset()); // coordinates are below 0174 } 0175 0176 if (element()) { 0177 if (_x <= absx + xPos() + (width() / 2)) { 0178 return RenderPosition(element(), 0); 0179 } 0180 return RenderPosition(element(), 1); 0181 } 0182 0183 return RenderBox::positionForCoordinates(_x, _y); 0184 } 0185 0186 // ----------------------------------------------------------------------------- 0187 0188 RenderWidget::RenderWidget(DOM::NodeImpl *node) 0189 : RenderReplaced(node) 0190 { 0191 m_widget = nullptr; 0192 m_underMouse = nullptr; 0193 m_buffer[0] = nullptr; 0194 m_buffer[1] = nullptr; 0195 m_nativeFrameShape = QFrame::NoFrame; 0196 // a widget doesn't support being anonymous 0197 assert(!isAnonymous()); 0198 m_view = node->document()->view(); 0199 m_arena.reset(renderArena()); 0200 m_needsMask = false; 0201 m_ownsWidget = true; 0202 0203 // this is no real reference counting, it is just there 0204 // to make sure that we're not deleted while we're recursed 0205 // in an eventFilter of the widget 0206 ref(); 0207 } 0208 0209 void RenderWidget::detach() 0210 { 0211 // warning: keep in sync with RenderObject::detach 0212 0213 detachCounters(); 0214 remove(); 0215 0216 if (m_widget) { 0217 if (m_view) { 0218 m_view->setWidgetVisible(this, false); 0219 } 0220 KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget); 0221 if (k) { 0222 k->m_kwp->setRenderWidget(nullptr); 0223 } 0224 m_widget->removeEventFilter(this); 0225 m_widget->setMouseTracking(false); 0226 } 0227 0228 // make sure our DOM-node don't think we exist 0229 if (node() && node()->renderer() == this) { 0230 node()->setRenderer(nullptr); 0231 } 0232 0233 setDetached(); 0234 deref(); 0235 } 0236 0237 RenderWidget::~RenderWidget() 0238 { 0239 KHTMLAssert(refCount() <= 0); 0240 0241 if (m_widget) { 0242 if (m_widget->hasFocus()) { 0243 m_widget->clearFocus(); 0244 } 0245 m_widget->hide(); 0246 if (m_ownsWidget) { 0247 m_widget->deleteLater(); 0248 } 0249 } 0250 delete m_buffer[0]; 0251 delete m_buffer[1]; 0252 } 0253 0254 class QWidgetResizeEvent : public QEvent 0255 { 0256 public: 0257 enum { Type = QEvent::User + 0xbee }; 0258 QWidgetResizeEvent(int _w, int _h) : 0259 QEvent((QEvent::Type) Type), w(_w), h(_h) {} 0260 int w; 0261 int h; 0262 }; 0263 0264 void RenderWidget::resizeWidget(int w, int h) 0265 { 0266 // ugly hack to limit the maximum size of the widget ( as X11 has problems if 0267 // it is bigger ) 0268 h = qMin(h, 3072); 0269 w = qMin(w, 2000); 0270 0271 if (m_widget->width() != w || m_widget->height() != h) { 0272 m_widget->resize(w, h); 0273 if (isRedirectedWidget() && qobject_cast<KHTMLView *>(m_widget) && !m_widget->isVisible()) { 0274 // Emission of Resize event is delayed. 0275 // we have to pre-call KHTMLView::resizeEvent 0276 // so that viewport size change and subsequent layout update 0277 // is effective synchronously, which is important for JS. 0278 // This only work because m_widget is a redirected view, 0279 // and thus has visibleWidth()/visibleHeight() that mirror this RenderWidget, 0280 // rather than the effective widget size. - gg. 0281 QResizeEvent e(QSize(w, h), QSize(m_widget->width(), m_widget->height())); 0282 static_cast<KHTMLView *>(m_widget)->resizeEvent(&e); 0283 } 0284 } 0285 } 0286 0287 bool RenderWidget::event(QEvent *e) 0288 { 0289 // eat all events - except if this is a frame (in which case KHTMLView handles it all) 0290 if (qobject_cast<KHTMLView *>(m_widget)) { 0291 return QObject::event(e); 0292 } 0293 return true; 0294 } 0295 0296 bool RenderWidget::isRedirectedWidget() const 0297 { 0298 KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget); 0299 return k ? k->m_kwp->isRedirected() : false; 0300 } 0301 0302 void RenderWidget::setQWidget(QWidget *widget) 0303 { 0304 if (widget != m_widget) { 0305 if (m_widget) { 0306 m_widget->removeEventFilter(this); 0307 disconnect(m_widget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestructed())); 0308 m_widget->hide(); 0309 if (m_ownsWidget) { 0310 m_widget->deleteLater(); //Might happen due to event on the widget, so be careful 0311 } 0312 m_widget = nullptr; 0313 } 0314 m_widget = widget; 0315 if (m_widget) { 0316 KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget); 0317 bool isRedirectedSubFrame = false; 0318 if (k) { 0319 k->m_kwp->setRenderWidget(this); 0320 // enable redirection of every sub-frame that is not a FRAME 0321 if (qobject_cast<KHTMLView *>(m_widget) && element() && element()->id() != ID_FRAME) { 0322 k->m_kwp->setIsRedirected(true); 0323 isRedirectedSubFrame = true; 0324 } 0325 } 0326 m_widget->setParent(m_view->widget()); 0327 if (isRedirectedSubFrame) { 0328 static_cast<KHTMLView *>(m_widget)->setHasStaticBackground(); 0329 } 0330 connect(m_widget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestructed())); 0331 m_widget->installEventFilter(this); 0332 if (isRedirectedWidget()) { 0333 if (!qobject_cast<QFrame *>(m_widget)) { 0334 m_widget->setAttribute(Qt::WA_NoSystemBackground); 0335 } 0336 } 0337 if (m_widget->focusPolicy() > Qt::StrongFocus) { 0338 m_widget->setFocusPolicy(Qt::StrongFocus); 0339 } 0340 // if we've already received a layout, apply the calculated space to the 0341 // widget immediately, but we have to have really been full constructed (with a non-null 0342 // style pointer). 0343 if (!needsLayout() && style()) { 0344 resizeWidget(m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(), 0345 m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom()); 0346 } else { 0347 setPos(xPos(), -500000); 0348 } 0349 } 0350 m_view->setWidgetVisible(this, false); 0351 if (m_widget) { 0352 m_widget->move(0, -500000); 0353 m_widget->hide(); 0354 } 0355 } 0356 } 0357 0358 void RenderWidget::layout() 0359 { 0360 KHTMLAssert(needsLayout()); 0361 KHTMLAssert(minMaxKnown()); 0362 if (m_widget) { 0363 resizeWidget(m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(), 0364 m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom()); 0365 if (!isRedirectedWidget() && (!isFrame() || document()->part()->parentPart()) && !m_needsMask) { 0366 m_needsMask = true; 0367 RenderLayer *rl = enclosingStackingContext(); 0368 RenderLayer *el = enclosingLayer(); 0369 while (rl && el && el != rl) { 0370 if (el->renderer()->style()->position() != PSTATIC) { 0371 m_needsMask = false; 0372 break; 0373 } 0374 el = el->parent(); 0375 } 0376 if (m_needsMask) { 0377 if (rl) { 0378 rl->setHasOverlaidWidgets(); 0379 } 0380 canvas()->setNeedsWidgetMasks(); 0381 } 0382 } 0383 } 0384 0385 setNeedsLayout(false); 0386 } 0387 0388 void RenderWidget::updateFromElement() 0389 { 0390 if (m_widget && !qobject_cast<KHTMLView *>(m_widget)) { 0391 // Color: 0392 QColor color = style()->color(); 0393 if (forceTransparentText()) { 0394 color = Qt::transparent; 0395 } 0396 QColor backgroundColor = style()->backgroundColor(); 0397 0398 if (!backgroundColor.isValid() && !style()->htmlHacks()) { 0399 backgroundColor = Qt::transparent; 0400 } 0401 0402 bool hasBackgroundImage = style()->hasBackgroundImage(); 0403 // check if we have to paint our background and let it show through the widget 0404 bool trans = (isRedirectedWidget() && !qobject_cast<KUrlRequester *>(m_widget) && 0405 (hasBackgroundImage || (style()->hasBackground() && shouldPaintCSSBorders()))); 0406 0407 QPalette pal(QApplication::palette(m_widget)); 0408 // We need a non-transparent version for widgets with popups (e.g. kcombobox). The popups must not let 0409 // the background show through. 0410 QPalette non_trans_pal = pal; 0411 0412 if (color.isValid() || backgroundColor.isValid() || trans) { 0413 int contrast_ = KColorScheme::contrast(); 0414 int highlightVal = 100 + (2 * contrast_ + 4) * 16 / 10; 0415 int lowlightVal = 100 + (2 * contrast_ + 4) * 10; 0416 bool shouldChangeBgPal = true; 0417 0418 if (!backgroundColor.isValid()) { 0419 backgroundColor = pal.color(widget()->backgroundRole()); 0420 } else 0421 shouldChangeBgPal = !((backgroundColor == colorForCSSValue(CSS_VAL_WINDOW)) || 0422 (backgroundColor == colorForCSSValue(CSS_VAL_BUTTONFACE))); 0423 if (shouldChangeBgPal || trans) { 0424 pal.setColor(widget()->backgroundRole(), trans ? QColor(0, 0, 0, 0) : backgroundColor); 0425 for (int i = 0; i < QPalette::NColorGroups; ++i) { 0426 if (shouldChangeBgPal) { 0427 pal.setColor((QPalette::ColorGroup)i, QPalette::Window, backgroundColor); 0428 pal.setColor((QPalette::ColorGroup)i, QPalette::Light, backgroundColor.lighter(highlightVal)); 0429 pal.setColor((QPalette::ColorGroup)i, QPalette::Dark, backgroundColor.darker(lowlightVal)); 0430 pal.setColor((QPalette::ColorGroup)i, QPalette::Mid, backgroundColor.darker(120)); 0431 pal.setColor((QPalette::ColorGroup)i, QPalette::Midlight, backgroundColor.lighter(110)); 0432 } 0433 pal.setColor((QPalette::ColorGroup)i, QPalette::Button, trans ? QColor(0, 0, 0, 0) : backgroundColor); 0434 pal.setColor((QPalette::ColorGroup)i, QPalette::Base, trans ? QColor(0, 0, 0, 0) : backgroundColor); 0435 } 0436 } 0437 0438 if (color.isValid()) { 0439 struct ColorSet { 0440 QPalette::ColorGroup cg; 0441 QPalette::ColorRole cr; 0442 }; 0443 const struct ColorSet toSet [] = { 0444 { QPalette::Active, QPalette::WindowText }, 0445 { QPalette::Active, QPalette::ButtonText }, 0446 { QPalette::Active, QPalette::Text }, 0447 { QPalette::Inactive, QPalette::WindowText }, 0448 { QPalette::Inactive, QPalette::ButtonText }, 0449 { QPalette::Inactive, QPalette::Text }, 0450 { QPalette::NColorGroups, QPalette::NColorRoles }, 0451 }; 0452 const ColorSet *set = toSet; 0453 while (set->cg != QPalette::NColorGroups) { 0454 pal.setColor(set->cg, set->cr, color); 0455 non_trans_pal.setColor(set->cg, set->cr, color); 0456 ++set; 0457 } 0458 0459 QColor disfg = color; 0460 int h, s, v; 0461 disfg.getHsv(&h, &s, &v); 0462 if (v > 128) 0463 // dark bg, light fg - need a darker disabled fg 0464 { 0465 disfg = disfg.darker(lowlightVal); 0466 } else if (v > 64) 0467 // light bg, dark fg - need a lighter disabled fg - but only if !black 0468 { 0469 disfg = disfg.lighter(highlightVal); 0470 } else 0471 // for really dark fg - use darkgray disabled fg, 0472 // as ::light is pretty useless in this range 0473 { 0474 disfg = Qt::darkGray; 0475 } 0476 pal.setColor(QPalette::Disabled, QPalette::WindowText, disfg); 0477 pal.setColor(QPalette::Disabled, QPalette::Text, disfg); 0478 pal.setColor(QPalette::Disabled, QPalette::ButtonText, disfg); 0479 non_trans_pal.setColor(QPalette::Disabled, QPalette::WindowText, disfg); 0480 non_trans_pal.setColor(QPalette::Disabled, QPalette::Text, disfg); 0481 non_trans_pal.setColor(QPalette::Disabled, QPalette::ButtonText, disfg); 0482 } 0483 } 0484 0485 if ((qobject_cast<QCheckBox *>(m_widget) || qobject_cast<QRadioButton *>(m_widget)) && 0486 (backgroundColor == Qt::transparent && !hasBackgroundImage)) { 0487 m_widget->setPalette(non_trans_pal); 0488 } else { 0489 m_widget->setPalette(pal); 0490 } 0491 0492 // Combobox's popup colors 0493 if (qobject_cast<QComboBox *>(m_widget)) { 0494 // Background 0495 if (hasBackgroundImage) { 0496 non_trans_pal = QApplication::palette(); 0497 } else if (backgroundColor.isValid() && backgroundColor != Qt::transparent) { 0498 non_trans_pal.setColor(QPalette::Base, backgroundColor); 0499 } 0500 // mmh great, there's no accessor for the popup... 0501 QList<QWidget *>l = m_widget->findChildren<QWidget *>(); 0502 foreach (QWidget *w, l) { 0503 if (QAbstractScrollArea *lView = qobject_cast<QAbstractScrollArea *>(w)) { 0504 // we have the listview, climb up to reach its container. 0505 assert(w->parentWidget() != m_widget); 0506 if (w->parentWidget()) { 0507 w->parentWidget()->setPalette(non_trans_pal); 0508 // Set system color for vertical scrollbar 0509 lView->verticalScrollBar()->setPalette(QApplication::palette()); 0510 } 0511 } 0512 } 0513 } else if (QAbstractScrollArea *scrollView = qobject_cast<QAbstractScrollArea *>(m_widget)) { 0514 // Border 0515 if (QFrame *frame = qobject_cast<QFrame *>(m_widget)) { 0516 if (shouldDisableNativeBorders()) { 0517 if (frame->frameShape() != QFrame::NoFrame) { 0518 m_nativeFrameShape = frame->frameShape(); 0519 frame->setFrameShape(QFrame::NoFrame); 0520 } 0521 } else if (m_nativeFrameShape != QFrame::NoFrame) { 0522 frame->setFrameShape(m_nativeFrameShape); 0523 } 0524 } 0525 // Scrollbars color (ie css extension) 0526 scrollView->horizontalScrollBar()->setPalette(style()->palette()); 0527 scrollView->verticalScrollBar()->setPalette(style()->palette()); 0528 } else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_widget)) { 0529 lineEdit->setFrame(!shouldDisableNativeBorders()); 0530 } 0531 } 0532 0533 RenderReplaced::updateFromElement(); 0534 } 0535 0536 void RenderWidget::paintBoxDecorations(PaintInfo &paintInfo, int _tx, int _ty) 0537 { 0538 QRect r = QRect(_tx, _ty, width(), height()); 0539 QRect cr = r.intersected(paintInfo.r); 0540 0541 if (qobject_cast<QAbstractScrollArea *>(m_widget) || (isRedirectedWidget() && 0542 (style()->hasBackgroundImage() || (style()->hasBackground() && shouldPaintCSSBorders())))) { 0543 paintAllBackgrounds(paintInfo.p, style()->backgroundColor(), style()->backgroundLayers(), 0544 cr, r.x(), r.y(), r.width(), r.height()); 0545 } 0546 0547 if (shouldPaintCSSBorders() && style()->hasBorder()) { 0548 paintBorder(paintInfo.p, _tx, _ty, width(), height(), style()); 0549 } 0550 } 0551 0552 void RenderWidget::slotWidgetDestructed() 0553 { 0554 if (m_view) { 0555 m_view->setWidgetVisible(this, false); 0556 } 0557 m_widget = nullptr; 0558 } 0559 0560 void RenderWidget::setStyle(RenderStyle *_style) 0561 { 0562 RenderReplaced::setStyle(_style); 0563 if (m_widget) { 0564 m_widget->setFont(style()->font()); 0565 if (style()->visibility() != VISIBLE) { 0566 if (m_view) { 0567 m_view->setWidgetVisible(this, false); 0568 } 0569 m_widget->hide(); 0570 } 0571 } 0572 } 0573 0574 void RenderWidget::paint(PaintInfo &paintInfo, int _tx, int _ty) 0575 { 0576 0577 // not visible or not even once layouted 0578 if (style()->visibility() != VISIBLE || m_y <= -500000) { 0579 return; 0580 } 0581 0582 _tx += m_x; 0583 _ty += m_y; 0584 0585 int os = maximalOutlineSize(paintInfo.phase); 0586 if ((_ty - os > paintInfo.r.bottom()) || (_ty + m_height + os <= paintInfo.r.top()) || 0587 (_tx + m_width + os <= paintInfo.r.left()) || (_tx - os > paintInfo.r.right())) { 0588 return; 0589 } 0590 0591 if ((paintInfo.phase == PaintActionChildBackground || paintInfo.phase == PaintActionChildBackgrounds) && 0592 shouldPaintBackgroundOrBorder() && !qobject_cast<KUrlRequester *>(m_widget)) { 0593 paintBoxDecorations(paintInfo, _tx, _ty); 0594 } 0595 0596 if (paintInfo.phase == PaintActionOutline && style()->outlineWidth()) { 0597 paintOutline(paintInfo.p, _tx, _ty, width(), height(), style()); 0598 } 0599 0600 if (!m_widget || !m_view || paintInfo.phase != PaintActionForeground) { 0601 return; 0602 } 0603 0604 int xPos = _tx + borderLeft() + paddingLeft(); 0605 int yPos = _ty + borderTop() + paddingTop(); 0606 0607 bool khtmlw = isRedirectedWidget(); 0608 int childw = m_widget->width(); 0609 int childh = m_widget->height(); 0610 if ((childw == 2000 || childh == 3072) && m_widget->inherits("KHTMLView")) { 0611 KHTMLView *vw = static_cast<KHTMLView *>(m_widget); 0612 int cy = m_view->contentsY(); 0613 int ch = m_view->visibleHeight(); 0614 0615 int childx = m_widget->pos().x(); 0616 int childy = m_widget->pos().y(); 0617 0618 int xNew = xPos; 0619 int yNew = childy; 0620 0621 // qDebug("cy=%d, ch=%d, childy=%d, childh=%d", cy, ch, childy, childh ); 0622 if (childh == 3072) { 0623 if (cy + ch > childy + childh) { 0624 yNew = cy + (ch - childh) / 2; 0625 } else if (cy < childy) { 0626 yNew = cy + (ch - childh) / 2; 0627 } 0628 // qDebug("calculated yNew=%d", yNew); 0629 } 0630 yNew = qMin(yNew, yPos + m_height - childh); 0631 yNew = qMax(yNew, yPos); 0632 if (yNew != childy || xNew != childx) { 0633 if (vw->contentsHeight() < yNew - yPos + childh) { 0634 vw->resizeContents(vw->contentsWidth(), yNew - yPos + childh); 0635 } 0636 vw->setContentsPos(xNew - xPos, yNew - yPos); 0637 } 0638 xPos = xNew; 0639 yPos = yNew; 0640 } 0641 m_view->setWidgetVisible(this, true); 0642 if (!khtmlw) { 0643 m_view->addChild(m_widget, xPos, yPos); 0644 } else { 0645 m_view->addChild(m_widget, xPos, -500000 + yPos); 0646 } 0647 m_widget->show(); 0648 if (khtmlw) { 0649 if (KHTMLView *v = qobject_cast<KHTMLView *>(m_widget)) { 0650 // our buffers are dedicated to scrollbars. 0651 if (v->verticalScrollBar()->isVisible() && (!m_buffer[0] || v->verticalScrollBar()->size() != m_buffer[0]->size())) { 0652 delete m_buffer[0]; 0653 m_buffer[0] = new QPixmap(v->verticalScrollBar()->size()); 0654 } 0655 if (v->horizontalScrollBar()->isVisible() && (!m_buffer[1] || v->horizontalScrollBar()->size() != m_buffer[1]->size())) { 0656 delete m_buffer[1]; 0657 m_buffer[1] = new QPixmap(v->horizontalScrollBar()->size()); 0658 } 0659 } else if (!m_buffer[0] || (m_widget->size() != m_buffer[0]->size())) { 0660 assert(!m_buffer[1]); 0661 delete m_buffer[0]; 0662 m_buffer[0] = new QPixmap(m_widget->size()); 0663 } 0664 paintWidget(paintInfo, m_widget, xPos, yPos, m_buffer); 0665 } 0666 } 0667 0668 static void setInPaintEventFlag(QWidget *w, bool b = true, bool recurse = true) 0669 { 0670 w->setAttribute(Qt::WA_WState_InPaintEvent, b); 0671 0672 if (!recurse) { 0673 return; 0674 } 0675 if (qobject_cast<KHTMLView *>(w)) { 0676 setInPaintEventFlag(static_cast<KHTMLView *>(w)->widget(), b, false); 0677 setInPaintEventFlag(static_cast<KHTMLView *>(w)->horizontalScrollBar(), b, false); 0678 setInPaintEventFlag(static_cast<KHTMLView *>(w)->verticalScrollBar(), b, false); 0679 return; 0680 } 0681 0682 foreach (QObject *o, w->children()) { 0683 QWidget *const cw = static_cast<QWidget *>(o); 0684 if (o->isWidgetType() && ! cw->isWindow() 0685 && !(cw->windowModality() & Qt::ApplicationModal)) { 0686 setInPaintEventFlag(cw, b); 0687 } 0688 } 0689 } 0690 0691 static void copyWidget(const QRect &r, QPainter *p, QWidget *widget, int tx, int ty, bool buffered = false, QPixmap *buffer = nullptr) 0692 { 0693 if (r.isNull() || r.isEmpty()) { 0694 return; 0695 } 0696 0697 QPoint thePoint(tx, ty); 0698 QTransform t = p->worldTransform(); 0699 0700 if (!buffered && t.isTranslating()) { 0701 thePoint.setX(thePoint.x() + static_cast<int>(t.dx())); 0702 thePoint.setY(thePoint.y() + static_cast<int>(t.dy())); 0703 } 0704 QPixmap *pm = nullptr; 0705 QPaintDevice *d = p->device(); 0706 #ifdef IN_PLACE_WIDGET_PAINTING 0707 QPaintDevice *x = d; 0708 bool vte = p->viewTransformEnabled(); 0709 bool wme = p->worldMatrixEnabled(); 0710 QRect w = p->window(); 0711 QRect v = p->viewport(); 0712 QRegion rg = p->clipRegion(); 0713 qreal op = p->opacity(); 0714 QPen pen = p->pen(); 0715 QBrush brush = p->brush(); 0716 QPainter::RenderHints rh = p->renderHints(); 0717 #endif 0718 if (buffered) { 0719 if (!widget->size().isValid()) { 0720 return; 0721 } 0722 // TT says Qt 4's widget painting hits an NVidia RenderAccel bug/shortcoming 0723 // resulting in pixmap buffers being unsuitable for reuse by more than one widget. 0724 // 0725 // Until a turnaround exist in Qt, we can't reliably use shared buffers. 0726 // ### pm = PaintBuffer::grab(widget->size()); 0727 assert(buffer); 0728 pm = buffer; 0729 if (!pm->hasAlphaChannel()) { 0730 pm->fill(Qt::transparent); 0731 } else { 0732 QPainter pp(pm); 0733 pp.setCompositionMode(QPainter::CompositionMode_Source); 0734 pp.fillRect(r, Qt::transparent); 0735 } 0736 d = pm; 0737 } else { 0738 p->end(); 0739 } 0740 0741 setInPaintEventFlag(widget, false); 0742 0743 widget->render(d, (buffered ? QPoint(0, 0) : thePoint) + r.topLeft(), r); 0744 0745 setInPaintEventFlag(widget); 0746 0747 if (!buffered) { 0748 #ifdef IN_PLACE_WIDGET_PAINTING 0749 p->begin(x); 0750 p->setWorldTransform(t); 0751 p->setWindow(w); 0752 p->setViewport(v); 0753 p->setViewTransformEnabled(vte); 0754 p->setWorldMatrixEnabled(wme); 0755 p->setRenderHints(rh); 0756 if (!rg.isEmpty()) { 0757 p->setClipRegion(rg); 0758 } 0759 if (op < 1.0f) { 0760 p->setOpacity(op); 0761 } 0762 p->setPen(pen); 0763 p->setBrush(brush); 0764 #else 0765 assert(false); 0766 #endif 0767 } else { 0768 // transfer results 0769 QPoint off(r.x(), r.y()); 0770 p->drawPixmap(thePoint + off, static_cast<QPixmap &>(*d), r); 0771 // ### PaintBuffer::release(pm); 0772 } 0773 } 0774 0775 void RenderWidget::paintWidget(PaintInfo &pI, QWidget *widget, int tx, int ty, QPixmap *buffer[]) 0776 { 0777 QPainter *const p = pI.p; 0778 allowWidgetPaintEvents = true; 0779 0780 bool buffered = 0781 #ifdef IN_PLACE_WIDGET_PAINTING 0782 p->combinedMatrix().m22() != 1.0 || (p->device()->devType() == QInternal::Printer); 0783 #else 0784 true; 0785 #endif 0786 QRect rr = pI.r; 0787 rr.translate(-tx, -ty); 0788 const QRect r = widget->rect().intersected(rr); 0789 if (KHTMLView *v = qobject_cast<KHTMLView *>(widget)) { 0790 QPoint thePoint(tx, ty); 0791 if (v->verticalScrollBar()->isVisible()) { 0792 QRect vbr = v->verticalScrollBar()->rect(); 0793 QPoint of = v->verticalScrollBar()->mapTo(v, QPoint(vbr.x(), vbr.y())); 0794 vbr.translate(of); 0795 vbr &= r; 0796 vbr.translate(-of); 0797 if (vbr.isValid() && !vbr.isEmpty()) { 0798 copyWidget(vbr, p, v->verticalScrollBar(), tx + of.x(), ty + of.y(), buffered, buffer[0]); 0799 } 0800 } 0801 if (v->horizontalScrollBar()->isVisible()) { 0802 QRect hbr = v->horizontalScrollBar()->rect(); 0803 QPoint of = v->horizontalScrollBar()->mapTo(v, QPoint(hbr.x(), hbr.y())); 0804 hbr.translate(of); 0805 hbr &= r; 0806 hbr.translate(-of); 0807 if (hbr.isValid() && !hbr.isEmpty()) { 0808 copyWidget(hbr, p, v->horizontalScrollBar(), tx + of.x(), ty + of.y(), buffered, buffer[1]); 0809 } 0810 } 0811 QPoint of = v->viewport()->mapTo(v, QPoint(0, 0)); 0812 QRect vr = (r & v->viewport()->rect().translated(of)); 0813 if (vr.isValid() && !vr.isEmpty()) { 0814 v->render(p, vr, thePoint); 0815 } 0816 } else { 0817 copyWidget(r, p, widget, tx, ty, buffered, buffer[0]); 0818 } 0819 allowWidgetPaintEvents = false; 0820 } 0821 0822 bool RenderWidget::eventFilter(QObject * /*o*/, QEvent *e) 0823 { 0824 // no special event processing if this is a frame (in which case KHTMLView handles it all) 0825 if (qobject_cast<KHTMLView *>(m_widget) || isRedirectedWidget()) { 0826 return false; 0827 } 0828 if (!element()) { 0829 return true; 0830 } 0831 0832 static bool directToWidget = false; 0833 if (directToWidget) { 0834 //We're trying to get the event to the widget 0835 //promptly. So get out of here.. 0836 return false; 0837 } 0838 0839 ref(); 0840 element()->ref(); 0841 0842 bool filtered = false; 0843 0844 //qCDebug(KHTML_LOG) << "RenderWidget::eventFilter type=" << e->type(); 0845 switch (e->type()) { 0846 case QEvent::FocusOut: 0847 // First, forward it to the widget, so that Qt gets a precise 0848 // state of the focus before pesky JS can try changing it.. 0849 directToWidget = true; 0850 QApplication::sendEvent(m_widget, e); 0851 directToWidget = false; 0852 filtered = true; //We already delivered it! 0853 0854 // Don't count popup as a valid reason for losing the focus 0855 // (example: opening the options of a select combobox shouldn't emit onblur) 0856 if (static_cast<QFocusEvent *>(e)->reason() != Qt::PopupFocusReason) { 0857 handleFocusOut(); 0858 } 0859 break; 0860 case QEvent::FocusIn: 0861 //As above, forward to the widget first... 0862 directToWidget = true; 0863 QApplication::sendEvent(m_widget, e); 0864 directToWidget = false; 0865 filtered = true; //We already delivered it! 0866 0867 //qCDebug(KHTML_LOG) << "RenderWidget::eventFilter captures FocusIn"; 0868 document()->setFocusNode(element()); 0869 // if ( isEditable() ) { 0870 // KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>( element()->view->part()->browserExtension() ); 0871 // if ( ext ) ext->editableWidgetFocused( m_widget ); 0872 // } 0873 break; 0874 case QEvent::Wheel: { 0875 if (widget()->parentWidget() == view()->widget()) { 0876 bool vertical = (static_cast<QWheelEvent *>(e)->orientation() == Qt::Vertical); 0877 // don't allow the widget to react to wheel event if 0878 // the view is being scrolled by mouse wheel 0879 // This does not apply if the webpage has no valid scroll range in the given wheel event orientation. 0880 if (((vertical && (view()->contentsHeight() > view()->visibleHeight())) || 0881 (!vertical && (view()->contentsWidth() > view()->visibleWidth()))) && 0882 view()->isScrollingFromMouseWheel()) { 0883 static_cast<QWheelEvent *>(e)->ignore(); 0884 QApplication::sendEvent(view(), e); 0885 filtered = true; 0886 } 0887 } 0888 break; 0889 } 0890 case QEvent::KeyPress: 0891 case QEvent::KeyRelease: 0892 // TODO this seems wrong - Qt events are not correctly translated to DOM ones, 0893 // like in KHTMLView::dispatchKeyEvent() 0894 if (element()->dispatchKeyEvent(static_cast<QKeyEvent *>(e), false)) { 0895 filtered = true; 0896 } 0897 break; 0898 0899 default: 0900 break; 0901 }; 0902 0903 element()->deref(); 0904 0905 // stop processing if the widget gets deleted, but continue in all other cases 0906 if (hasOneRef()) { 0907 filtered = true; 0908 } 0909 deref(); 0910 0911 return filtered; 0912 } 0913 0914 void RenderWidget::EventPropagator::sendEvent(QEvent *e) 0915 { 0916 // ### why don't we just call event()? That would be the normal route. 0917 switch (e->type()) { 0918 case QEvent::Wheel: 0919 wheelEvent(static_cast<QWheelEvent *>(e)); 0920 break; 0921 case QEvent::MouseButtonPress: 0922 mousePressEvent(static_cast<QMouseEvent *>(e)); 0923 break; 0924 case QEvent::MouseButtonRelease: 0925 mouseReleaseEvent(static_cast<QMouseEvent *>(e)); 0926 break; 0927 case QEvent::MouseButtonDblClick: 0928 mouseDoubleClickEvent(static_cast<QMouseEvent *>(e)); 0929 break; 0930 case QEvent::MouseMove: 0931 mouseMoveEvent(static_cast<QMouseEvent *>(e)); 0932 break; 0933 case QEvent::KeyPress: 0934 keyPressEvent(static_cast<QKeyEvent *>(e)); 0935 break; 0936 case QEvent::KeyRelease: 0937 if (qobject_cast<QLineEdit *>(this)) { 0938 event(e); 0939 } else { 0940 keyReleaseEvent(static_cast<QKeyEvent *>(e)); 0941 } 0942 break; 0943 case QEvent::FocusIn: 0944 focusInEvent(static_cast<QFocusEvent *>(e)); 0945 break; 0946 case QEvent::FocusOut: 0947 focusOutEvent(static_cast<QFocusEvent *>(e)); 0948 break; 0949 case QEvent::ContextMenu: 0950 contextMenuEvent(static_cast<QContextMenuEvent *>(e)); 0951 break; 0952 default: 0953 break; 0954 } 0955 } 0956 0957 // send event to target and let it bubble up until it is accepted or 0958 // once it would go through a limiting widget level 0959 static bool bubblingSend(QWidget *target, QEvent *e, QWidget *stoppingParent) 0960 { 0961 for (;;) { 0962 static_cast<RenderWidget::EventPropagator *>(target)->sendEvent(e); 0963 if (e->isAccepted()) { 0964 return true; 0965 } 0966 if (target == stoppingParent) { 0967 return false; 0968 } 0969 // ### might want to shift Q*Event::pos() as we go up 0970 target = target->parentWidget(); 0971 assert(target != nullptr); 0972 } 0973 } 0974 0975 bool RenderWidget::handleEvent(const DOM::EventImpl &ev) 0976 { 0977 bool ret = false; 0978 0979 switch (ev.id()) { 0980 case EventImpl::DOMFOCUSIN_EVENT: 0981 case EventImpl::DOMFOCUSOUT_EVENT: { 0982 QFocusEvent e(ev.id() == EventImpl::DOMFOCUSIN_EVENT ? QEvent::FocusIn : QEvent::FocusOut); 0983 // E.g. a KLineEdit child widget might be defined to receive 0984 // focus instead 0985 QWidget *fw = m_widget->focusProxy() ? m_widget->focusProxy() : m_widget; 0986 static_cast<EventPropagator *>(fw)->sendEvent(&e); 0987 ret = e.isAccepted(); 0988 break; 0989 } 0990 case EventImpl::KHTML_MOUSEWHEEL_EVENT: 0991 case EventImpl::MOUSEDOWN_EVENT: 0992 case EventImpl::MOUSEUP_EVENT: 0993 case EventImpl::MOUSEMOVE_EVENT: { 0994 if (!ev.isMouseEvent()) { 0995 break; 0996 } 0997 0998 const MouseEventImpl &me = static_cast<const MouseEventImpl &>(ev); 0999 QMouseEvent *const qme = me.qEvent(); 1000 QMouseEvent::Type type; 1001 Qt::MouseButton button = Qt::NoButton; 1002 Qt::MouseButtons buttons = Qt::NoButton; 1003 Qt::KeyboardModifiers state = Qt::NoModifier; 1004 Qt::Orientation orient = Qt::Vertical; 1005 1006 if (qme) { 1007 buttons = qme->buttons(); 1008 button = qme->button(); 1009 state = qme->modifiers(); 1010 type = qme->type(); 1011 } else { 1012 switch (me.button()) { 1013 case 0: 1014 button = Qt::LeftButton; 1015 break; 1016 case 1: 1017 button = Qt::MidButton; 1018 break; 1019 case 2: 1020 button = Qt::RightButton; 1021 break; 1022 default: 1023 break; 1024 } 1025 1026 buttons = button; 1027 1028 switch (me.id()) { 1029 case EventImpl::MOUSEDOWN_EVENT: 1030 type = QMouseEvent::MouseButtonPress; 1031 break; 1032 case EventImpl::MOUSEUP_EVENT: 1033 type = QMouseEvent::MouseButtonRelease; 1034 break; 1035 case EventImpl::KHTML_MOUSEWHEEL_EVENT: 1036 case EventImpl::MOUSEMOVE_EVENT: 1037 default: 1038 type = QMouseEvent::MouseMove; 1039 button = Qt::NoButton; 1040 break; 1041 } 1042 1043 if (me.orientation() == MouseEventImpl::OHorizontal) { 1044 orient = Qt::Horizontal; 1045 } 1046 1047 if (me.ctrlKey()) { 1048 state |= Qt::ControlModifier; 1049 } 1050 if (me.altKey()) { 1051 state |= Qt::AltModifier; 1052 } 1053 if (me.shiftKey()) { 1054 state |= Qt::ShiftModifier; 1055 } 1056 if (me.metaKey()) { 1057 state |= Qt::MetaModifier; 1058 } 1059 } 1060 1061 int absx = 0; 1062 int absy = 0; 1063 absolutePosition(absx, absy); 1064 absx += borderLeft() + paddingLeft(); 1065 absy += borderTop() + paddingTop(); 1066 1067 QPoint p(me.clientX() - absx + m_view->contentsX(), 1068 me.clientY() - absy + m_view->contentsY()); 1069 1070 if (ev.id() == EventImpl::MOUSEMOVE_EVENT && view()->mouseEventsTarget()) { 1071 // mitigate the problem that mouse moves outside of the widget rect 1072 // interrupt the selection process in textarea (#156574) 1073 // e.g. when extending a selection upward to make a textarea scroll 1074 // while selecting its content. 1075 // We don't emulate properly what Qt does it seems,tough I verified 1076 // the move event is properly forwarded to the textarea and has 1077 // appropriate coordinates. Might be Enter/Leave issue. ### FIXME 1078 // In the meantime, clamping the event to the widget rect 1079 // will at least prevent the selection to be lost. 1080 p.setX(qMin(qMax(0, p.x()), m_widget->width())); 1081 p.setY(qMin(qMax(0, p.y()), m_widget->height())); 1082 } 1083 1084 QPointer<QWidget> target; 1085 target = m_widget->childAt(p); 1086 1087 if (target) { 1088 p = target->mapFrom(m_widget, p); 1089 } 1090 1091 if (m_underMouse != target && ev.id() != EventImpl::KHTML_MOUSEWHEEL_EVENT) { 1092 if (m_underMouse) { 1093 QEvent moe(QEvent::Leave); 1094 QApplication::sendEvent(m_underMouse, &moe); 1095 // qCDebug(KHTML_LOG) << "sending LEAVE to"<< m_underMouse; 1096 if (m_underMouse->testAttribute(Qt::WA_Hover)) { 1097 QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), QPoint(0, 0)); 1098 QApplication::sendEvent(m_underMouse, &he); 1099 } 1100 } 1101 if (target) { 1102 QEvent moe(QEvent::Enter); 1103 QApplication::sendEvent(target, &moe); 1104 // qCDebug(KHTML_LOG) << "sending ENTER to" << target; 1105 if (target->testAttribute(Qt::WA_Hover)) { 1106 QHoverEvent he(QEvent::HoverEnter, QPoint(0, 0), QPoint(-1, -1)); 1107 QApplication::sendEvent(target, &he); 1108 } 1109 } 1110 m_underMouse = target; 1111 } 1112 #if 0 1113 if (target && ev.id() == EventImpl::MOUSEMOVE_EVENT) { 1114 // ### is this one still necessary? it doubles every mouse event... 1115 // I'd reckon it's no longer needed since Harri made the event propagation bubble 1116 QMouseEvent evt(QEvent::MouseMove, p, Qt::NoButton, 1117 QApplication::mouseButtons(), QApplication::keyboardModifiers()); 1118 QApplication::sendEvent(target, &evt); 1119 } 1120 #endif 1121 if (ev.id() == EventImpl::MOUSEDOWN_EVENT) { 1122 if (!target || (!::qobject_cast<QScrollBar *>(target) && 1123 !::qobject_cast<KUrlRequester *>(m_widget) && 1124 !::qobject_cast<QLineEdit *>(m_widget))) { 1125 target = m_widget; 1126 } 1127 view()->setMouseEventsTarget(target); 1128 } else { 1129 target = view()->mouseEventsTarget(); 1130 if (target) { 1131 QWidget *parent = target; 1132 while (parent && parent != m_widget) { 1133 parent = parent->parentWidget(); 1134 } 1135 if (!parent) { 1136 return false; 1137 } 1138 } else { 1139 target = m_widget; 1140 } 1141 } 1142 1143 bool needContextMenuEvent = (type == QMouseEvent::MouseButtonPress && button == Qt::RightButton); 1144 bool isMouseWheel = (ev.id() == EventImpl::KHTML_MOUSEWHEEL_EVENT); 1145 1146 if (isMouseWheel) { 1147 // don't allow the widget to react to wheel event if 1148 // a) the view is being scrolled by mouse wheel 1149 // b) it's an unfocused ComboBox (for extra security against unwanted changes to formulars) 1150 // This does not apply if the webpage has no valid scroll range in the given wheel event orientation. 1151 if (((orient == Qt::Vertical && (view()->contentsHeight() > view()->visibleHeight())) || 1152 (orient == Qt::Horizontal && (view()->contentsWidth() > view()->visibleWidth()))) && 1153 (view()->isScrollingFromMouseWheel() || 1154 (qobject_cast<QComboBox *>(m_widget) && 1155 (!document()->focusNode() || document()->focusNode()->renderer() != this)))) { 1156 ret = false; 1157 break; 1158 } 1159 } 1160 1161 QScopedPointer<QEvent> e(isMouseWheel ? 1162 static_cast<QEvent *>(new QWheelEvent(p, -me.detail() * 40, buttons, state, orient)) : 1163 static_cast<QEvent *>(new QMouseEvent(type, p, button, buttons, state))); 1164 1165 ret = bubblingSend(target, e.data(), m_widget); 1166 1167 if (!target) { 1168 break; 1169 } 1170 if (needContextMenuEvent) { 1171 QContextMenuEvent cme(QContextMenuEvent::Mouse, p); 1172 static_cast<EventPropagator *>(target.data())->sendEvent(&cme); 1173 } else if (type == QEvent::MouseMove && target->testAttribute(Qt::WA_Hover)) { 1174 QHoverEvent he(QEvent::HoverMove, p, p); 1175 QApplication::sendEvent(target, &he); 1176 } 1177 if (ev.id() == EventImpl::MOUSEUP_EVENT) { 1178 view()->setMouseEventsTarget(nullptr); 1179 } 1180 break; 1181 } 1182 case EventImpl::KEYDOWN_EVENT: 1183 // do nothing; see the mapping table below 1184 break; 1185 case EventImpl::KEYUP_EVENT: { 1186 if (!ev.isKeyRelatedEvent()) { 1187 break; 1188 } 1189 1190 const KeyEventBaseImpl &domKeyEv = static_cast<const KeyEventBaseImpl &>(ev); 1191 if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) { 1192 break; 1193 } 1194 1195 QKeyEvent *const ke = domKeyEv.qKeyEvent(); 1196 static_cast<EventPropagator *>(m_widget)->sendEvent(ke); 1197 ret = ke->isAccepted(); 1198 break; 1199 } 1200 case EventImpl::KEYPRESS_EVENT: { 1201 if (!ev.isKeyRelatedEvent()) { 1202 break; 1203 } 1204 1205 const KeyEventBaseImpl &domKeyEv = static_cast<const KeyEventBaseImpl &>(ev); 1206 if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) { 1207 break; 1208 } 1209 1210 // See KHTMLView::dispatchKeyEvent: autorepeat is just keypress in the DOM 1211 // but it's keyrelease+keypress in Qt. So here we do the inverse mapping as 1212 // the one done in KHTMLView: generate two events for one DOM auto-repeat keypress. 1213 // Similarly, DOM keypress events with non-autorepeat Qt event do nothing here, 1214 // because the matching Qt keypress event was already sent from DOM keydown event. 1215 1216 // Reverse drawing as the one in KHTMLView: 1217 // DOM: Down Press | Press | Up 1218 // Qt: (nothing) Press | Release(autorepeat) + Press(autorepeat) | Release 1219 // 1220 // Qt::KeyPress is sent for DOM keypress and not DOM keydown to allow 1221 // sites to block a key with onkeypress, #99749 1222 1223 QKeyEvent *const ke = domKeyEv.qKeyEvent(); 1224 if (ke->isAutoRepeat()) { 1225 QKeyEvent releaseEv(QEvent::KeyRelease, ke->key(), ke->modifiers(), 1226 ke->text(), ke->isAutoRepeat(), ke->count()); 1227 static_cast<EventPropagator *>(m_widget)->sendEvent(&releaseEv); 1228 } 1229 QWidget *fw = m_widget->focusWidget() ? m_widget->focusWidget() : m_widget; 1230 static_cast<EventPropagator *>(fw)->sendEvent(ke); 1231 ret = ke->isAccepted(); 1232 break; 1233 } 1234 case EventImpl::MOUSEOUT_EVENT: { 1235 QWidget *target = m_underMouse ? (QWidget *) m_underMouse : m_widget; 1236 QEvent moe(QEvent::Leave); 1237 QApplication::sendEvent(target, &moe); 1238 // qCDebug(KHTML_LOG) << "received MOUSEOUT, forwarding to" << target ; 1239 if (target->testAttribute(Qt::WA_Hover)) { 1240 QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), QPoint(0, 0)); 1241 QApplication::sendEvent(target, &he); 1242 } 1243 m_underMouse = nullptr; 1244 break; 1245 } 1246 case EventImpl::MOUSEOVER_EVENT: { 1247 QEvent moe(QEvent::Enter); 1248 QApplication::sendEvent(m_widget, &moe); 1249 // qCDebug(KHTML_LOG) << "received MOUSEOVER, forwarding to" << m_widget; 1250 if (m_widget->testAttribute(Qt::WA_Hover)) { 1251 QHoverEvent he(QEvent::HoverEnter, QPoint(0, 0), QPoint(-1, -1)); 1252 QApplication::sendEvent(m_widget, &he); 1253 } 1254 view()->part()->resetHoverText(); 1255 break; 1256 } 1257 default: 1258 break; 1259 } 1260 return ret; 1261 } 1262 1263 void RenderWidget::deref() 1264 { 1265 if (_ref) { 1266 _ref--; 1267 } 1268 // qDebug( "deref(%p): width get count is %d", this, _ref); 1269 if (!_ref) { 1270 if (attached()) { 1271 _ref++; 1272 detach(); // will perform the final deref. 1273 return; 1274 } 1275 SharedPtr<RenderArena> guard(m_arena); //Since delete on us gets called -first-, 1276 //before the arena free 1277 arenaDelete(m_arena.get()); 1278 } 1279 } 1280 1281 #ifdef ENABLE_DUMP 1282 void RenderWidget::dump(QTextStream &stream, const QString &ind) const 1283 { 1284 RenderReplaced::dump(stream, ind); 1285 if (widget()) 1286 stream << " color=" << widget()->palette().color(widget()->foregroundRole()).name() 1287 << " bg=" << widget()->palette().color(widget()->backgroundRole()).name(); 1288 else { 1289 stream << " null widget"; 1290 } 1291 } 1292 #endif 1293 1294 // ----------------------------------------------------------------------------- 1295 1296 QPoint KHTMLWidgetPrivate::absolutePos() 1297 { 1298 if (!m_rw) { 1299 return m_pos; 1300 } 1301 int x, y; 1302 m_rw->absolutePosition(x, y); 1303 x += m_rw->borderLeft() + m_rw->paddingLeft(); 1304 y += m_rw->borderTop() + m_rw->paddingTop(); 1305 return QPoint(x, y); 1306 } 1307 1308 KHTMLView *KHTMLWidgetPrivate::rootViewPos(QPoint &pos) 1309 { 1310 if (!m_rw || !m_rw->widget()) { 1311 pos = QPoint(); 1312 return nullptr; 1313 } 1314 pos = absolutePos(); 1315 KHTMLView *v = m_rw->view(); 1316 KHTMLView *last = nullptr; 1317 while (v) { 1318 last = v; 1319 int w, h = 0; 1320 v->applyTransforms(pos.rx(), pos.ry(), w, h); 1321 KHTMLWidget *kw = dynamic_cast<KHTMLWidget *>(v); 1322 if (!kw || !kw->m_kwp->isRedirected()) { 1323 break; 1324 } 1325 pos += kw->m_kwp->absolutePos(); 1326 v = v->part()->parentPart() ? v->part()->parentPart()->view() : nullptr; 1327 } 1328 return last; 1329 } 1330 1331 void KHTMLWidgetPrivate::setIsRedirected(bool b) 1332 { 1333 m_redirected = b; 1334 if (!b && m_rw && m_rw->widget()) { 1335 setInPaintEventFlag(m_rw->widget(), false); 1336 m_rw->widget()->setAttribute(Qt::WA_OpaquePaintEvent, false); 1337 m_rw->widget()->removeEventFilter(m_rw->view()); 1338 } 1339 } 1340 1341 // ----------------------------------------------------------------------------- 1342 1343 KHTMLWidget::KHTMLWidget() 1344 : m_kwp(new KHTMLWidgetPrivate()) {} 1345 1346 KHTMLWidget::~KHTMLWidget() 1347 { 1348 delete m_kwp; 1349 } 1350 1351 #include "moc_render_replaced.cpp"