KHtml

khtmlview.cpp
1 /* This file is part of the KDE project
2  *
3  * Copyright (C) 1998, 1999 Torben Weis <[email protected]>
4  * 1999 Lars Knoll <[email protected]>
5  * 1999 Antti Koivisto <[email protected]>
6  * 2000-2004 Dirk Mueller <[email protected]>
7  * 2003 Leo Savernik <[email protected]>
8  * 2003-2008 Apple Computer, Inc.
9  * 2008 Allan Sandfeld Jensen <[email protected]>
10  * 2006-2008 Germain Garand <[email protected]>
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB. If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27 
28 #include "khtmlview.h"
29 
30 #include "khtml_part.h"
31 #include "khtml_events.h"
32 #include <config-khtml.h>
33 #if HAVE_X11
34 #include <qx11info_x11.h>
35 #endif
36 
37 #include "html/html_documentimpl.h"
38 #include "html/html_inlineimpl.h"
39 #include "html/html_formimpl.h"
40 #include "html/htmltokenizer.h"
41 #include "editing/editor.h"
42 #include "rendering/render_arena.h"
43 #include "rendering/render_canvas.h"
44 #include "rendering/render_frames.h"
45 #include "rendering/render_replaced.h"
46 #include "rendering/render_form.h"
47 #include "rendering/render_layer.h"
48 #include "rendering/render_line.h"
49 #include "rendering/render_table.h"
50 // removeme
51 #define protected public
52 #include "rendering/render_text.h"
53 #undef protected
54 #include "xml/dom2_eventsimpl.h"
55 #include "css/cssstyleselector.h"
56 #include "misc/loader.h"
57 #include "khtml_settings.h"
58 #include "khtml_printsettings.h"
59 
60 #include "khtmlpart_p.h"
61 
62 #include <kcursor.h>
63 #include "khtml_debug.h"
64 #include <kiconloader.h>
65 #include <knotification.h>
66 #include <kconfig.h>
67 #include <../khtml_version.h>
68 
69 #include <kstringhandler.h>
70 #include <kconfiggroup.h>
71 #include <ksharedconfig.h>
72 
73 #include <QBitmap>
74 #include <QDialog>
75 #include <QDialogButtonBox>
76 #include <QLabel>
77 #include <QKeyEvent>
78 #include <QObject>
79 #include <QPainter>
80 #include <QHash>
81 #include <QToolTip>
82 #include <QString>
83 #include <QTextDocument>
84 #include <QTimer>
85 #include <QAbstractEventDispatcher>
86 #include <QVector>
87 #include <QAbstractScrollArea>
88 #include <QPrinter>
89 #include <QPrintDialog>
90 #include <qstandardpaths.h>
91 
92 //#define DEBUG_FLICKER
93 
94 #include <limits.h>
95 #if HAVE_X11
96 #include <X11/Xlib.h>
97 #include <fixx11h.h>
98 #elif defined(Q_OS_WIN)
99 #include <windows.h>
100 #endif
101 
102 #if 0
103 namespace khtml
104 {
105 void dumpLineBoxes(RenderFlow *flow);
106 }
107 #endif
108 
109 using namespace DOM;
110 using namespace khtml;
111 
112 #ifndef NDEBUG
113 static const int sFirstLayoutDelay = 520;
114 static const int sParsingLayoutsInterval = 380;
115 static const int sLayoutAttemptDelay = 300;
116 #else
117 static const int sFirstLayoutDelay = 280;
118 static const int sParsingLayoutsInterval = 320;
119 static const int sLayoutAttemptDelay = 200;
120 #endif
121 static const int sLayoutAttemptIncrement = 20;
122 static const int sParsingLayoutsIncrement = 60;
123 
124 static const int sSmoothScrollTime = 128;
125 static const int sSmoothScrollTick = 16;
126 static const int sSmoothScrollMinStaticPixels = 320 * 200;
127 
128 static const int sMaxMissedDeadlines = 12;
129 static const int sWayTooMany = -1;
130 
131 class KHTMLViewPrivate
132 {
133  friend class KHTMLView;
134 public:
135 
136  enum PseudoFocusNodes {
137  PFNone,
138  PFTop,
139  PFBottom
140  };
141 
142  enum StaticBackgroundState {
143  SBNone = 0,
144  SBPartial,
145  SBFull
146  };
147 
148  enum CompletedState {
149  CSNone = 0,
150  CSFull,
151  CSActionPending
152  };
153 
154  KHTMLViewPrivate(KHTMLView *v)
155  : underMouse(nullptr), underMouseNonShared(nullptr), oldUnderMouse(nullptr)
156  {
157  postponed_autorepeat = nullptr;
158  scrollingFromWheelTimerId = 0;
159  smoothScrollMode = KHTMLView::SSMWhenEfficient;
160 
161  reset();
162  vpolicy = Qt::ScrollBarAsNeeded;
163  hpolicy = Qt::ScrollBarAsNeeded;
164  formCompletions = nullptr;
165  prevScrollbarVisible = true;
166 
167  possibleTripleClick = false;
168  emitCompletedAfterRepaint = CSNone;
169  cursorIconWidget = nullptr;
170  cursorIconType = KHTMLView::LINK_NORMAL;
171  m_mouseScrollTimer = nullptr;
172  m_mouseScrollIndicator = nullptr;
173  contentsX = 0;
174  contentsY = 0;
175  view = v;
176  }
177  ~KHTMLViewPrivate()
178  {
179  delete formCompletions;
180  delete postponed_autorepeat;
181  if (underMouse) {
182  underMouse->deref();
183  }
184  if (underMouseNonShared) {
185  underMouseNonShared->deref();
186  }
187  if (oldUnderMouse) {
188  oldUnderMouse->deref();
189  }
190 
191  delete cursorIconWidget;
192  delete m_mouseScrollTimer;
193  delete m_mouseScrollIndicator;
194  }
195  void reset()
196  {
197  if (underMouse) {
198  underMouse->deref();
199  }
200  underMouse = nullptr;
201  if (underMouseNonShared) {
202  underMouseNonShared->deref();
203  }
204  underMouseNonShared = nullptr;
205  if (oldUnderMouse) {
206  oldUnderMouse->deref();
207  }
208  oldUnderMouse = nullptr;
209  linkPressed = false;
210  staticWidget = SBNone;
211  fixedObjectsCount = 0;
212  staticObjectsCount = 0;
213  tabMovePending = false;
214  lastTabbingDirection = true;
215  pseudoFocusNode = PFNone;
216  zoomLevel = 100;
217 #ifndef KHTML_NO_SCROLLBARS
218  //We don't turn off the toolbars here
219  //since if the user turns them
220  //off, then chances are they want them turned
221  //off always - even after a reset.
222 #else
223  vpolicy = ScrollBarAlwaysOff;
224  hpolicy = ScrollBarAlwaysOff;
225 #endif
226  scrollBarMoved = false;
227  contentsMoving = false;
228  ignoreWheelEvents = false;
229  scrollingFromWheel = QPoint(-1, -1);
230  borderX = 30;
231  borderY = 30;
232  steps = 0;
233  dx = dy = 0;
234  paged = false;
235  clickX = -1;
236  clickY = -1;
237  clickCount = 0;
238  isDoubleClick = false;
239  scrollingSelf = false;
240  delete postponed_autorepeat;
241  postponed_autorepeat = nullptr;
242  layoutTimerId = 0;
243  repaintTimerId = 0;
244  scrollTimerId = 0;
245  scrollSuspended = false;
246  scrollSuspendPreActivate = false;
247  smoothScrolling = false;
248  smoothScrollModeIsDefault = true;
249  shouldSmoothScroll = false;
250  smoothScrollMissedDeadlines = 0;
251  hasFrameset = false;
252  complete = false;
253  firstLayoutPending = true;
254 #ifdef SPEED_DEBUG
255  firstRepaintPending = true;
256 #endif
257  needsFullRepaint = true;
258  dirtyLayout = false;
259  layoutSchedulingEnabled = true;
260  painting = false;
261  layoutCounter = 0;
262  layoutAttemptCounter = 0;
263  scheduledLayoutCounter = 0;
264  updateRegion = QRegion();
265  m_dialogsAllowed = true;
266  accessKeysActivated = false;
267  accessKeysPreActivate = false;
268 
269  // the view might have been built before the part it will be assigned to,
270  // so exceptionally, we need to directly ref/deref KHTMLGlobal to
271  // account for this transitory case.
272  KHTMLGlobal::ref();
273  accessKeysEnabled = KHTMLGlobal::defaultHTMLSettings()->accessKeysEnabled();
274  KHTMLGlobal::deref();
275 
276  emitCompletedAfterRepaint = CSNone;
277  m_mouseEventsTarget = nullptr;
278  m_clipHolder = nullptr;
279  }
280  void newScrollTimer(QWidget *view, int tid)
281  {
282  //qCDebug(KHTML_LOG) << "newScrollTimer timer " << tid;
283  view->killTimer(scrollTimerId);
284  scrollTimerId = tid;
285  scrollSuspended = false;
286  }
287  enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
288 
289  void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
290  {
291  static const struct {
292  int msec, pixels;
293  } timings [] = {
294  {320, 1}, {224, 1}, {160, 1}, {112, 1}, {80, 1}, {56, 1}, {40, 1},
295  {28, 1}, {20, 1}, {20, 2}, {20, 3}, {20, 4}, {20, 6}, {20, 8}, {0, 0}
296  };
297  if (!scrollTimerId ||
298  (static_cast<int>(scrollDirection) != direction &&
299  (static_cast<int>(scrollDirection) != oppositedir || scrollSuspended))) {
300  scrollTiming = 6;
301  scrollBy = timings[scrollTiming].pixels;
302  scrollDirection = direction;
303  newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
304  } else if (scrollDirection == direction &&
305  timings[scrollTiming + 1].msec && !scrollSuspended) {
306  scrollBy = timings[++scrollTiming].pixels;
307  newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
308  } else if (scrollDirection == oppositedir) {
309  if (scrollTiming) {
310  scrollBy = timings[--scrollTiming].pixels;
311  newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
312  }
313  }
314  scrollSuspended = false;
315  }
316 
317  bool haveZoom() const
318  {
319  return zoomLevel != 100;
320  }
321 
322  void startScrolling()
323  {
324  smoothScrolling = true;
325  smoothScrollTimer.start(sSmoothScrollTick);
326  shouldSmoothScroll = false;
327  }
328 
329  void stopScrolling()
330  {
331  smoothScrollTimer.stop();
332  dx = dy = 0;
333  steps = 0;
334  updateContentsXY();
335  smoothScrolling = false;
336  shouldSmoothScroll = false;
337  }
338 
339  void updateContentsXY()
340  {
341  contentsX = QApplication::isRightToLeft() ?
342  view->horizontalScrollBar()->maximum() - view->horizontalScrollBar()->value() : view->horizontalScrollBar()->value();
343  contentsY = view->verticalScrollBar()->value();
344  }
345  void scrollAccessKeys(int dx, int dy)
346  {
347  QList<QLabel *> wl = view->widget()->findChildren<QLabel *>("KHTMLAccessKey");
348  foreach (QLabel *w, wl) {
349  w->move(w->pos() + QPoint(dx, dy));
350  }
351  }
352  void scrollExternalWidgets(int dx, int dy)
353  {
354  if (visibleWidgets.isEmpty()) {
355  return;
356  }
357 
358  QHashIterator<void *, QWidget *> it(visibleWidgets);
359  while (it.hasNext()) {
360  it.next();
361  it.value()->move(it.value()->pos() + QPoint(dx, dy));
362  }
363  }
364 
365  NodeImpl *underMouse;
366  NodeImpl *underMouseNonShared;
367  NodeImpl *oldUnderMouse;
368 
369  // Do not adjust bitfield enums sizes.
370  // They are oversized because they are signed on some platforms.
371  bool tabMovePending: 1;
372  bool lastTabbingDirection: 1;
373  PseudoFocusNodes pseudoFocusNode: 3;
374  bool scrollBarMoved: 1;
375  bool contentsMoving: 1;
376 
377  Qt::ScrollBarPolicy vpolicy;
378  Qt::ScrollBarPolicy hpolicy;
379  bool prevScrollbarVisible: 1;
380  bool linkPressed: 1;
381  bool ignoreWheelEvents: 1;
382  StaticBackgroundState staticWidget: 3;
383  int staticObjectsCount;
384  int fixedObjectsCount;
385 
386  int zoomLevel;
387  int borderX, borderY;
388  int dx, dy;
389  int steps;
390  KConfig *formCompletions;
391 
392  int clickX, clickY, clickCount;
393  bool isDoubleClick;
394 
395  bool paged;
396 
397  bool scrollingSelf;
398  int contentsX, contentsY;
399  int layoutTimerId;
400  QKeyEvent *postponed_autorepeat;
401 
402  int repaintTimerId;
403  int scrollTimerId;
404  int scrollTiming;
405  int scrollBy;
406  ScrollDirection scrollDirection : 3;
407  bool scrollSuspended : 1;
408  bool scrollSuspendPreActivate : 1;
409  KHTMLView::SmoothScrollingMode smoothScrollMode : 3;
410  bool smoothScrolling : 1;
411  bool smoothScrollModeIsDefault : 1;
412  bool shouldSmoothScroll : 1;
413  bool hasFrameset : 1;
414  bool complete : 1;
415  bool firstLayoutPending : 1;
416 #ifdef SPEED_DEBUG
417  bool firstRepaintPending : 1;
418 #endif
419  bool layoutSchedulingEnabled : 1;
420  bool needsFullRepaint : 1;
421  bool painting : 1;
422  bool possibleTripleClick : 1;
423  bool dirtyLayout : 1;
424  bool m_dialogsAllowed : 1;
425  short smoothScrollMissedDeadlines;
426  int layoutCounter;
427  int layoutAttemptCounter;
428  int scheduledLayoutCounter;
429  QRegion updateRegion;
430  QTimer smoothScrollTimer;
431  QTime smoothScrollStopwatch;
432  QHash<void *, QWidget *> visibleWidgets;
433  bool accessKeysEnabled;
434  bool accessKeysActivated;
435  bool accessKeysPreActivate;
436  CompletedState emitCompletedAfterRepaint;
437 
438  QLabel *cursorIconWidget;
439  KHTMLView::LinkCursor cursorIconType;
440 
441  // scrolling activated by MMB
442  short m_mouseScroll_byX;
443  short m_mouseScroll_byY;
444  QPoint scrollingFromWheel;
445  int scrollingFromWheelTimerId;
446  QTimer *m_mouseScrollTimer;
447  QWidget *m_mouseScrollIndicator;
448  QPointer<QWidget> m_mouseEventsTarget;
449  QStack<QRegion> *m_clipHolder;
450  KHTMLView *view;
451 };
452 
453 #ifndef QT_NO_TOOLTIP
454 
455 /** calculates the client-side image map rectangle for the given image element
456  * @param img image element
457  * @param scrollOfs scroll offset of viewport in content coordinates
458  * @param p position to be probed in viewport coordinates
459  * @param r returns the bounding rectangle in content coordinates
460  * @param s returns the title string
461  * @return true if an appropriate area was found -- only in this case r and
462  * s are valid, false otherwise
463  */
464 static bool findImageMapRect(HTMLImageElementImpl *img, const QPoint &scrollOfs,
465  const QPoint &p, QRect &r, QString &s)
466 {
467  HTMLMapElementImpl *map;
468  if (img && img->document()->isHTMLDocument() &&
469  (map = static_cast<HTMLDocumentImpl *>(img->document())->getMap(img->imageMap()))) {
470  RenderObject::NodeInfo info(true, false);
471  RenderObject *rend = img->renderer();
472  int ax, ay;
473  if (!rend || !rend->absolutePosition(ax, ay)) {
474  return false;
475  }
476  // we're a client side image map
477  bool inside = map->mapMouseEvent(p.x() - ax + scrollOfs.x(),
478  p.y() - ay + scrollOfs.y(), rend->contentWidth(),
479  rend->contentHeight(), info);
480  if (inside && info.URLElement()) {
481  HTMLAreaElementImpl *area = static_cast<HTMLAreaElementImpl *>(info.URLElement());
482  Q_ASSERT(area->id() == ID_AREA);
483  s = area->getAttribute(ATTR_TITLE).string();
484  QRegion reg = area->cachedRegion();
485  if (!s.isEmpty() && !reg.isEmpty()) {
486  r = reg.boundingRect();
487  r.translate(ax, ay);
488  return true;
489  }
490  }
491  }
492  return false;
493 }
494 
495 bool KHTMLView::event(QEvent *e)
496 {
497  switch (e->type()) {
498  case QEvent::ToolTip: {
499  QHelpEvent *he = static_cast<QHelpEvent *>(e);
500  QPoint p = he->pos();
501 
502  DOM::NodeImpl *node = d->underMouseNonShared;
503  QRect region;
504  while (node) {
505  if (node->isElementNode()) {
506  DOM::ElementImpl *e = static_cast<DOM::ElementImpl *>(node);
507  QRect r;
508  QString s;
509  bool found = false;
510  // for images, check if it is part of a client-side image map,
511  // and query the <area>s' title attributes, too
512  if (e->id() == ID_IMG && !e->getAttribute(ATTR_USEMAP).isEmpty()) {
513  found = findImageMapRect(static_cast<HTMLImageElementImpl *>(e),
514  viewportToContents(QPoint(0, 0)), p, r, s);
515  }
516  if (!found) {
517  s = e->getAttribute(ATTR_TITLE).string().trimmed();
518  r = node->getRect();
519  }
520  region |= QRect(contentsToViewport(r.topLeft()), r.size());
521  if (!s.isEmpty()) {
524  widget(), region);
525  break;
526  }
527  }
528  node = node->parentNode();
529  }
530  // Qt makes tooltip events happen nearly immediately when a preceding one was processed in the past few seconds.
531  // We don't want that feature to apply to web tootlips however, as it clashes with dhtml menus.
532  // So we'll just pretend we did not process that event.
533  return false;
534  }
535 
536  case QEvent::DragEnter:
537  case QEvent::DragMove:
538  case QEvent::DragLeave:
539  case QEvent::Drop:
540  // In Qt4, one needs to both call accept() on the DND event and return
541  // true on ::event for the candidate widget for the drop to be possible.
542  // Apps hosting us, such as konq, can do the former but not the later.
543  // We will do the second bit, as it's a no-op unless someone else explicitly
544  // accepts the event. We need to skip the scrollarea to do that,
545  // since it will just skip the events, both killing the drop, and
546  // not permitting us to forward it up the part hiearchy in our dragEnterEvent,
547  // etc. handlers
548  return QWidget::event(e);
549  case QEvent::StyleChange:
550  case QEvent::LayoutRequest: {
551  updateScrollBars();
552  return QAbstractScrollArea::event(e);
553  }
555  slotPaletteChanged();
556  return QScrollArea::event(e);
557  default:
558  return QScrollArea::event(e);
559  }
560 }
561 #endif
562 
564  : QScrollArea(parent), d(new KHTMLViewPrivate(this))
565 {
566  m_medium = "screen";
567 
568  m_part = part;
569 
572 
573  initWidget();
574  widget()->setMouseTracking(true);
575 }
576 
577 KHTMLView::~KHTMLView()
578 {
579  closeChildDialogs();
580  if (m_part) {
581  DOM::DocumentImpl *doc = m_part->xmlDocImpl();
582  if (doc) {
583  doc->detach();
584  }
585  }
586  delete d;
587 }
588 
589 void KHTMLView::setPart(KHTMLPart *part)
590 {
591  assert(part && !m_part);
592  m_part = part;
593 }
594 
595 void KHTMLView::initWidget()
596 {
597  // Do not access the part here. It might not be fully constructed.
598 
601  viewport()->setFocusProxy(this);
602 
603  _marginWidth = -1; // undefined
604  _marginHeight = -1;
605  _width = 0;
606  _height = 0;
607 
608  installEventFilter(this);
609 
610  setAcceptDrops(true);
611  if (!widget()) {
612  setWidget(new QWidget(this));
613  }
615 
616  // Do *not* remove this attribute frivolously.
617  // You might not notice a change of behaviour in Debug builds
618  // but removing opaque events will make QWidget::scroll fail horribly
619  // in Release builds.
621 
624 
625  connect(&d->smoothScrollTimer, SIGNAL(timeout()), this, SLOT(scrollTick()));
626 }
627 
628 void KHTMLView::resizeContentsToViewport()
629 {
630  QSize s = viewport()->size();
631  resizeContents(s.width(), s.height());
632 }
633 
634 // called by KHTMLPart::clear()
635 void KHTMLView::clear()
636 {
637  if (d->accessKeysEnabled && d->accessKeysActivated) {
638  accessKeysTimeout();
639  }
640  viewport()->unsetCursor();
641  if (d->cursorIconWidget) {
642  d->cursorIconWidget->hide();
643  }
644  if (d->smoothScrolling) {
645  d->stopScrolling();
646  }
647  d->reset();
649  emit cleared();
650 
653  verticalScrollBar()->setEnabled(false);
655 
656 }
657 
658 void KHTMLView::hideEvent(QHideEvent *e)
659 {
661 }
662 
663 void KHTMLView::showEvent(QShowEvent *e)
664 {
666 }
667 
668 void KHTMLView::setMouseEventsTarget(QWidget *w)
669 {
670  d->m_mouseEventsTarget = w;
671 }
672 
673 QWidget *KHTMLView::mouseEventsTarget() const
674 {
675  return d->m_mouseEventsTarget;
676 }
677 
678 void KHTMLView::setClipHolder(QStack<QRegion> *ch)
679 {
680  d->m_clipHolder = ch;
681 }
682 
683 QStack<QRegion> *KHTMLView::clipHolder() const
684 {
685  return d->m_clipHolder;
686 }
687 
689 {
690  return widget() ? widget()->width() : 0;
691 }
692 
694 {
695  return widget() ? widget()->height() : 0;
696 }
697 
698 void KHTMLView::resizeContents(int w, int h)
699 {
700  if (!widget()) {
701  return;
702  }
703  widget()->resize(w, h);
704  if (!widget()->isVisible()) {
705  updateScrollBars();
706  }
707 }
708 
710 {
711  return d->contentsX;
712 }
713 
715 {
716  return d->contentsY;
717 }
718 
720 {
721  if (m_kwp->isRedirected()) {
722  // our RenderWidget knows better
723  if (RenderWidget *rw = m_kwp->renderWidget()) {
724  int ret = rw->width() - rw->paddingLeft() - rw->paddingRight() - rw->borderLeft() - rw->borderRight();
725  if (verticalScrollBar()->isVisible()) {
726  ret -= verticalScrollBar()->sizeHint().width();
727  ret = qMax(0, ret);
728  }
729  return ret;
730  }
731  }
732  return viewport()->width();
733 }
734 
736 {
737  if (m_kwp->isRedirected()) {
738  // our RenderWidget knows better
739  if (RenderWidget *rw = m_kwp->renderWidget()) {
740  int ret = rw->height() - rw->paddingBottom() - rw->paddingTop() - rw->borderTop() - rw->borderBottom();
741  if (horizontalScrollBar()->isVisible()) {
742  ret -= horizontalScrollBar()->sizeHint().height();
743  ret = qMax(0, ret);
744  }
745  return ret;
746  }
747  }
748  return viewport()->height();
749 }
750 
752 {
754  horizontalScrollBar()->maximum() - x : x);
756 }
757 
758 void KHTMLView::scrollBy(int x, int y)
759 {
760  if (d->scrollTimerId) {
761  d->newScrollTimer(this, 0);
762  }
764  verticalScrollBar()->setValue(verticalScrollBar()->value() + y);
765 }
766 
768 {
769  return QPoint(p.x() - contentsX(), p.y() - contentsY());
770 }
771 
772 void KHTMLView::contentsToViewport(int x, int y, int &cx, int &cy) const
773 {
774  QPoint p(x, y);
775  p = contentsToViewport(p);
776  cx = p.x();
777  cy = p.y();
778 }
779 
781 {
782  return QPoint(p.x() + contentsX(), p.y() + contentsY());
783 }
784 
785 void KHTMLView::viewportToContents(int x, int y, int &cx, int &cy) const
786 {
787  QPoint p(x, y);
788  p = viewportToContents(p);
789  cx = p.x();
790  cy = p.y();
791 }
792 
793 void KHTMLView::updateContents(int x, int y, int w, int h)
794 {
795  applyTransforms(x, y, w, h);
796  if (m_kwp->isRedirected()) {
797  QPoint off = m_kwp->absolutePos();
798  KHTMLView *pview = m_part->parentPart()->view();
799  pview->updateContents(x + off.x(), y + off.y(), w, h);
800  } else {
801  widget()->update(x, y, w, h);
802  }
803 }
804 
806 {
807  updateContents(r.x(), r.y(), r.width(), r.height());
808 }
809 
810 void KHTMLView::repaintContents(int x, int y, int w, int h)
811 {
812  applyTransforms(x, y, w, h);
813  if (m_kwp->isRedirected()) {
814  QPoint off = m_kwp->absolutePos();
815  KHTMLView *pview = m_part->parentPart()->view();
816  pview->repaintContents(x + off.x(), y + off.y(), w, h);
817  } else {
818  widget()->repaint(x, y, w, h);
819  }
820 }
821 
823 {
824  repaintContents(r.x(), r.y(), r.width(), r.height());
825 }
826 
827 void KHTMLView::applyTransforms(int &x, int &y, int &w, int &h) const
828 {
829  if (d->haveZoom()) {
830  const int z = d->zoomLevel;
831  x = x * z / 100;
832  y = y * z / 100;
833  w = w * z / 100;
834  h = h * z / 100;
835  }
836  x -= contentsX();
837  y -= contentsY();
838 }
839 
840 void KHTMLView::revertTransforms(int &x, int &y, int &w, int &h) const
841 {
842  x += contentsX();
843  y += contentsY();
844  if (d->haveZoom()) {
845  const int z = d->zoomLevel;
846  x = x * 100 / z;
847  y = y * 100 / z;
848  w = w * 100 / z;
849  h = h * 100 / z;
850  }
851 }
852 
853 void KHTMLView::revertTransforms(int &x, int &y) const
854 {
855  int dummy = 0;
856  revertTransforms(x, y, dummy, dummy);
857 }
858 
859 void KHTMLView::resizeEvent(QResizeEvent * /*e*/)
860 {
861  updateScrollBars();
862 
863  // If we didn't load anything, make white area as big as the view
864  if (!m_part->xmlDocImpl()) {
865  resizeContentsToViewport();
866  }
867 
868  // Viewport-dependent media queries may cause us to need completely different style information.
869  if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->styleSelector()->affectedByViewportChange()) {
870  m_part->xmlDocImpl()->updateStyleSelector();
871  }
872 
873  if (d->layoutSchedulingEnabled) {
874  layout();
875  }
876 
878 
879  if (m_part && m_part->xmlDocImpl()) {
880  if (m_part->parentPart()) {
881  // sub-frame : queue the resize event until our toplevel is done layouting
882  khtml::ChildFrame *cf = m_part->parentPart()->frame(m_part);
883  if (cf && !cf->m_partContainerElement.isNull()) {
884  cf->m_partContainerElement.data()->postResizeEvent();
885  }
886  } else {
887  // toplevel : dispatch sub-frames'resize events before our own
888  HTMLPartContainerElementImpl::sendPostedResizeEvents();
889  m_part->xmlDocImpl()->dispatchWindowEvent(EventImpl::RESIZE_EVENT, false, false);
890  }
891  }
892 }
893 
894 void KHTMLView::paintEvent(QPaintEvent *e)
895 {
896  QRect r = e->rect();
898  QPoint off(contentsX(), contentsY());
899  r.translate(off);
900  r = r.intersected(v);
901  if (!r.isValid() || r.isEmpty()) {
902  return;
903  }
904 
905  QPainter p(widget());
906  p.translate(-off);
907 
908  if (d->haveZoom()) {
909  p.scale(d->zoomLevel / 100., d->zoomLevel / 100.);
910 
911  r.setX(r.x() * 100 / d->zoomLevel);
912  r.setY(r.y() * 100 / d->zoomLevel);
913  r.setWidth(r.width() * 100 / d->zoomLevel);
914  r.setHeight(r.height() * 100 / d->zoomLevel);
915  r.adjust(-1, -1, 1, 1);
916  }
917  p.setClipRect(r);
918 
919  int ex = r.x();
920  int ey = r.y();
921  int ew = r.width();
922  int eh = r.height();
923 
924  if (!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
925  p.fillRect(ex, ey, ew, eh, palette().brush(QPalette::Active, QPalette::Base));
926  return;
927  } else if (d->complete && static_cast<RenderCanvas *>(m_part->xmlDocImpl()->renderer())->needsLayout()) {
928  // an external update request happens while we have a layout scheduled
929  unscheduleRelayout();
930  layout();
931  } else if (m_part->xmlDocImpl()->tokenizer()) {
932  m_part->xmlDocImpl()->tokenizer()->setNormalYieldDelay();
933  }
934 
935  if (d->painting) {
936  // qCDebug(KHTML_LOG) << "WARNING: paintEvent reentered! ";
937  return;
938  }
939  d->painting = true;
940 
941  m_part->xmlDocImpl()->renderer()->layer()->paint(&p, r);
942 
943  if (d->hasFrameset) {
944  NodeImpl *body = static_cast<HTMLDocumentImpl *>(m_part->xmlDocImpl())->body();
945  if (body && body->renderer() && body->id() == ID_FRAMESET) {
946  static_cast<RenderFrameSet *>(body->renderer())->paintFrameSetRules(&p, r);
947  } else {
948  d->hasFrameset = false;
949  }
950  }
951 
952  khtml::DrawContentsEvent event(&p, ex, ey, ew, eh);
953  QApplication::sendEvent(m_part, &event);
954 
955  if (d->contentsMoving && !d->smoothScrolling && widget()->underMouse()) {
958  QApplication::postEvent(widget(), tempEvent);
959  }
960 #ifdef SPEED_DEBUG
961  if (d->firstRepaintPending && !m_part->parentPart()) {
962  qCDebug(KHTML_LOG) << "FIRST PAINT:" << m_part->d->m_parsetime.elapsed();
963  }
964  d->firstRepaintPending = false;
965 #endif
966  d->painting = false;
967 }
968 
970 {
971  // make it update the rendering area when set
972  _marginWidth = w;
973 }
974 
975 void KHTMLView::setMarginHeight(int h)
976 {
977  // make it update the rendering area when set
978  _marginHeight = h;
979 }
980 
982 {
983  if (m_part && m_part->xmlDocImpl()) {
984  DOM::DocumentImpl *document = m_part->xmlDocImpl();
985 
986  khtml::RenderCanvas *canvas = static_cast<khtml::RenderCanvas *>(document->renderer());
987  if (!canvas) {
988  return;
989  }
990 
991  d->layoutSchedulingEnabled = false;
992  d->dirtyLayout = true;
993 
994  // the reference object for the overflow property on canvas
995  RenderObject *ref = nullptr;
996  RenderObject *root = document->documentElement() ? document->documentElement()->renderer() : nullptr;
997 
998  if (document->isHTMLDocument()) {
999  NodeImpl *body = static_cast<HTMLDocumentImpl *>(document)->body();
1000  if (body && body->renderer() && body->id() == ID_FRAMESET) {
1003  body->renderer()->setNeedsLayout(true);
1004  d->hasFrameset = true;
1005  } else if (root) { // only apply body's overflow to canvas if root has a visible overflow
1006  ref = (!body || root->style()->hidesOverflow()) ? root : body->renderer();
1007  }
1008  } else {
1009  ref = root;
1010  }
1011  if (ref) {
1012  if (ref->style()->overflowX() == OHIDDEN) {
1013  if (d->hpolicy == Qt::ScrollBarAsNeeded) {
1015  }
1016  } else if (ref->style()->overflowX() == OSCROLL) {
1017  if (d->hpolicy == Qt::ScrollBarAsNeeded) {
1019  }
1020  } else if (horizontalScrollBarPolicy() != d->hpolicy) {
1022  }
1023  if (ref->style()->overflowY() == OHIDDEN) {
1024  if (d->vpolicy == Qt::ScrollBarAsNeeded) {
1026  }
1027  } else if (ref->style()->overflowY() == OSCROLL) {
1028  if (d->vpolicy == Qt::ScrollBarAsNeeded) {
1030  }
1031  } else if (verticalScrollBarPolicy() != d->vpolicy) {
1033  }
1034  }
1035  d->needsFullRepaint = d->firstLayoutPending;
1036  if (_height != visibleHeight() || _width != visibleWidth()) {
1037  ;
1038  d->needsFullRepaint = true;
1039  _height = visibleHeight();
1040  _width = visibleWidth();
1041  }
1042 
1043  canvas->layout();
1044 
1045  emit finishedLayout();
1046  if (d->firstLayoutPending) {
1047  // make sure firstLayoutPending is set to false now in case this layout
1048  // wasn't scheduled
1049  d->firstLayoutPending = false;
1050  verticalScrollBar()->setEnabled(true);
1052  }
1053  d->layoutCounter++;
1054 
1055  if (d->accessKeysEnabled && d->accessKeysActivated) {
1056  emit hideAccessKeys();
1058  }
1059  } else {
1060  _width = visibleWidth();
1061  }
1062 
1063  if (d->layoutTimerId) {
1064  killTimer(d->layoutTimerId);
1065  }
1066  d->layoutTimerId = 0;
1067  d->layoutSchedulingEnabled = true;
1068 }
1069 
1070 void KHTMLView::closeChildDialogs()
1071 {
1072  QList<QDialog *> dlgs = findChildren<QDialog *>();
1073  foreach (QDialog *dlg, dlgs) {
1074  if (dlg->testAttribute(Qt::WA_ShowModal)) {
1075  // qCDebug(KHTML_LOG) << "closeChildDialogs: closing dialog " << dlg;
1076  // close() ends up calling QButton::animateClick, which isn't immediate
1077  // we need something the exits the event loop immediately (#49068)
1078  dlg->reject();
1079  }
1080  }
1081  d->m_dialogsAllowed = false;
1082 }
1083 
1084 bool KHTMLView::dialogsAllowed()
1085 {
1086  bool allowed = d->m_dialogsAllowed;
1087  KHTMLPart *p = m_part->parentPart();
1088  if (p && p->view()) {
1089  allowed &= p->view()->dialogsAllowed();
1090  }
1091  return allowed;
1092 }
1093 
1094 void KHTMLView::closeEvent(QCloseEvent *ev)
1095 {
1096  closeChildDialogs();
1098 }
1099 
1100 void KHTMLView::setZoomLevel(int percent)
1101 {
1102  percent = percent < 20 ? 20 : (percent > 800 ? 800 : percent);
1103  int oldpercent = d->zoomLevel;
1104  d->zoomLevel = percent;
1105  if (percent != oldpercent) {
1106  if (d->layoutSchedulingEnabled) {
1107  layout();
1108  }
1109  widget()->update();
1110  }
1111 }
1112 
1114 {
1115  return d->zoomLevel;
1116 }
1117 
1119 {
1120  d->smoothScrollMode = m;
1121  d->smoothScrollModeIsDefault = false;
1122  if (d->smoothScrolling && !m) {
1123  d->stopScrolling();
1124  }
1125 }
1126 
1127 void KHTMLView::setSmoothScrollingModeDefault(SmoothScrollingMode m)
1128 {
1129  // check for manual override
1130  if (!d->smoothScrollModeIsDefault) {
1131  return;
1132  }
1133  d->smoothScrollMode = m;
1134  if (d->smoothScrolling && !m) {
1135  d->stopScrolling();
1136  }
1137 }
1138 
1140 {
1141  return d->smoothScrollMode;
1142 }
1143 
1144 //
1145 // Event Handling
1146 //
1147 /////////////////
1148 
1149 void KHTMLView::mousePressEvent(QMouseEvent *_mouse)
1150 {
1151  if (!m_part->xmlDocImpl()) {
1152  return;
1153  }
1154  if (d->possibleTripleClick && (_mouse->button() & Qt::MouseButtonMask) == Qt::LeftButton) {
1155  mouseDoubleClickEvent(_mouse); // it handles triple clicks too
1156  return;
1157  }
1158 
1159  int xm = _mouse->x();
1160  int ym = _mouse->y();
1161  revertTransforms(xm, ym);
1162 
1163  // qCDebug(KHTML_LOG) << "mousePressEvent: viewport=("<<_mouse->x()-contentsX()<<"/"<<_mouse->y()-contentsY()<<"), contents=(" << xm << "/" << ym << ")\n";
1164 
1165  d->isDoubleClick = false;
1166 
1167  DOM::NodeImpl::MouseEvent mev(_mouse->buttons(), DOM::NodeImpl::MousePress);
1168  m_part->xmlDocImpl()->prepareMouseEvent(false, xm, ym, &mev);
1169 
1170  //qCDebug(KHTML_LOG) << "innerNode="<<mev.innerNode.nodeName().string();
1171 
1172  if ((_mouse->button() == Qt::MidButton) &&
1173  !m_part->d->m_bOpenMiddleClick && !d->m_mouseScrollTimer &&
1174  mev.url.isNull() && (mev.innerNode.elementId() != ID_INPUT)) {
1175  QPoint point = mapFromGlobal(_mouse->globalPos());
1176 
1177  d->m_mouseScroll_byX = 0;
1178  d->m_mouseScroll_byY = 0;
1179 
1180  d->m_mouseScrollTimer = new QTimer(this);
1181  connect(d->m_mouseScrollTimer, SIGNAL(timeout()), this, SLOT(slotMouseScrollTimer()));
1182 
1183  if (!d->m_mouseScrollIndicator) {
1184  QPixmap pixmap(48, 48), icon;
1185  pixmap.fill(QColor(qRgba(127, 127, 127, 127)));
1186 
1187  QPainter p(&pixmap);
1188  QStyleOption option;
1189 
1190  option.rect.setRect(16, 0, 16, 16);
1192  option.rect.setRect(0, 16, 16, 16);
1194  option.rect.setRect(16, 32, 16, 16);
1196  option.rect.setRect(32, 16, 16, 16);
1198  p.drawEllipse(23, 23, 2, 2);
1199 
1200  d->m_mouseScrollIndicator = new QWidget(this);
1201  d->m_mouseScrollIndicator->setFixedSize(48, 48);
1202  QPalette palette;
1203  palette.setBrush(d->m_mouseScrollIndicator->backgroundRole(), QBrush(pixmap));
1204  d->m_mouseScrollIndicator->setPalette(palette);
1205  }
1206  d->m_mouseScrollIndicator->move(point.x() - 24, point.y() - 24);
1207 
1208  bool hasHorBar = visibleWidth() < contentsWidth();
1209  bool hasVerBar = visibleHeight() < contentsHeight();
1210 
1211  KConfigGroup cg(KSharedConfig::openConfig(), "HTML Settings");
1212  if (cg.readEntry("ShowMouseScrollIndicator", true)) {
1213  d->m_mouseScrollIndicator->show();
1214  d->m_mouseScrollIndicator->unsetCursor();
1215 
1216  QBitmap mask = d->m_mouseScrollIndicator->palette().brush(d->m_mouseScrollIndicator->backgroundRole()).texture().createHeuristicMask(true);
1217 
1218  if (hasHorBar && !hasVerBar) {
1219  QBitmap bm(16, 16);
1220  bm.clear();
1221  QPainter painter(&mask);
1222  painter.drawPixmap(QRectF(16, 0, bm.width(), bm.height()), bm, bm.rect());
1223  painter.drawPixmap(QRectF(16, 32, bm.width(), bm.height()), bm, bm.rect());
1224  d->m_mouseScrollIndicator->setCursor(Qt::SizeHorCursor);
1225  } else if (!hasHorBar && hasVerBar) {
1226  QBitmap bm(16, 16);
1227  bm.clear();
1228  QPainter painter(&mask);
1229  painter.drawPixmap(QRectF(0, 16, bm.width(), bm.height()), bm, bm.rect());
1230  painter.drawPixmap(QRectF(32, 16, bm.width(), bm.height()), bm, bm.rect());
1231  d->m_mouseScrollIndicator->setCursor(Qt::SizeVerCursor);
1232  } else {
1233  d->m_mouseScrollIndicator->setCursor(Qt::SizeAllCursor);
1234  }
1235 
1236  d->m_mouseScrollIndicator->setMask(mask);
1237  } else {
1238  if (hasHorBar && !hasVerBar) {
1240  } else if (!hasHorBar && hasVerBar) {
1242  } else {
1244  }
1245  }
1246 
1247  return;
1248  } else if (d->m_mouseScrollTimer) {
1249  delete d->m_mouseScrollTimer;
1250  d->m_mouseScrollTimer = nullptr;
1251 
1252  if (d->m_mouseScrollIndicator) {
1253  d->m_mouseScrollIndicator->hide();
1254  }
1255  }
1256 
1257  if (d->clickCount > 0 &&
1258  QPoint(d->clickX - xm, d->clickY - ym).manhattanLength() <= QApplication::startDragDistance()) {
1259  d->clickCount++;
1260  } else {
1261  d->clickCount = 1;
1262  d->clickX = xm;
1263  d->clickY = ym;
1264  }
1265 
1266  bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT, mev.innerNode.handle(), mev.innerNonSharedNode.handle(), true,
1267  d->clickCount, _mouse, true, DOM::NodeImpl::MousePress);
1268 
1269  if (!swallowEvent) {
1270  emit m_part->nodeActivated(mev.innerNode);
1271 
1272  khtml::MousePressEvent event(_mouse, xm, ym, mev.url, mev.target, mev.innerNode);
1273  QApplication::sendEvent(m_part, &event);
1274  // we might be deleted after this
1275  }
1276 }
1277 
1278 void KHTMLView::mouseDoubleClickEvent(QMouseEvent *_mouse)
1279 {
1280  if (!m_part->xmlDocImpl()) {
1281  return;
1282  }
1283 
1284  int xm = _mouse->x();
1285  int ym = _mouse->y();
1286  revertTransforms(xm, ym);
1287 
1288  // qCDebug(KHTML_LOG) << "mouseDblClickEvent: x=" << xm << ", y=" << ym;
1289 
1290  d->isDoubleClick = true;
1291 
1292  DOM::NodeImpl::MouseEvent mev(_mouse->buttons(), DOM::NodeImpl::MouseDblClick);
1293  m_part->xmlDocImpl()->prepareMouseEvent(false, xm, ym, &mev);
1294 
1295  // We do the same thing as mousePressEvent() here, since the DOM does not treat
1296  // single and double-click events as separate (only the detail, i.e. number of clicks differs)
1297  if (d->clickCount > 0 &&
1298  QPoint(d->clickX - xm, d->clickY - ym).manhattanLength() <= QApplication::startDragDistance()) {
1299  d->clickCount++;
1300  } else { // shouldn't happen, if Qt has the same criterias for double clicks.
1301  d->clickCount = 1;
1302  d->clickX = xm;
1303  d->clickY = ym;
1304  }
1305  bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT, mev.innerNode.handle(), mev.innerNonSharedNode.handle(), true,
1306  d->clickCount, _mouse, true, DOM::NodeImpl::MouseDblClick);
1307 
1308  if (!swallowEvent) {
1309  khtml::MouseDoubleClickEvent event(_mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount);
1310  QApplication::sendEvent(m_part, &event);
1311  }
1312 
1313  d->possibleTripleClick = true;
1314  QTimer::singleShot(QApplication::doubleClickInterval(), this, SLOT(tripleClickTimeout()));
1315 }
1316 
1317 void KHTMLView::tripleClickTimeout()
1318 {
1319  d->possibleTripleClick = false;
1320  d->clickCount = 0;
1321 }
1322 
1323 static bool targetOpensNewWindow(KHTMLPart *part, QString target)
1324 {
1325  if (!target.isEmpty() && (target.toLower() != "_top") &&
1326  (target.toLower() != "_self") && (target.toLower() != "_parent")) {
1327  if (target.toLower() == "_blank") {
1328  return true;
1329  } else {
1330  while (part->parentPart()) {
1331  part = part->parentPart();
1332  }
1333  if (!part->frameExists(target)) {
1334  return true;
1335  }
1336  }
1337  }
1338  return false;
1339 }
1340 
1341 void KHTMLView::mouseMoveEvent(QMouseEvent *_mouse)
1342 {
1343  if (d->m_mouseScrollTimer) {
1344  QPoint point = mapFromGlobal(_mouse->globalPos());
1345 
1346  int deltaX = point.x() - d->m_mouseScrollIndicator->x() - 24;
1347  int deltaY = point.y() - d->m_mouseScrollIndicator->y() - 24;
1348 
1349  (deltaX > 0) ? d->m_mouseScroll_byX = 1 : d->m_mouseScroll_byX = -1;
1350  (deltaY > 0) ? d->m_mouseScroll_byY = 1 : d->m_mouseScroll_byY = -1;
1351 
1352  double adX = qAbs(deltaX) / 30.0;
1353  double adY = qAbs(deltaY) / 30.0;
1354 
1355  d->m_mouseScroll_byX = qMax(qMin(d->m_mouseScroll_byX * int(adX * adX), SHRT_MAX), SHRT_MIN);
1356  d->m_mouseScroll_byY = qMax(qMin(d->m_mouseScroll_byY * int(adY * adY), SHRT_MAX), SHRT_MIN);
1357 
1358  if (d->m_mouseScroll_byX == 0 && d->m_mouseScroll_byY == 0) {
1359  d->m_mouseScrollTimer->stop();
1360  } else if (!d->m_mouseScrollTimer->isActive()) {
1361  d->m_mouseScrollTimer->start(20);
1362  }
1363  }
1364 
1365  if (!m_part->xmlDocImpl()) {
1366  return;
1367  }
1368 
1369  int xm = _mouse->x();
1370  int ym = _mouse->y();
1371  revertTransforms(xm, ym);
1372 
1373  DOM::NodeImpl::MouseEvent mev(_mouse->buttons(), DOM::NodeImpl::MouseMove);
1374  // Do not modify :hover/:active state while mouse is pressed.
1375  m_part->xmlDocImpl()->prepareMouseEvent(_mouse->buttons() /*readonly ?*/, xm, ym, &mev);
1376 
1377  // qCDebug(KHTML_LOG) << "mouse move: " << _mouse->pos()
1378  // << " button " << _mouse->button()
1379  // << " state " << _mouse->state();
1380 
1381  DOM::NodeImpl *target = mev.innerNode.handle();
1382  DOM::NodeImpl *fn = m_part->xmlDocImpl()->focusNode();
1383 
1384  // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
1385  if (d->m_mouseEventsTarget && fn && fn->renderer() && fn->renderer()->isWidget()) {
1386  target = fn;
1387  }
1388 
1389  bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT, target, mev.innerNonSharedNode.handle(), false,
1390  0, _mouse, true, DOM::NodeImpl::MouseMove);
1391 
1392  if (d->clickCount > 0 &&
1393  QPoint(d->clickX - xm, d->clickY - ym).manhattanLength() > QApplication::startDragDistance()) {
1394  d->clickCount = 0; // moving the mouse outside the threshold invalidates the click
1395  }
1396 
1397  khtml::RenderObject *r = target ? target->renderer() : nullptr;
1398  bool setCursor = true;
1399  bool forceDefault = false;
1400  if (r && r->isWidget()) {
1401  RenderWidget *rw = static_cast<RenderWidget *>(r);
1402  KHTMLWidget *kw = qobject_cast<KHTMLView *>(rw->widget()) ? dynamic_cast<KHTMLWidget *>(rw->widget()) : nullptr;
1403  if (kw && kw->m_kwp->isRedirected()) {
1404  setCursor = false;
1405  } else if (QLineEdit *le = qobject_cast<QLineEdit *>(rw->widget())) {
1406  QList<QWidget *> wl = le->findChildren<QWidget *>("KLineEditButton");
1407  // force arrow cursor above lineedit clear button
1408  foreach (QWidget *w, wl) {
1409  if (w->underMouse()) {
1410  forceDefault = true;
1411  break;
1412  }
1413  }
1414  } else if (QTextEdit *te = qobject_cast<QTextEdit *>(rw->widget())) {
1415  if (te->verticalScrollBar()->underMouse() || te->horizontalScrollBar()->underMouse()) {
1416  forceDefault = true;
1417  }
1418  }
1419  }
1420  khtml::RenderStyle *style = (r && r->style()) ? r->style() : nullptr;
1421  QCursor c;
1422  LinkCursor linkCursor = LINK_NORMAL;
1423  switch (!forceDefault ? (style ? style->cursor() : CURSOR_AUTO) : CURSOR_DEFAULT) {
1424  case CURSOR_AUTO:
1425  if (r && r->isText() && ((m_part->d->m_bMousePressed && m_part->d->editor_context.m_beganSelectingText) ||
1426  !r->isPointInsideSelection(xm, ym, m_part->caret()))) {
1427  c = QCursor(Qt::IBeamCursor);
1428  }
1429  if (mev.url.length() && m_part->settings()->changeCursor()) {
1430  c = m_part->urlCursor();
1431  if (mev.url.string().startsWith("mailto:") && mev.url.string().indexOf('@') > 0) {
1432  linkCursor = LINK_MAILTO;
1433  } else if (targetOpensNewWindow(m_part, mev.target.string())) {
1434  linkCursor = LINK_NEWWINDOW;
1435  }
1436  }
1437 
1438  if (r && r->isFrameSet() && !static_cast<RenderFrameSet *>(r)->noResize()) {
1439  c = QCursor(static_cast<RenderFrameSet *>(r)->cursorShape());
1440  }
1441 
1442  break;
1443  case CURSOR_CROSS:
1444  c = QCursor(Qt::CrossCursor);
1445  break;
1446  case CURSOR_POINTER:
1447  c = m_part->urlCursor();
1448  if (mev.url.string().startsWith("mailto:") && mev.url.string().indexOf('@') > 0) {
1449  linkCursor = LINK_MAILTO;
1450  } else if (targetOpensNewWindow(m_part, mev.target.string())) {
1451  linkCursor = LINK_NEWWINDOW;
1452  }
1453  break;
1454  case CURSOR_PROGRESS:
1455  c = QCursor(Qt::BusyCursor); // working_cursor
1456  break;
1457  case CURSOR_MOVE:
1458  case CURSOR_ALL_SCROLL:
1460  break;
1461  case CURSOR_E_RESIZE:
1462  case CURSOR_W_RESIZE:
1463  case CURSOR_EW_RESIZE:
1465  break;
1466  case CURSOR_N_RESIZE:
1467  case CURSOR_S_RESIZE:
1468  case CURSOR_NS_RESIZE:
1470  break;
1471  case CURSOR_NE_RESIZE:
1472  case CURSOR_SW_RESIZE:
1473  case CURSOR_NESW_RESIZE:
1475  break;
1476  case CURSOR_NW_RESIZE:
1477  case CURSOR_SE_RESIZE:
1478  case CURSOR_NWSE_RESIZE:
1480  break;
1481  case CURSOR_TEXT:
1482  c = QCursor(Qt::IBeamCursor);
1483  break;
1484  case CURSOR_WAIT:
1485  c = QCursor(Qt::WaitCursor);
1486  break;
1487  case CURSOR_HELP:
1489  break;
1490  case CURSOR_DEFAULT:
1491  break;
1492  case CURSOR_NONE:
1493  case CURSOR_NOT_ALLOWED:
1495  break;
1496  case CURSOR_ROW_RESIZE:
1498  break;
1499  case CURSOR_COL_RESIZE:
1501  break;
1502  case CURSOR_VERTICAL_TEXT:
1503  case CURSOR_CONTEXT_MENU:
1504  case CURSOR_NO_DROP:
1505  case CURSOR_CELL:
1506  case CURSOR_COPY:
1507  case CURSOR_ALIAS:
1508  c = QCursor(Qt::ArrowCursor);
1509  break;
1510  }
1511 
1512  if (!setCursor && style && style->cursor() != CURSOR_AUTO) {
1513  setCursor = true;
1514  }
1515 
1516  QWidget *vp = viewport();
1517  for (KHTMLPart *p = m_part; p; p = p->parentPart())
1518  if (!p->parentPart()) {
1519  vp = p->view()->viewport();
1520  }
1521  if (setCursor && (vp->cursor().shape() != c.shape() || c.shape() == Qt::BitmapCursor)) {
1522  if (c.shape() == Qt::ArrowCursor) {
1523  for (KHTMLPart *p = m_part; p; p = p->parentPart()) {
1524  p->view()->viewport()->unsetCursor();
1525  }
1526  } else {
1527  vp->setCursor(c);
1528  }
1529  }
1530 
1531  if (linkCursor != LINK_NORMAL && isVisible() && hasFocus()) {
1532 #if HAVE_X11
1533 
1534  if (!d->cursorIconWidget) {
1535 #if HAVE_X11
1536  d->cursorIconWidget = new QLabel(nullptr, Qt::X11BypassWindowManagerHint);
1537  XSetWindowAttributes attr;
1538  attr.save_under = True;
1539  XChangeWindowAttributes(QX11Info::display(), d->cursorIconWidget->winId(), CWSaveUnder, &attr);
1540 #else
1541  d->cursorIconWidget = new QLabel(NULL, NULL);
1542  //TODO
1543 #endif
1544  }
1545 
1546  // Update the pixmap if need be.
1547  if (linkCursor != d->cursorIconType) {
1548  d->cursorIconType = linkCursor;
1549  QString cursorIcon;
1550  switch (linkCursor) {
1551  case LINK_MAILTO: cursorIcon = "mail-message-new"; break;
1552  case LINK_NEWWINDOW: cursorIcon = "window-new"; break;
1553  default: cursorIcon = "dialog-error"; break;
1554  }
1555 
1556  QPixmap icon_pixmap = KHTMLGlobal::iconLoader()->loadIcon(cursorIcon, KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(), nullptr, true);
1557 
1558  d->cursorIconWidget->resize(icon_pixmap.width(), icon_pixmap.height());
1559  d->cursorIconWidget->setMask(icon_pixmap.createMaskFromColor(Qt::transparent));
1560  d->cursorIconWidget->setPixmap(icon_pixmap);
1561  d->cursorIconWidget->update();
1562  }
1563 
1564  QPoint c_pos = QCursor::pos();
1565  d->cursorIconWidget->move(c_pos.x() + 15, c_pos.y() + 15);
1566 #if HAVE_X11
1567  XRaiseWindow(QX11Info::display(), d->cursorIconWidget->winId());
1569 #elif defined(Q_OS_WIN)
1570  SetWindowPos(d->cursorIconWidget->winId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1571 #else
1572  //TODO?
1573 #endif
1574  d->cursorIconWidget->show();
1575 #endif
1576  } else if (d->cursorIconWidget) {
1577  d->cursorIconWidget->hide();
1578  }
1579 
1580  if (r && r->isWidget()) {
1581  _mouse->ignore();
1582  }
1583 
1584  if (!swallowEvent) {
1585  khtml::MouseMoveEvent event(_mouse, xm, ym, mev.url, mev.target, mev.innerNode);
1586  QApplication::sendEvent(m_part, &event);
1587  }
1588 }
1589 
1590 void KHTMLView::mouseReleaseEvent(QMouseEvent *_mouse)
1591 {
1592  bool swallowEvent = false;
1593 
1594  int xm = _mouse->x();
1595  int ym = _mouse->y();
1596  revertTransforms(xm, ym);
1597 
1598  DOM::NodeImpl::MouseEvent mev(_mouse->buttons(), DOM::NodeImpl::MouseRelease);
1599 
1600  if (m_part->xmlDocImpl()) {
1601  m_part->xmlDocImpl()->prepareMouseEvent(false, xm, ym, &mev);
1602 
1603  DOM::NodeImpl *target = mev.innerNode.handle();
1604  DOM::NodeImpl *fn = m_part->xmlDocImpl()->focusNode();
1605 
1606  // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
1607  if (d->m_mouseEventsTarget && fn && fn->renderer() && fn->renderer()->isWidget()) {
1608  target = fn;
1609  }
1610 
1611  swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT, target, mev.innerNonSharedNode.handle(), true,
1612  d->clickCount, _mouse, false, DOM::NodeImpl::MouseRelease);
1613 
1614  // clear our sticky event target on any mouseRelease event
1615  if (d->m_mouseEventsTarget) {
1616  d->m_mouseEventsTarget = nullptr;
1617  }
1618 
1619  if (d->clickCount > 0 &&
1620  QPoint(d->clickX - xm, d->clickY - ym).manhattanLength() <= QApplication::startDragDistance()) {
1622  _mouse->pos(), _mouse->button(), _mouse->buttons(), _mouse->modifiers());
1623  dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(), mev.innerNonSharedNode.handle(), true,
1624  d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
1625  }
1626 
1627  khtml::RenderObject *r = target ? target->renderer() : nullptr;
1628  if (r && r->isWidget()) {
1629  _mouse->ignore();
1630  }
1631  }
1632 
1633  if (!swallowEvent) {
1634  khtml::MouseReleaseEvent event(_mouse, xm, ym, mev.url, mev.target, mev.innerNode);
1635  QApplication::sendEvent(m_part, &event);
1636  }
1637 }
1638 
1639 // returns true if event should be swallowed
1640 bool KHTMLView::dispatchKeyEvent(QKeyEvent *_ke)
1641 {
1642  if (!m_part->xmlDocImpl()) {
1643  return false;
1644  }
1645  // Pressing and releasing a key should generate keydown, keypress and keyup events
1646  // Holding it down should generated keydown, keypress (repeatedly) and keyup events
1647  // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
1648  // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
1649  // of the Qt events shouldn't be passed to DOM, but it should be still filtered
1650  // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
1651  // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
1652  // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
1653  // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
1654  // The solution is to filter out and postpone the Qt autorepeat keyrelease until
1655  // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
1656  // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
1657  // again, and here it will be ignored.
1658  //
1659  // Qt: Press | Release(autorepeat) Press(autorepeat) etc. | Release
1660  // DOM: Down + Press | (nothing) Press | Up
1661 
1662  // It's also possible to get only Releases. E.g. the release of alt-tab,
1663  // or when the keypresses get captured by an accel.
1664 
1665  if (_ke == d->postponed_autorepeat) { // replayed event
1666  return false;
1667  }
1668 
1669  if (_ke->type() == QEvent::KeyPress) {
1670  if (!_ke->isAutoRepeat()) {
1671  bool ret = dispatchKeyEventHelper(_ke, false); // keydown
1672  // don't send keypress even if keydown was blocked, like IE (and unlike Mozilla)
1673  if (!ret && dispatchKeyEventHelper(_ke, true)) { // keypress
1674  ret = true;
1675  }
1676  return ret;
1677  } else { // autorepeat
1678  bool ret = dispatchKeyEventHelper(_ke, true); // keypress
1679  if (!ret && d->postponed_autorepeat) {
1680  keyPressEvent(d->postponed_autorepeat);
1681  }
1682  delete d->postponed_autorepeat;
1683  d->postponed_autorepeat = nullptr;
1684  return ret;
1685  }
1686  } else { // QEvent::KeyRelease
1687  // Discard postponed "autorepeat key-release" events that didn't see
1688  // a keypress after them (e.g. due to QAccel)
1689  delete d->postponed_autorepeat;
1690  d->postponed_autorepeat = nullptr;
1691 
1692  if (!_ke->isAutoRepeat()) {
1693  return dispatchKeyEventHelper(_ke, false); // keyup
1694  } else {
1695  d->postponed_autorepeat = new QKeyEvent(_ke->type(), _ke->key(), _ke->modifiers(),
1696  _ke->text(), _ke->isAutoRepeat(), _ke->count());
1697  if (_ke->isAccepted()) {
1698  d->postponed_autorepeat->accept();
1699  } else {
1700  d->postponed_autorepeat->ignore();
1701  }
1702  return true;
1703  }
1704  }
1705 }
1706 
1707 // returns true if event should be swallowed
1708 bool KHTMLView::dispatchKeyEventHelper(QKeyEvent *_ke, bool keypress)
1709 {
1710  DOM::NodeImpl *keyNode = m_part->xmlDocImpl()->focusNode();
1711  if (keyNode) {
1712  return keyNode->dispatchKeyEvent(_ke, keypress);
1713  } else { // no focused node, send to document
1714  return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
1715  }
1716 }
1717 
1718 void KHTMLView::keyPressEvent(QKeyEvent *_ke)
1719 {
1720  // If CTRL was hit, be prepared for access keys
1721  if (d->accessKeysEnabled && _ke->key() == Qt::Key_Control && !(_ke->modifiers() & ~Qt::ControlModifier) && !d->accessKeysActivated) {
1722  d->accessKeysPreActivate = true;
1723  _ke->accept();
1724  return;
1725  }
1726 
1727  if (_ke->key() == Qt::Key_Shift && !(_ke->modifiers() & ~Qt::ShiftModifier)) {
1728  d->scrollSuspendPreActivate = true;
1729  }
1730 
1731  // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
1732  // may eat the event
1733 
1734  if (d->accessKeysEnabled && d->accessKeysActivated) {
1736  if (state == 0 || state == Qt::ShiftModifier) {
1737  if (_ke->key() != Qt::Key_Shift) {
1738  accessKeysTimeout();
1739  }
1740  handleAccessKey(_ke);
1741  _ke->accept();
1742  return;
1743  }
1744  accessKeysTimeout();
1745  _ke->accept();
1746  return;
1747  }
1748 
1749  if (dispatchKeyEvent(_ke)) {
1750  // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
1751  _ke->accept();
1752  return;
1753  }
1754 
1755  int offs = (viewport()->height() < 30) ? viewport()->height() : 30; // ### ??
1756  if (_ke->modifiers() & Qt::ShiftModifier)
1757  switch (_ke->key()) {
1758  case Qt::Key_Space:
1759  verticalScrollBar()->setValue(verticalScrollBar()->value() - viewport()->height() + offs);
1760  if (d->scrollSuspended) {
1761  d->newScrollTimer(this, 0);
1762  }
1763  break;
1764 
1765  case Qt::Key_Down:
1766  case Qt::Key_J:
1767  d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
1768  break;
1769 
1770  case Qt::Key_Up:
1771  case Qt::Key_K:
1772  d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
1773  break;
1774 
1775  case Qt::Key_Left:
1776  case Qt::Key_H:
1777  d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
1778  break;
1779 
1780  case Qt::Key_Right:
1781  case Qt::Key_L:
1782  d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
1783  break;
1784  }
1785  else
1786  switch (_ke->key()) {
1787  case Qt::Key_Down:
1788  case Qt::Key_J:
1789  if (!d->scrollTimerId || d->scrollSuspended) {
1790  verticalScrollBar()->setValue(verticalScrollBar()->value() + 10);
1791  }
1792  if (d->scrollTimerId) {
1793  d->newScrollTimer(this, 0);
1794  }
1795  break;
1796 
1797  case Qt::Key_Space:
1798  case Qt::Key_PageDown:
1799  d->shouldSmoothScroll = true;
1800  verticalScrollBar()->setValue(verticalScrollBar()->value() + viewport()->height() - offs);
1801  if (d->scrollSuspended) {
1802  d->newScrollTimer(this, 0);
1803  }
1804  break;
1805 
1806  case Qt::Key_Up:
1807  case Qt::Key_K:
1808  if (!d->scrollTimerId || d->scrollSuspended) {
1809  verticalScrollBar()->setValue(verticalScrollBar()->value() - 10);
1810  }
1811  if (d->scrollTimerId) {
1812  d->newScrollTimer(this, 0);
1813  }
1814  break;
1815 
1816  case Qt::Key_PageUp:
1817  d->shouldSmoothScroll = true;
1818  verticalScrollBar()->setValue(verticalScrollBar()->value() - viewport()->height() + offs);
1819  if (d->scrollSuspended) {
1820  d->newScrollTimer(this, 0);
1821  }
1822  break;
1823  case Qt::Key_Right:
1824  case Qt::Key_L:
1825  if (!d->scrollTimerId || d->scrollSuspended) {
1826  horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 10);
1827  }
1828  if (d->scrollTimerId) {
1829  d->newScrollTimer(this, 0);
1830  }
1831  break;
1832 
1833  case Qt::Key_Left:
1834  case Qt::Key_H:
1835  if (!d->scrollTimerId || d->scrollSuspended) {
1836  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 10);
1837  }
1838  if (d->scrollTimerId) {
1839  d->newScrollTimer(this, 0);
1840  }
1841  break;
1842  case Qt::Key_Enter:
1843  case Qt::Key_Return:
1844  // ### FIXME:
1845  // or even better to HTMLAnchorElementImpl::event()
1846  if (m_part->xmlDocImpl()) {
1847  NodeImpl *n = m_part->xmlDocImpl()->focusNode();
1848  if (n) {
1849  n->setActive();
1850  }
1851  }
1852  break;
1853  case Qt::Key_Home:
1856  if (d->scrollSuspended) {
1857  d->newScrollTimer(this, 0);
1858  }
1859  break;
1860  case Qt::Key_End:
1862  if (d->scrollSuspended) {
1863  d->newScrollTimer(this, 0);
1864  }
1865  break;
1866  case Qt::Key_Shift:
1867  // what are you doing here?
1868  _ke->ignore();
1869  return;
1870  default:
1871  if (d->scrollTimerId) {
1872  d->newScrollTimer(this, 0);
1873  }
1874  _ke->ignore();
1875  return;
1876  }
1877 
1878  _ke->accept();
1879 }
1880 
1881 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
1882 {
1883  if (d->scrollSuspendPreActivate && _ke->key() != Qt::Key_Shift) {
1884  d->scrollSuspendPreActivate = false;
1885  }
1886  if (_ke->key() == Qt::Key_Shift && d->scrollSuspendPreActivate && !(_ke->modifiers() & Qt::ShiftModifier))
1887  if (d->scrollTimerId) {
1888  d->scrollSuspended = !d->scrollSuspended;
1889  if (d->scrollSuspended) {
1890  d->stopScrolling();
1891  }
1892  }
1893 
1894  if (d->accessKeysEnabled) {
1895  if (d->accessKeysPreActivate && _ke->key() != Qt::Key_Control) {
1896  d->accessKeysPreActivate = false;
1897  }
1898  if (d->accessKeysPreActivate && !(_ke->modifiers() & Qt::ControlModifier)) {
1900  m_part->setStatusBarText(i18n("Access Keys activated"), KHTMLPart::BarOverrideText);
1901  d->accessKeysActivated = true;
1902  d->accessKeysPreActivate = false;
1903  _ke->accept();
1904  return;
1905  } else if (d->accessKeysActivated) {
1906  accessKeysTimeout();
1907  _ke->accept();
1908  return;
1909  }
1910  }
1911 
1912  // Send keyup event
1913  if (dispatchKeyEvent(_ke)) {
1914  _ke->accept();
1915  return;
1916  }
1917 
1919 }
1920 
1921 bool KHTMLView::focusNextPrevChild(bool next)
1922 {
1923  // Now try to find the next child
1924  if (m_part->xmlDocImpl() && focusNextPrevNode(next)) {
1925  //if (m_part->xmlDocImpl()->focusNode())
1926  // qCDebug(KHTML_LOG) << "focusNode.name: "
1927  // << m_part->xmlDocImpl()->focusNode()->nodeName().string();
1928  return true; // focus node found
1929  }
1930 
1931  // If we get here, pass tabbing control up to the next/previous child in our parent
1932  d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
1933  if (m_part->parentPart() && m_part->parentPart()->view()) {
1934  return m_part->parentPart()->view()->focusNextPrevChild(next);
1935  }
1936 
1937  return QWidget::focusNextPrevChild(next);
1938 }
1939 
1940 void KHTMLView::doAutoScroll()
1941 {
1942  QPoint pos = QCursor::pos();
1943  QPoint off;
1944  KHTMLView *v = m_kwp->isRedirected() ? m_kwp->rootViewPos(off) : this;
1945  pos = v->viewport()->mapFromGlobal(pos);
1946  pos -= off;
1947  int xm, ym;
1948  viewportToContents(pos.x(), pos.y(), xm, ym); // ###
1949 
1950  pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
1951  if ((pos.y() < 0) || (pos.y() > visibleHeight()) ||
1952  (pos.x() < 0) || (pos.x() > visibleWidth())) {
1953  ensureVisible(xm, ym, 0, 5);
1954 
1955 #ifndef KHTML_NO_SELECTION
1956  // extend the selection while scrolling
1957  DOM::Node innerNode;
1958  if (m_part->isExtendingSelection()) {
1959  RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
1960  m_part->xmlDocImpl()->renderer()->layer()
1961  ->nodeAtPoint(renderInfo, xm, ym);
1962  innerNode = renderInfo.innerNode();
1963  }/*end if*/
1964 
1965  if (innerNode.handle() && innerNode.handle()->renderer()
1966  && innerNode.handle()->renderer()->shouldSelect()) {
1967  m_part->extendSelectionTo(xm, ym, innerNode);
1968  }/*end if*/
1969 #endif // KHTML_NO_SELECTION
1970  }
1971 }
1972 
1973 // KHTML defines its own stacking order for any object and thus takes
1974 // control of widget painting whenever it can. This is called "redirection".
1975 //
1976 // Redirected widgets are placed off screen. When they are declared as a child of our view (ChildPolished event),
1977 // an event filter is installed, so as to catch any paint event and translate them as update() of the view's main widget.
1978 //
1979 // Painting also happens spontaneously within widgets. In this case, the widget would update() parts of itself.
1980 // While this ordinarily results in a paintEvent being schedduled, it is not the case with off screen widgets.
1981 // Thus update() is monitored by using the mechanism that deffers any update call happening during a paint event,
1982 // transforming it into a posted UpdateLater event. Hence the need to set Qt::WA_WState_InPaintEvent on redirected widgets.
1983 //
1984 // Once the UpdateLater event has been received, Qt::WA_WState_InPaintEvent is removed and the process continues
1985 // with the update of the corresponding rect on the view. That in turn will make our painting subsystem render()
1986 // the widget at the correct stacking position.
1987 //
1988 // For non-redirected (e.g. external) widgets, z-order is honoured through masking. cf.RenderLayer::updateWidgetMasks
1989 
1990 static void handleWidget(QWidget *w, KHTMLView *view, bool recurse = true)
1991 {
1992  if (w->isWindow()) {
1993  return;
1994  }
1995 
1996  if (!qobject_cast<QFrame *>(w)) {
1998  }
1999 
2001 
2002  if (!(w->objectName() == "KLineEditButton")) {
2004  }
2005 
2006  w->installEventFilter(view);
2007 
2008  if (!recurse) {
2009  return;
2010  }
2011  if (qobject_cast<KHTMLView *>(w)) {
2012  handleWidget(static_cast<KHTMLView *>(w)->widget(), view, false);
2013  handleWidget(static_cast<KHTMLView *>(w)->horizontalScrollBar(), view, false);
2014  handleWidget(static_cast<KHTMLView *>(w)->verticalScrollBar(), view, false);
2015  return;
2016  }
2017 
2018  QObjectList children = w->children();
2019  foreach (QObject *object, children) {
2020  QWidget *widget = qobject_cast<QWidget *>(object);
2021  if (widget) {
2022  handleWidget(widget, view);
2023  }
2024  }
2025 }
2026 
2027 class KHTMLBackingStoreHackWidget : public QWidget
2028 {
2029 public:
2030  void publicEvent(QEvent *e)
2031  {
2032  QWidget::event(e);
2033  }
2034 };
2035 
2036 bool KHTMLView::viewportEvent(QEvent *e)
2037 {
2038  switch (e->type()) {
2039  // those must not be dispatched to the specialized handlers
2040  // as widgetEvent() already took care of that
2044  case QEvent::MouseMove:
2045 #ifndef QT_NO_WHEELEVENT
2046  case QEvent::Wheel:
2047 #endif
2048  case QEvent::ContextMenu:
2049  case QEvent::DragEnter:
2050  case QEvent::DragMove:
2051  case QEvent::DragLeave:
2052  case QEvent::Drop:
2053  return false;
2054  default:
2055  break;
2056  }
2057  return QScrollArea::viewportEvent(e);
2058 }
2059 
2060 static void setInPaintEventFlag(QWidget *w, bool b = true, bool recurse = true)
2061 {
2063 
2064  if (!recurse) {
2065  return;
2066  }
2067  if (qobject_cast<KHTMLView *>(w)) {
2068  setInPaintEventFlag(static_cast<KHTMLView *>(w)->widget(), b, false);
2069  setInPaintEventFlag(static_cast<KHTMLView *>(w)->horizontalScrollBar(), b, false);
2070  setInPaintEventFlag(static_cast<KHTMLView *>(w)->verticalScrollBar(), b, false);
2071  return;
2072  }
2073 
2074  foreach (QObject *cw, w->children()) {
2075  if (cw->isWidgetType() && ! static_cast<QWidget *>(cw)->isWindow()
2076  && !(static_cast<QWidget *>(cw)->windowModality() & Qt::ApplicationModal)) {
2077  setInPaintEventFlag(static_cast<QWidget *>(cw), b);
2078  }
2079  }
2080 }
2081 
2082 bool KHTMLView::eventFilter(QObject *o, QEvent *e)
2083 {
2084  if (e->type() == QEvent::ShortcutOverride) {
2085  QKeyEvent *ke = (QKeyEvent *) e;
2086  if (m_part->isEditable() || m_part->isCaretMode()
2087  || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
2088  && m_part->xmlDocImpl()->focusNode()->isContentEditable())) {
2089  if ((ke->modifiers() & Qt::ControlModifier) || (ke->modifiers() & Qt::ShiftModifier)) {
2090  switch (ke->key()) {
2091  case Qt::Key_Left:
2092  case Qt::Key_Right:
2093  case Qt::Key_Up:
2094  case Qt::Key_Down:
2095  case Qt::Key_Home:
2096  case Qt::Key_End:
2097  ke->accept();
2098  return true;
2099  default:
2100  break;
2101  }
2102  }
2103  }
2104  }
2105 
2106  if (e->type() == QEvent::Leave) {
2107  if (d->cursorIconWidget) {
2108  d->cursorIconWidget->hide();
2109  }
2110  m_part->resetHoverText();
2111  }
2112 
2113  QWidget *view = widget();
2114  if (o == view) {
2115  if (widgetEvent(e)) {
2116  return true;
2117  } else if (e->type() == QEvent::Resize) {
2118  updateScrollBars();
2119  return false;
2120  }
2121  } else if (o->isWidgetType()) {
2122  QWidget *v = static_cast<QWidget *>(o);
2123  QWidget *c = v;
2124  while (v && v != view) {
2125  c = v;
2126  v = v->parentWidget();
2127  }
2128  KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(c);
2129  if (v && k && k->m_kwp->isRedirected()) {
2130  bool block = false;
2131  QWidget *w = static_cast<QWidget *>(o);
2132  switch (e->type()) {
2133  case QEvent::UpdateRequest: {
2134  // implicitly call qt_syncBackingStore(w)
2135  static_cast<KHTMLBackingStoreHackWidget *>(w)->publicEvent(e);
2136  block = true;
2137  break;
2138  }
2139  case QEvent::UpdateLater:
2140  // no break;
2141  case QEvent::Paint:
2142  if (!allowWidgetPaintEvents) {
2143  // eat the event. Like this we can control exactly when the widget
2144  // gets repainted.
2145  block = true;
2146  int x = 0, y = 0;
2147  QWidget *v = w;
2148  while (v && v->parentWidget() != view) {
2149  x += v->x();
2150  y += v->y();
2151  v = v->parentWidget();
2152  }
2153 
2154  QPoint ap = k->m_kwp->absolutePos();
2155  x += ap.x();
2156  y += ap.y();
2157  }
2158  break;
2159  case QEvent::MouseMove:
2163 
2164  if (0 && w->parentWidget() == view && !qobject_cast<QScrollBar *>(w) && !::qobject_cast<QScrollBar *>(w)) {
2165  QMouseEvent *me = static_cast<QMouseEvent *>(e);
2166  QPoint pt = w->mapTo(view, me->pos());
2167  QMouseEvent me2(me->type(), pt, me->button(), me->buttons(), me->modifiers());
2168 
2169  if (e->type() == QEvent::MouseMove) {
2170  mouseMoveEvent(&me2);
2171  } else if (e->type() == QEvent::MouseButtonPress) {
2172  mousePressEvent(&me2);
2173  } else if (e->type() == QEvent::MouseButtonRelease) {
2174  mouseReleaseEvent(&me2);
2175  } else {
2176  mouseDoubleClickEvent(&me2);
2177  }
2178  block = true;
2179  }
2180  break;
2181  }
2182  case QEvent::KeyPress:
2183  case QEvent::KeyRelease:
2184  if (w->parentWidget() == view && !qobject_cast<QScrollBar *>(w)) {
2185  QKeyEvent *ke = static_cast<QKeyEvent *>(e);
2186  if (e->type() == QEvent::KeyPress) {
2187  keyPressEvent(ke);
2188  ke->accept();
2189  } else {
2190  keyReleaseEvent(ke);
2191  ke->accept();
2192  }
2193  block = true;
2194  }
2195 
2196  if (qobject_cast<KUrlRequester *>(w->parentWidget()) &&
2197  e->type() == QEvent::KeyPress) {
2198  // Since keypress events on the upload widget will
2199  // be forwarded to the lineedit anyway,
2200  // block the original copy at this level to prevent
2201  // double-emissions of events it doesn't accept
2202  e->ignore();
2203  block = true;
2204  }
2205 
2206  break;
2207  case QEvent::FocusIn:
2208  case QEvent::FocusOut: {
2209  QPoint dummy;
2210  KHTMLView *root = m_kwp->rootViewPos(dummy);
2211  if (!root) {
2212  root = this;
2213  }
2214  block = static_cast<QFocusEvent *>(e)->reason() != Qt::MouseFocusReason || root->underMouse();
2215  break;
2216  }
2217  default:
2218  break;
2219  }
2220  if (block) {
2221  //qDebug("eating event");
2222  return true;
2223  }
2224  }
2225  }
2226 
2227 // qCDebug(KHTML_LOG) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type();
2228  return QScrollArea::eventFilter(o, e);
2229 }
2230 
2231 bool KHTMLView::widgetEvent(QEvent *e)
2232 {
2233  switch (e->type()) {
2237  case QEvent::MouseMove:
2238  case QEvent::Paint:
2239 #ifndef QT_NO_WHEELEVENT
2240  case QEvent::Wheel:
2241 #endif
2242  case QEvent::ContextMenu:
2243  case QEvent::DragEnter:
2244  case QEvent::DragMove:
2245  case QEvent::DragLeave:
2246  case QEvent::Drop:
2247  return QFrame::event(e);
2248  case QEvent::ChildPolished: {
2249  // we need to install an event filter on all children of the widget() to
2250  // be able to get correct stacking of children within the document.
2251  QObject *c = static_cast<QChildEvent *>(e)->child();
2252  if (c->isWidgetType()) {
2253  QWidget *w = static_cast<QWidget *>(c);
2254  // don't install the event filter on toplevels
2255  if (!(w->windowFlags() & Qt::Window) && !(w->windowModality() & Qt::ApplicationModal)) {
2256  KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(w);
2257  if (k && k->m_kwp->isRedirected()) {
2258  w->unsetCursor();
2259  handleWidget(w, this);
2260  }
2261  }
2262  }
2263  break;
2264  }
2265  case QEvent::Move: {
2266  if (static_cast<QMoveEvent *>(e)->pos() != QPoint(0, 0)) {
2267  widget()->move(0, 0);
2268  updateScrollBars();
2269  return true;
2270  }
2271  break;
2272  }
2273  default:
2274  break;
2275  }
2276  return false;
2277 }
2278 
2279 bool KHTMLView::hasLayoutPending()
2280 {
2281  return d->layoutTimerId && !d->firstLayoutPending;
2282 }
2283 
2284 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
2285 {
2286  return d->underMouse;
2287 }
2288 
2289 DOM::NodeImpl *KHTMLView::nonSharedNodeUnderMouse() const
2290 {
2291  return d->underMouseNonShared;
2292 }
2293 
2294 bool KHTMLView::scrollTo(const QRect &bounds)
2295 {
2296  d->scrollingSelf = true; // so scroll events get ignored
2297 
2298  int x, y, xe, ye;
2299  x = bounds.left();
2300  y = bounds.top();
2301  xe = bounds.right();
2302  ye = bounds.bottom();
2303 
2304  //qCDebug(KHTML_LOG)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y;
2305 
2306  int deltax;
2307  int deltay;
2308 
2309  int curHeight = visibleHeight();
2310  int curWidth = visibleWidth();
2311 
2312  if (ye - y > curHeight - d->borderY) {
2313  ye = y + curHeight - d->borderY;
2314  }
2315 
2316  if (xe - x > curWidth - d->borderX) {
2317  xe = x + curWidth - d->borderX;
2318  }
2319 
2320  // is xpos of target left of the view's border?
2321  if (x < contentsX() + d->borderX) {
2322  deltax = x - contentsX() - d->borderX;
2323  }
2324  // is xpos of target right of the view's right border?
2325  else if (xe + d->borderX > contentsX() + curWidth) {
2326  deltax = xe + d->borderX - (contentsX() + curWidth);
2327  } else {
2328  deltax = 0;
2329  }
2330 
2331  // is ypos of target above upper border?
2332  if (y < contentsY() + d->borderY) {
2333  deltay = y - contentsY() - d->borderY;
2334  }
2335  // is ypos of target below lower border?
2336  else if (ye + d->borderY > contentsY() + curHeight) {
2337  deltay = ye + d->borderY - (contentsY() + curHeight);
2338  } else {
2339  deltay = 0;
2340  }
2341 
2342  int maxx = curWidth - d->borderX;
2343  int maxy = curHeight - d->borderY;
2344 
2345  int scrollX, scrollY;
2346 
2347  scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax > -maxx ? deltax : -maxx);
2348  scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay > -maxy ? deltay : -maxy);
2349 
2350  if (contentsX() + scrollX < 0) {
2351  scrollX = -contentsX();
2352  } else if (contentsWidth() - visibleWidth() - contentsX() < scrollX) {
2353  scrollX = contentsWidth() - visibleWidth() - contentsX();
2354  }
2355 
2356  if (contentsY() + scrollY < 0) {
2357  scrollY = -contentsY();
2358  } else if (contentsHeight() - visibleHeight() - contentsY() < scrollY) {
2359  scrollY = contentsHeight() - visibleHeight() - contentsY();
2360  }
2361 
2362  horizontalScrollBar()->setValue(horizontalScrollBar()->value() + scrollX);
2363  verticalScrollBar()->setValue(verticalScrollBar()->value() + scrollY);
2364 
2365  d->scrollingSelf = false;
2366 
2367  if ((abs(deltax) <= maxx) && (abs(deltay) <= maxy)) {
2368  return true;
2369  } else {
2370  return false;
2371  }
2372 
2373 }
2374 
2375 bool KHTMLView::focusNextPrevNode(bool next)
2376 {
2377  // Sets the focus node of the document to be the node after (or if
2378  // next is false, before) the current focus node. Only nodes that
2379  // are selectable (i.e. for which isFocusable() returns true) are
2380  // taken into account, and the order used is that specified in the
2381  // HTML spec (see DocumentImpl::nextFocusNode() and
2382  // DocumentImpl::previousFocusNode() for details).
2383 
2384  DocumentImpl *doc = m_part->xmlDocImpl();
2385  NodeImpl *oldFocusNode = doc->focusNode();
2386 
2387  // See whether we're in the middle of a detach, or hiding of the
2388  // widget. In this case, we will just clear focus, being careful not to emit events
2389  // or update rendering. Doing this also prevents the code below from going bonkers with
2390  // oldFocusNode not actually being focusable, etc.
2391  if (oldFocusNode) {
2392  if ((oldFocusNode->renderer() && !oldFocusNode->renderer()->parent())
2393  || !oldFocusNode->isTabFocusable()) {
2394  doc->quietResetFocus();
2395  return true;
2396  }
2397  }
2398 
2399 #if 1
2400  // If the user has scrolled the document, then instead of picking
2401  // the next focusable node in the document, use the first one that
2402  // is within the visible area (if possible).
2403  if (d->scrollBarMoved) {
2404  NodeImpl *toFocus;
2405  if (next) {
2406  toFocus = doc->nextFocusNode(oldFocusNode);
2407  } else {
2408  toFocus = doc->previousFocusNode(oldFocusNode);
2409  }
2410 
2411  if (!toFocus && oldFocusNode) {
2412  if (next) {
2413  toFocus = doc->nextFocusNode(nullptr);
2414  } else {
2415  toFocus = doc->previousFocusNode(nullptr);
2416  }
2417  }
2418 
2419  while (toFocus && toFocus != oldFocusNode) {
2420 
2421  QRect focusNodeRect = toFocus->getRect();
2422  if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
2423  (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
2424  {
2425  QRect r = toFocus->getRect();
2426  ensureVisible(r.right(), r.bottom());
2427  ensureVisible(r.left(), r.top());
2428  d->scrollBarMoved = false;
2429  d->tabMovePending = false;
2430  d->lastTabbingDirection = next;
2431  d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
2432  m_part->xmlDocImpl()->setFocusNode(toFocus);
2433  Node guard(toFocus);
2434  if (!toFocus->hasOneRef()) {
2435  emit m_part->nodeActivated(Node(toFocus));
2436  }
2437  return true;
2438  }
2439  }
2440  if (next) {
2441  toFocus = doc->nextFocusNode(toFocus);
2442  } else {
2443  toFocus = doc->previousFocusNode(toFocus);
2444  }
2445 
2446  if (!toFocus && oldFocusNode) {
2447  if (next) {
2448  toFocus = doc->nextFocusNode(nullptr);
2449  } else {
2450  toFocus = doc->previousFocusNode(nullptr);
2451  }
2452  }
2453  }
2454 
2455  d->scrollBarMoved = false;
2456  }
2457 #endif
2458 
2459  if (!oldFocusNode && d->pseudoFocusNode == KHTMLViewPrivate::PFNone) {
2460  ensureVisible(contentsX(), next ? 0 : contentsHeight());
2461  d->scrollBarMoved = false;
2462  d->pseudoFocusNode = next ? KHTMLViewPrivate::PFTop : KHTMLViewPrivate::PFBottom;
2463  return true;
2464  }
2465 
2466  NodeImpl *newFocusNode = nullptr;
2467 
2468  if (d->tabMovePending && next != d->lastTabbingDirection) {
2469  //qCDebug(KHTML_LOG) << " tab move pending and tabbing direction changed!\n";
2470  newFocusNode = oldFocusNode;
2471  } else if (next) {
2472  if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFTop) {
2473  newFocusNode = doc->nextFocusNode(oldFocusNode);
2474  }
2475  } else {
2476  if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFBottom) {
2477  newFocusNode = doc->previousFocusNode(oldFocusNode);
2478  }
2479  }
2480 
2481  bool targetVisible = false;
2482  if (!newFocusNode) {
2483  if (next) {
2484  targetVisible = scrollTo(QRect(contentsX() + visibleWidth() / 2, contentsHeight() - d->borderY, 0, 0));
2485  } else {
2486  targetVisible = scrollTo(QRect(contentsX() + visibleWidth() / 2, d->borderY, 0, 0));
2487  }
2488  } else {
2489  // if it's an editable element, activate the caret
2490  if (!m_part->isCaretMode() && newFocusNode->isContentEditable()) {
2491  // qCDebug(KHTML_LOG) << "show caret! fn: " << newFocusNode->nodeName().string();
2492  m_part->clearCaretRectIfNeeded();
2493  m_part->d->editor_context.m_selection.moveTo(Position(newFocusNode, 0L));
2494  m_part->setCaretVisible(true);
2495  } else {
2496  m_part->setCaretVisible(false);
2497  // qCDebug(KHTML_LOG) << "hide caret! fn: " << newFocusNode->nodeName().string();
2498  }
2499  m_part->notifySelectionChanged();
2500 
2501  targetVisible = scrollTo(newFocusNode->getRect());
2502  }
2503 
2504  if (targetVisible) {
2505  //qCDebug(KHTML_LOG) << " target reached.\n";
2506  d->tabMovePending = false;
2507 
2508  m_part->xmlDocImpl()->setFocusNode(newFocusNode);
2509  if (newFocusNode) {
2510  Node guard(newFocusNode);
2511  if (!newFocusNode->hasOneRef()) {
2512  emit m_part->nodeActivated(Node(newFocusNode));
2513  }
2514  return true;
2515  } else {
2516  d->pseudoFocusNode = next ? KHTMLViewPrivate::PFBottom : KHTMLViewPrivate::PFTop;
2517  return false;
2518  }
2519  } else {
2520  if (!d->tabMovePending) {
2521  d->lastTabbingDirection = next;
2522  }
2523  d->tabMovePending = true;
2524  return true;
2525  }
2526 }
2527 
2529 {
2530  QVector< QChar > taken;
2531  displayAccessKeys(nullptr, this, taken, false);
2532  displayAccessKeys(nullptr, this, taken, true);
2533 }
2534 
2535 void KHTMLView::displayAccessKeys(KHTMLView *caller, KHTMLView *origview, QVector< QChar > &taken, bool use_fallbacks)
2536 {
2537  QMap< ElementImpl *, QChar > fallbacks;
2538  if (use_fallbacks) {
2539  fallbacks = buildFallbackAccessKeys();
2540  }
2541  for (NodeImpl *n = m_part->xmlDocImpl(); n != nullptr; n = n->traverseNextNode()) {
2542  if (n->isElementNode()) {
2543  ElementImpl *en = static_cast< ElementImpl * >(n);
2544  DOMString s = en->getAttribute(ATTR_ACCESSKEY);
2545  QString accesskey;
2546  if (s.length() == 1) {
2547  QChar a = s.string()[ 0 ].toUpper();
2548  if (qFind(taken.begin(), taken.end(), a) == taken.end()) { // !contains
2549  accesskey = a;
2550  }
2551  }
2552  if (accesskey.isNull() && fallbacks.contains(en)) {
2553  QChar a = fallbacks[ en ].toUpper();
2554  if (qFind(taken.begin(), taken.end(), a) == taken.end()) { // !contains
2555  accesskey = QString("<qt><i>") + a + "</i></qt>";
2556  }
2557  }
2558  if (!accesskey.isNull()) {
2559  QRect rec = en->getRect();
2560  QLabel *lab = new QLabel(accesskey, widget());
2562  lab->setObjectName("KHTMLAccessKey");
2563  connect(origview, SIGNAL(hideAccessKeys()), lab, SLOT(close()));
2564  connect(this, SIGNAL(repaintAccessKeys()), lab, SLOT(repaint()));
2565  lab->setPalette(QToolTip::palette());
2566  lab->setLineWidth(2);
2568  lab->setContentsMargins(3, 3, 3, 3);
2569  lab->adjustSize();
2570  lab->setParent(widget());
2571  lab->setAutoFillBackground(true);
2572  lab->move(
2573  qMin(rec.left() + rec.width() / 2 - contentsX(), contentsWidth() - lab->width()),
2574  qMin(rec.top() + rec.height() / 2 - contentsY(), contentsHeight() - lab->height()));
2575  lab->show();
2576  taken.append(accesskey[ 0 ]);
2577  }
2578  }
2579  }
2580  if (use_fallbacks) {
2581  return;
2582  }
2583 
2584  QList<KParts::ReadOnlyPart *> frames = m_part->frames();
2585  foreach (KParts::ReadOnlyPart *cur, frames) {
2586  if (!qobject_cast<KHTMLPart *>(cur)) {
2587  continue;
2588  }
2589  KHTMLPart *part = static_cast< KHTMLPart * >(cur);
2590  if (part->view() && part->view() != caller) {
2591  part->view()->displayAccessKeys(this, origview, taken, use_fallbacks);
2592  }
2593  }
2594 
2595  // pass up to the parent
2596  if (m_part->parentPart() && m_part->parentPart()->view()
2597  && m_part->parentPart()->view() != caller) {
2598  m_part->parentPart()->view()->displayAccessKeys(this, origview, taken, use_fallbacks);
2599  }
2600 }
2601 
2602 bool KHTMLView::isScrollingFromMouseWheel() const
2603 {
2604  return d->scrollingFromWheel != QPoint(-1, -1);
2605 }
2606 
2607 void KHTMLView::accessKeysTimeout()
2608 {
2609  d->accessKeysActivated = false;
2610  d->accessKeysPreActivate = false;
2611  m_part->setStatusBarText(QString(), KHTMLPart::BarOverrideText);
2612  emit hideAccessKeys();
2613 }
2614 
2615 // Handling of the HTML accesskey attribute.
2616 bool KHTMLView::handleAccessKey(const QKeyEvent *ev)
2617 {
2618 // Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
2619 // but this code must act as if the modifiers weren't pressed
2620  QChar c;
2621  if (ev->key() >= Qt::Key_A && ev->key() <= Qt::Key_Z) {
2622  c = 'A' + ev->key() - Qt::Key_A;
2623  } else if (ev->key() >= Qt::Key_0 && ev->key() <= Qt::Key_9) {
2624  c = '0' + ev->key() - Qt::Key_0;
2625  } else {
2626  // TODO fake XKeyEvent and XLookupString ?
2627  // This below seems to work e.g. for eacute though.
2628  if (ev->text().length() == 1) {
2629  c = ev->text()[ 0 ];
2630  }
2631  }
2632  if (c.isNull()) {
2633  return false;
2634  }
2635  return focusNodeWithAccessKey(c);
2636 }
2637 
2638 bool KHTMLView::focusNodeWithAccessKey(QChar c, KHTMLView *caller)
2639 {
2640  DocumentImpl *doc = m_part->xmlDocImpl();
2641  if (!doc) {
2642  return false;
2643  }
2644  ElementImpl *node = doc->findAccessKeyElement(c);
2645  if (!node) {
2646  QList<KParts::ReadOnlyPart *> frames = m_part->frames();
2647  foreach (KParts::ReadOnlyPart *cur, frames) {
2648  if (!qobject_cast<KHTMLPart *>(cur)) {
2649  continue;
2650  }
2651  KHTMLPart *part = static_cast< KHTMLPart * >(cur);
2652  if (part->view() && part->view() != caller
2653  && part->view()->focusNodeWithAccessKey(c, this)) {
2654  return true;
2655  }
2656  }
2657  // pass up to the parent
2658  if (m_part->parentPart() && m_part->parentPart()->view()
2659  && m_part->parentPart()->view() != caller
2660  && m_part->parentPart()->view()->focusNodeWithAccessKey(c, this)) {
2661  return true;
2662  }
2663  if (caller == nullptr) { // the active frame (where the accesskey was pressed)
2664  const QMap< ElementImpl *, QChar > fallbacks = buildFallbackAccessKeys();
2665  for (QMap< ElementImpl *, QChar >::ConstIterator it = fallbacks.begin();
2666  it != fallbacks.end();
2667  ++it)
2668  if (*it == c) {
2669  node = it.key();
2670  break;
2671  }
2672  }
2673  if (node == nullptr) {
2674  return false;
2675  }
2676  }
2677 
2678  // Scroll the view as necessary to ensure that the new focus node is visible
2679 
2680  QRect r = node->getRect();
2681  ensureVisible(r.right(), r.bottom());
2682  ensureVisible(r.left(), r.top());
2683 
2684  Node guard(node);
2685  if (node->isFocusable()) {
2686  if (node->id() == ID_LABEL) {
2687  // if Accesskey is a label, give focus to the label's referrer.
2688  node = static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl * >(node)->getFormElement());
2689  if (!node) {
2690  return true;
2691  }
2692  guard = node;
2693  }
2694  // Set focus node on the document
2695  m_part->xmlDocImpl()->setFocusNode(node);
2696 
2697  if (node != nullptr && node->hasOneRef()) { // deleted, only held by guard
2698  return true;
2699  }
2700  emit m_part->nodeActivated(Node(node));
2701  if (node != nullptr && node->hasOneRef()) {
2702  return true;
2703  }
2704  }
2705 
2706  switch (node->id()) {
2707  case ID_A:
2708  static_cast< HTMLAnchorElementImpl * >(node)->click();
2709  break;
2710  case ID_INPUT:
2711  static_cast< HTMLInputElementImpl * >(node)->click();
2712  break;
2713  case ID_BUTTON:
2714  static_cast< HTMLButtonElementImpl * >(node)->click();
2715  break;
2716  case ID_AREA:
2717  static_cast< HTMLAreaElementImpl * >(node)->click();
2718  break;
2719  case ID_TEXTAREA:
2720  break; // just focusing it is enough
2721  case ID_LEGEND:
2722  // TODO
2723  break;
2724  }
2725  return true;
2726 }
2727 
2728 static QString getElementText(NodeImpl *start, bool after)
2729 {
2730  QString ret; // nextSibling(), to go after e.g. </select>
2731  for (NodeImpl *n = after ? start->nextSibling() : start->traversePreviousNode();
2732  n != nullptr;
2733  n = after ? n->traverseNextNode() : n->traversePreviousNode()) {
2734  if (n->isTextNode()) {
2735  if (after) {
2736  ret += static_cast< TextImpl * >(n)->toString().string();
2737  } else {
2738  ret.prepend(static_cast< TextImpl * >(n)->toString().string());
2739  }
2740  } else {
2741  switch (n->id()) {
2742  case ID_A:
2743  case ID_FONT:
2744  case ID_TT:
2745  case ID_U:
2746  case ID_B:
2747  case ID_I:
2748  case ID_S:
2749  case ID_STRIKE:
2750  case ID_BIG:
2751  case ID_SMALL:
2752  case ID_EM:
2753  case ID_STRONG:
2754  case ID_DFN:
2755  case ID_CODE:
2756  case ID_SAMP:
2757  case ID_KBD:
2758  case ID_VAR:
2759  case ID_CITE:
2760  case ID_ABBR:
2761  case ID_ACRONYM:
2762  case ID_SUB:
2763  case ID_SUP:
2764  case ID_SPAN:
2765  case ID_NOBR:
2766  case ID_WBR:
2767  break;
2768  case ID_TD:
2769  if (ret.trimmed().isEmpty()) {
2770  break;
2771  }
2772  // fall through
2773  default:
2774  return ret.simplified();
2775  }
2776  }
2777  }
2778  return ret.simplified();
2779 }
2780 
2781 static QMap< NodeImpl *, QString > buildLabels(NodeImpl *start)
2782 {
2784  for (NodeImpl *n = start;
2785  n != nullptr;
2786  n = n->traverseNextNode()) {
2787  if (n->id() == ID_LABEL) {
2788  HTMLLabelElementImpl *label = static_cast< HTMLLabelElementImpl * >(n);
2789  NodeImpl *labelfor = label->getFormElement();
2790  if (labelfor) {
2791  ret[ labelfor ] = label->innerText().string().simplified();
2792  }
2793  }
2794  }
2795  return ret;
2796 }
2797 
2798 namespace khtml
2799 {
2800 struct AccessKeyData {
2801  ElementImpl *element;
2802  QString text;
2803  QString url;
2804  int priority; // 10(highest) - 0(lowest)
2805 };
2806 }
2807 
2808 QMap< ElementImpl *, QChar > KHTMLView::buildFallbackAccessKeys() const
2809 {
2810  // build a list of all possible candidate elements that could use an accesskey
2811  QLinkedList< AccessKeyData > data; // Note: this has to be a list type that keep iterators valid
2812  // when other entries are removed
2813  QMap< NodeImpl *, QString > labels = buildLabels(m_part->xmlDocImpl());
2814  QMap< QString, QChar > hrefs;
2815 
2816  for (NodeImpl *n = m_part->xmlDocImpl();
2817  n != nullptr;
2818  n = n->traverseNextNode()) {
2819  if (n->isElementNode()) {
2820  ElementImpl *element = static_cast< ElementImpl * >(n);
2821  if (element->renderer() == nullptr) {
2822  continue; // not visible
2823  }
2824  QString text;
2825  QString url;
2826  int priority = 0;
2827  bool ignore = false;
2828  bool text_after = false;
2829  bool text_before = false;
2830  switch (element->id()) {
2831  case ID_A:
2832  url = element->getAttribute(ATTR_HREF).trimSpaces().string();
2833  if (url.isEmpty()) { // doesn't have href, it's only an anchor
2834  continue;
2835  }
2836  text = static_cast< HTMLElementImpl * >(element)->innerText().string().simplified();
2837  priority = 2;
2838  break;
2839  case ID_INPUT: {
2840  HTMLInputElementImpl *in = static_cast< HTMLInputElementImpl * >(element);
2841  switch (in->inputType()) {
2842  case HTMLInputElementImpl::SUBMIT:
2843  text = in->value().string();
2844  if (text.isEmpty()) {
2845  text = i18n("Submit");
2846  }
2847  priority = 7;
2848  break;
2849  case HTMLInputElementImpl::IMAGE:
2850  text = in->altText().string();
2851  priority = 7;
2852  break;
2853  case HTMLInputElementImpl::BUTTON:
2854  text = in->value().string();
2855  priority = 5;
2856  break;
2857  case HTMLInputElementImpl::RESET:
2858  text = in->value().string();
2859  if (text.isEmpty()) {
2860  text = i18n("Reset");
2861  }
2862  priority = 5;
2863  break;
2864  case HTMLInputElementImpl::HIDDEN:
2865  ignore = true;
2866  break;
2867  case HTMLInputElementImpl::CHECKBOX:
2868  case HTMLInputElementImpl::RADIO:
2869  text_after = true;
2870  priority = 5;
2871  break;
2872  case HTMLInputElementImpl::TEXT:
2873  case HTMLInputElementImpl::PASSWORD:
2874  case HTMLInputElementImpl::FILE:
2875  text_before = true;
2876  priority = 5;
2877  break;
2878  default:
2879  priority = 5;
2880  break;
2881  }
2882  break;
2883  }
2884  case ID_BUTTON:
2885  text = static_cast< HTMLElementImpl * >(element)->innerText().string().simplified();
2886  switch (static_cast< HTMLButtonElementImpl * >(element)->buttonType()) {
2887  case HTMLButtonElementImpl::SUBMIT:
2888  if (text.isEmpty()) {
2889  text = i18n("Submit");
2890  }
2891  priority = 7;
2892  break;
2893  case HTMLButtonElementImpl::RESET:
2894  if (text.isEmpty()) {
2895  text = i18n("Reset");
2896  }
2897  priority = 5;
2898  break;
2899  default:
2900  priority = 5;
2901  break;
2902  }
2903  break;
2904  case ID_SELECT: // these don't have accesskey attribute, but quick access may be handy
2905  text_before = true;
2906  text_after = true;
2907  priority = 5;
2908  break;
2909  case ID_FRAME:
2910  ignore = true;
2911  break;
2912  default:
2913  ignore = !element->isFocusable();
2914  priority = 2;
2915  break;
2916  }
2917  if (ignore) {
2918  continue;
2919  }
2920 
2921  // build map of manually assigned accesskeys and their targets
2922  DOMString akey = element->getAttribute(ATTR_ACCESSKEY);
2923  if (akey.length() == 1) {
2924  hrefs[url] = akey.string()[ 0 ].toUpper();
2925  continue; // has accesskey set, ignore
2926  }
2927  if (text.isNull() && labels.contains(element)) {
2928  text = labels[ element ];
2929  }
2930  if (text.isNull() && text_before) {
2931  text = getElementText(element, false);
2932  }
2933  if (text.isNull() && text_after) {
2934  text = getElementText(element, true);
2935  }
2936  text = text.trimmed();
2937  // increase priority of items which have explicitly specified accesskeys in the config
2938  const QList< QPair< QString, QChar > > priorities
2939  = m_part->settings()->fallbackAccessKeysAssignments();
2940  for (QList< QPair< QString, QChar > >::ConstIterator it = priorities.begin();
2941  it != priorities.end();
2942  ++it) {
2943  if (text == (*it).first) {
2944  priority = 10;
2945  }
2946  }
2947  AccessKeyData tmp = { element, text, url, priority };
2948  data.append(tmp);
2949  }
2950  }
2951 
2952  QList< QChar > keys;
2953  for (char c = 'A'; c <= 'Z'; ++c) {
2954  keys << c;
2955  }
2956  for (char c = '0'; c <= '9'; ++c) {
2957  keys << c;
2958  }
2959  for (NodeImpl *n = m_part->xmlDocImpl();
2960  n != nullptr;
2961  n = n->traverseNextNode()) {
2962  if (n->isElementNode()) {
2963  ElementImpl *en = static_cast< ElementImpl * >(n);
2964  DOMString s = en->getAttribute(ATTR_ACCESSKEY);
2965  if (s.length() == 1) {
2966  QChar c = s.string()[ 0 ].toUpper();
2967  keys.removeAll(c); // remove manually assigned accesskeys
2968  }
2969  }
2970  }
2971 
2973  for (int priority = 10; priority >= 0; --priority) {
2975  it != data.end();
2976  ) {
2977  if ((*it).priority != priority) {
2978  ++it;
2979  continue;
2980  }
2981  if (keys.isEmpty()) {
2982  break;
2983  }
2984  QString text = (*it).text;
2985  QChar key;
2986  const QString url = (*it).url;
2987  // an identical link already has an accesskey assigned
2988  if (hrefs.contains(url)) {
2989  it = data.erase(it);
2990  continue;
2991  }
2992  if (!text.isEmpty()) {
2993  const QList< QPair< QString, QChar > > priorities
2994  = m_part->settings()->fallbackAccessKeysAssignments();
2995  for (QList< QPair< QString, QChar > >::ConstIterator it = priorities.begin();
2996  it != priorities.end();
2997  ++it)
2998  if (text == (*it).first && keys.contains((*it).second)) {
2999  key = (*it).second;
3000  break;
3001  }
3002  }
3003  // try first to select the first character as the accesskey,
3004  // then first character of the following words,
3005  // and then simply the first free character
3006  if (key.isNull() && !text.isEmpty()) {
3007  const QStringList words = text.split(' ');
3008  for (QStringList::ConstIterator it = words.begin();
3009  it != words.end();
3010  ++it) {
3011  if (keys.contains((*it)[ 0 ].toUpper())) {
3012  key = (*it)[ 0 ].toUpper();
3013  break;
3014  }
3015  }
3016  }
3017  if (key.isNull() && !text.isEmpty()) {
3018  for (int i = 0; i < text.length(); ++i) {
3019  if (keys.contains(text[ i ].toUpper())) {
3020  key = text[ i ].toUpper();
3021  break;
3022  }
3023  }
3024  }
3025  if (key.isNull()) {
3026  key = keys.front();
3027  }
3028  ret[(*it).element ] = key;
3029  keys.removeAll(key);
3030  it = data.erase(it);
3031  // assign the same accesskey also to other elements pointing to the same url
3032  if (!url.isEmpty() && !url.startsWith("javascript:", Qt::CaseInsensitive)) {
3034  it2 != data.end();
3035  ) {
3036  if ((*it2).url == url) {
3037  ret[(*it2).element ] = key;
3038  if (it == it2) {
3039  ++it;
3040  }
3041  it2 = data.erase(it2);
3042  } else {
3043  ++it2;
3044  }
3045  }
3046  }
3047  }
3048  }
3049  return ret;
3050 }
3051 
3052 void KHTMLView::setMediaType(const QString &medium)
3053 {
3054  m_medium = medium;
3055 }
3056 
3057 QString KHTMLView::mediaType() const
3058 {
3059  return m_medium;
3060 }
3061 
3062 bool KHTMLView::pagedMode() const
3063 {
3064  return d->paged;
3065 }
3066 
3067 void KHTMLView::setWidgetVisible(RenderWidget *w, bool vis)
3068 {
3069  if (vis) {
3070  d->visibleWidgets.insert(w, w->widget());
3071  } else {
3072  d->visibleWidgets.remove(w);
3073  }
3074 }
3075 
3076 bool KHTMLView::needsFullRepaint() const
3077 {
3078  return d->needsFullRepaint;
3079 }
3080 
3081 namespace
3082 {
3083 class QPointerDeleter
3084 {
3085 public:
3086  explicit QPointerDeleter(QObject *o) : obj(o) {}
3087  ~QPointerDeleter()
3088  {
3089  delete obj;
3090  }
3091 private:
3092  const QPointer<QObject> obj;
3093 };
3094 }
3095 
3096 void KHTMLView::print(bool quick)
3097 {
3098  QPrinter printer;
3099  print(&printer, quick);
3100 }
3101 
3102 void KHTMLView::print(QPrinter *_printer, bool quick)
3103 {
3104  if (!m_part->xmlDocImpl()) {
3105  return;
3106  }
3107  khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
3108  if (!root) {
3109  return;
3110  }
3111 
3112  QPrinter &printer = *_printer;
3113  QPointer<QPrintDialog> dialog(new QPrintDialog(&printer, this));
3114  QPointer<KHTMLPrintSettings> printSettings(new KHTMLPrintSettings(dialog)); //XXX: doesn't save settings between prints like this
3115  dialog->setOptionTabs(QList<QWidget *>() << printSettings.data());
3116 
3117  const QPointerDeleter dialogDeleter(dialog);
3118 
3119  QString docname = m_part->xmlDocImpl()->URL().toDisplayString();
3120  if (!docname.isEmpty()) {
3121  docname = KStringHandler::csqueeze(docname, 80);
3122  }
3123 
3124  if (quick || (dialog->exec() && dialog)) { /*'this' and thus dialog might have been deleted while exec()!*/
3125  viewport()->setCursor(Qt::WaitCursor); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
3126  // set up KPrinter
3127  printer.setFullPage(false);
3128  printer.setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KHTML_VERSION_MAJOR).arg(KHTML_VERSION_MINOR).arg(KHTML_VERSION_PATCH));
3129  printer.setDocName(docname);
3130 
3131  QPainter *p = new QPainter;
3132  p->begin(&printer);
3133  khtml::setPrintPainter(p);
3134 
3135  m_part->xmlDocImpl()->setPaintDevice(&printer);
3136  QString oldMediaType = mediaType();
3137  setMediaType("print");
3138  // We ignore margin settings for html and body when printing
3139  // and use the default margins from the print-system
3140  // (In Qt 3.0.x the default margins are hardcoded in Qt)
3141  m_part->xmlDocImpl()->setPrintStyleSheet(printSettings->printFriendly() ?
3142  "* { background-image: none !important;"
3143  " background-color: white !important;"
3144  " color: black !important; }"
3145  "body { margin: 0px !important; }"
3146  "html { margin: 0px !important; }" :
3147  "body { margin: 0px !important; }"
3148  "html { margin: 0px !important; }"
3149  );
3150 
3151  // qCDebug(KHTML_LOG) << "printing: physical page width = " << printer.width()
3152  // << " height = " << printer.height();
3153  root->setStaticMode(true);
3154  root->setPagedMode(true);
3155  root->setWidth(printer.width());
3156 // root->setHeight(printer.height());
3157  root->setPageTop(0);
3158  root->setPageBottom(0);
3159  d->paged = true;
3160 
3161  m_part->xmlDocImpl()->styleSelector()->computeFontSizes(printer.logicalDpiY(), 100);
3162  m_part->xmlDocImpl()->updateStyleSelector();
3163  root->setPrintImages(printSettings->printImages());
3164  root->makePageBreakAvoidBlocks();
3165 
3166  root->setNeedsLayoutAndMinMaxRecalc();
3167  root->layout();
3168 
3169  // check sizes ask for action.. (scale or clip)
3170 
3171  bool printHeader = printSettings->printHeader();
3172 
3173  int headerHeight = 0;
3174  QFont headerFont("Sans Serif", 8);
3175 
3177  QString headerMid = docname;
3178  QString headerRight;
3179 
3180  if (printHeader) {
3181  p->setFont(headerFont);
3182  headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
3183  }
3184 
3185  // ok. now print the pages.
3186  // qCDebug(KHTML_LOG) << "printing: html page width = " << root->docWidth()
3187  // << " height = " << root->docHeight();
3188  // qCDebug(KHTML_LOG) << "printing: margins left = " << printer.pageRect().left() - printer.paperRect().left()
3189  // << " top = " << printer.pageRect().top() - printer.paperRect().top();
3190  // qCDebug(KHTML_LOG) << "printing: paper width = " << printer.width()
3191  // << " height = " << printer.height();
3192  // if the width is too large to fit on the paper we just scale
3193  // the whole thing.
3194  int pageWidth = printer.width();
3195  int pageHeight = printer.height();
3196  p->setClipRect(0, 0, pageWidth, pageHeight);
3197 
3198  pageHeight -= headerHeight;
3199 
3200 #ifndef QT_NO_TRANSFORMATIONS
3201  bool scalePage = false;
3202  double scale = 0.0;
3203  if (root->docWidth() > printer.width()) {
3204  scalePage = true;
3205  scale = ((double) printer.width()) / ((double) root->docWidth());
3206  pageHeight = (int)(pageHeight / scale);
3207  pageWidth = (int)(pageWidth / scale);
3208  headerHeight = (int)(headerHeight / scale);
3209  }
3210 #endif
3211  // qCDebug(KHTML_LOG) << "printing: scaled html width = " << pageWidth
3212  // << " height = " << pageHeight;
3213 
3214  root->setHeight(pageHeight);
3215  root->setPageBottom(pageHeight);
3216  root->setNeedsLayout(true);
3217  root->layoutIfNeeded();
3218 // m_part->slotDebugRenderTree();
3219 
3220  // Squeeze header to make it it on the page.
3221  if (printHeader) {
3222  int available_width = printer.width() - 10 -
3223  2 * qMax(p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
3224  p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
3225  if (available_width < 150) {
3226  available_width = 150;
3227  }
3228  int mid_width;
3229  int squeeze = 120;
3230  do {
3231  headerMid = KStringHandler::csqueeze(docname, squeeze);
3232  mid_width = p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
3233  squeeze -= 10;
3234  } while (mid_width > available_width);
3235  }
3236 
3237  int top = 0;
3238  int bottom = 0;
3239  int page = 1;
3240  while (top < root->docHeight()) {
3241  if (top > 0) {
3242  printer.newPage();
3243  }
3244 #ifndef QT_NO_TRANSFORMATIONS
3245  if (scalePage) {
3246  p->scale(scale, scale);
3247  }
3248 #endif
3249  p->save();
3250  p->setClipRect(0, 0, pageWidth, headerHeight);
3251  if (printHeader) {
3252  int dy = p->fontMetrics().lineSpacing();
3253  p->setPen(Qt::black);
3254  p->setFont(headerFont);
3255 
3256  headerRight = QString("#%1").arg(page);
3257 
3258  p->drawText(0, 0, printer.width(), dy, Qt::AlignLeft, headerLeft);
3259  p->drawText(0, 0, printer.width(), dy, Qt::AlignHCenter, headerMid);
3260  p->drawText(0, 0, printer.width(), dy, Qt::AlignRight, headerRight);
3261  }
3262 
3263  p->restore();
3264  p->translate(0, headerHeight - top);
3265 
3266  bottom = top + pageHeight;
3267 
3268  root->setPageTop(top);
3269  root->setPageBottom(bottom);
3270  root->setPageNumber(page);
3271 
3272  root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
3273  // qCDebug(KHTML_LOG) << "printed: page " << page <<" bottom At = " << bottom;
3274 
3275  top = bottom;
3276  p->resetTransform();
3277  page++;
3278  }
3279 
3280  p->end();
3281  delete p;
3282 
3283  // and now reset the layout to the usual one...
3284  root->setPagedMode(false);
3285  root->setStaticMode(false);
3286  d->paged = false;
3287  khtml::setPrintPainter(nullptr);
3288  setMediaType(oldMediaType);
3289  m_part->xmlDocImpl()->setPaintDevice(this);
3290  m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->logicalDpiY(), m_part->fontScaleFactor());
3291  m_part->xmlDocImpl()->updateStyleSelector();
3292  viewport()->unsetCursor();
3293  }
3294 }
3295 
3296 void KHTMLView::slotPaletteChanged()
3297 {
3298  if (!m_part->xmlDocImpl()) {
3299  return;
3300  }
3301  DOM::DocumentImpl *document = m_part->xmlDocImpl();
3302  if (!document->isHTMLDocument()) {
3303  return;
3304  }
3305  khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
3306  if (!root) {
3307  return;
3308  }
3309  root->style()->resetPalette();
3310  NodeImpl *body = static_cast<HTMLDocumentImpl *>(document)->body();
3311  if (!body) {
3312  return;
3313  }
3314  body->setChanged(true);
3315  body->recalcStyle(NodeImpl::Force);
3316 }
3317 
3318 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
3319 {
3320  if (!m_part->xmlDocImpl()) {
3321  return;
3322  }
3323  khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
3324  if (!root) {
3325  return;
3326  }
3327 #ifdef SPEED_DEBUG
3328  d->firstRepaintPending = false;
3329 #endif
3330 
3331  QPaintDevice *opd = m_part->xmlDocImpl()->paintDevice();
3332  m_part->xmlDocImpl()->setPaintDevice(p->device());
3333  root->setPagedMode(true);
3334  root->setStaticMode(true);
3335  root->setWidth(rc.width());
3336 
3337  // save()
3338  QRegion creg = p->clipRegion();
3339  QTransform t = p->worldTransform();
3340  QRect w = p->window();
3341  QRect v = p->viewport();
3342  bool vte = p->viewTransformEnabled();
3343  bool wme = p->worldMatrixEnabled();
3344 
3345  p->setClipRect(rc);
3346  p->translate(rc.left(), rc.top());
3347  double scale = ((double) rc.width() / (double) root->docWidth());
3348  int height = (int)((double) rc.height() / scale);
3349 #ifndef QT_NO_TRANSFORMATIONS
3350  p->scale(scale, scale);
3351 #endif
3352  root->setPageTop(yOff);
3353  root->setPageBottom(yOff + height);
3354 
3355  root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
3356  if (more) {
3357  *more = yOff + height < root->docHeight();
3358  }
3359 
3360  // restore()
3361  p->setWorldTransform(t);
3362  p->setWindow(w);
3363  p->setViewport(v);
3364  p->setViewTransformEnabled(vte);
3365  p->setWorldMatrixEnabled(wme);
3366  if (!creg.isEmpty()) {
3367  p->setClipRegion(creg);
3368  } else {
3370  }
3371 
3372  root->setPagedMode(false);
3373  root->setStaticMode(false);
3374  m_part->xmlDocImpl()->setPaintDevice(opd);
3375 }
3376 
3377 void KHTMLView::render(QPainter *p, const QRect &r, const QPoint &off)
3378 {
3379 #ifdef SPEED_DEBUG
3380  d->firstRepaintPending = false;
3381 #endif
3382  QRect clip(off.x() + r.x(), off.y() + r.y(), r.width(), r.height());
3383  if (!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
3384  p->fillRect(clip, palette().brush(QPalette::Active, QPalette::Base));
3385  return;
3386  }
3387  QPaintDevice *opd = m_part->xmlDocImpl()->paintDevice();
3388  m_part->xmlDocImpl()->setPaintDevice(p->device());
3389 
3390  // save()
3391  QRegion creg = p->clipRegion();
3392  QTransform t = p->worldTransform();
3393  QRect w = p->window();
3394  QRect v = p->viewport();
3395  bool vte = p->viewTransformEnabled();
3396  bool wme = p->worldMatrixEnabled();
3397 
3398  p->setClipRect(clip);
3400  p->translate(off.x() - contentsX(), off.y() - contentsY());
3401 
3402  m_part->xmlDocImpl()->renderer()->layer()->paint(p, rect);
3403 
3404  // restore()
3405  p->setWorldTransform(t);
3406  p->setWindow(w);
3407  p->setViewport(v);
3408  p->setViewTransformEnabled(vte);
3409  p->setWorldMatrixEnabled(wme);
3410  if (!creg.isEmpty()) {
3411  p->setClipRegion(creg);
3412  } else {
3414  }
3415 
3416  m_part->xmlDocImpl()->setPaintDevice(opd);
3417 }
3418 
3419 void KHTMLView::setHasStaticBackground(bool partial)
3420 {
3421  // full static iframe is irreversible for now
3422  if (d->staticWidget == KHTMLViewPrivate::SBFull && m_kwp->isRedirected()) {
3423  return;
3424  }
3425 
3426  d->staticWidget = partial ?
3427  KHTMLViewPrivate::SBPartial : KHTMLViewPrivate::SBFull;
3428 }
3429 
3430 void KHTMLView::setHasNormalBackground()
3431 {
3432  // full static iframe is irreversible for now
3433  if (d->staticWidget == KHTMLViewPrivate::SBFull && m_kwp->isRedirected()) {
3434  return;
3435  }
3436 
3437  d->staticWidget = KHTMLViewPrivate::SBNone;
3438 }
3439 
3440 void KHTMLView::addStaticObject(bool fixed)
3441 {
3442  if (fixed) {
3443  d->fixedObjectsCount++;
3444  } else {
3445  d->staticObjectsCount++;
3446  }
3447 
3448  setHasStaticBackground(true /*partial*/);
3449 }
3450 
3451 void KHTMLView::removeStaticObject(bool fixed)
3452 {
3453  if (fixed) {
3454  d->fixedObjectsCount--;
3455  } else {
3456  d->staticObjectsCount--;
3457  }
3458 
3459  assert(d->fixedObjectsCount >= 0 && d->staticObjectsCount >= 0);
3460 
3461  if (!d->staticObjectsCount && !d->fixedObjectsCount) {
3462  setHasNormalBackground();
3463  } else {
3464  setHasStaticBackground(true /*partial*/);
3465  }
3466 }
3467 
3469 {
3470 #ifndef KHTML_NO_SCROLLBARS
3471  d->vpolicy = policy;
3473 #else
3474  Q_UNUSED(policy);
3475 #endif
3476 }
3477 
3479 {
3480 #ifndef KHTML_NO_SCROLLBARS
3481  d->hpolicy = policy;
3483 #else
3484  Q_UNUSED(policy);
3485 #endif
3486 }
3487 
3488 void KHTMLView::restoreScrollBar()
3489 {
3490  int ow = visibleWidth();
3492  if (visibleWidth() != ow) {
3493  layout();
3494  }
3495  d->prevScrollbarVisible = verticalScrollBar()->isVisible();
3496 }
3497 
3498 QStringList KHTMLView::formCompletionItems(const QString &name) const
3499 {
3500  if (!m_part->settings()->isFormCompletionEnabled()) {
3501  return QStringList();
3502  }
3503  if (!d->formCompletions) {
3504  d->formCompletions = new KConfig(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "khtml/formcompletions");
3505  }
3506  return d->formCompletions->group("").readEntry(name, QStringList());
3507 }
3508 
3509 void KHTMLView::clearCompletionHistory(const QString &name)
3510 {
3511  if (!d->formCompletions) {
3512  d->formCompletions = new KConfig(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "khtml/formcompletions");
3513  }
3514  d->formCompletions->group("").writeEntry(name, "");
3515  d->formCompletions->sync();
3516 }
3517 
3518 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
3519 {
3520  if (!m_part->settings()->isFormCompletionEnabled()) {
3521  return;
3522  }
3523  // don't store values that are all numbers or just numbers with
3524  // dashes or spaces as those are likely credit card numbers or
3525  // something similar
3526  bool cc_number(true);
3527  for (int i = 0; i < value.length(); ++i) {
3528  QChar c(value[i]);
3529  if (!c.isNumber() && c != '-' && !c.isSpace()) {
3530  cc_number = false;
3531  break;
3532  }
3533  }
3534  if (cc_number) {
3535  return;
3536  }
3537  QStringList items = formCompletionItems(name);
3538  if (!items.contains(value)) {
3539  items.prepend(value);
3540  }
3541  while ((int)items.count() > m_part->settings()->maxFormCompletionItems()) {
3542  items.erase(items.isEmpty() ? items.end() : --items.end());
3543  }
3544  d->formCompletions->group("").writeEntry(name, items);
3545 }
3546 
3547 void KHTMLView::addNonPasswordStorableSite(const QString &host)
3548 {
3549  if (!d->formCompletions) {
3550  d->formCompletions = new KConfig(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "khtml/formcompletions");
3551  }
3552 
3553  KConfigGroup cg(d->formCompletions, "NonPasswordStorableSites");
3554  QStringList sites = cg.readEntry("Sites", QStringList());
3555  sites.append(host);
3556  cg.writeEntry("Sites", sites);
3557  cg.sync();
3558 }
3559 
3560 void KHTMLView::delNonPasswordStorableSite(const QString &host)
3561 {
3562  if (!d->formCompletions) {
3563  d->formCompletions = new KConfig(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "khtml/formcompletions");
3564  }
3565 
3566  KConfigGroup cg(d->formCompletions, "NonPasswordStorableSites");
3567  QStringList sites = cg.readEntry("Sites", QStringList());
3568  sites.removeOne(host);
3569  cg.writeEntry("Sites", sites);
3570  cg.sync();
3571 }
3572 
3573 bool KHTMLView::nonPasswordStorableSite(const QString &host) const
3574 {
3575  if (!d->formCompletions) {
3576  d->formCompletions = new KConfig(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "khtml/formcompletions");
3577  }
3578  QStringList sites = d->formCompletions->group("NonPasswordStorableSites").readEntry("Sites", QStringList());
3579  return (sites.indexOf(host) != -1);
3580 }
3581 
3582 // returns true if event should be swallowed
3583 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
3584  DOM::NodeImpl *targetNodeNonShared, bool cancelable,
3585  int detail, QMouseEvent *_mouse, bool setUnder,
3586  int mouseEventType, int orient)
3587 {
3588  // if the target node is a text node, dispatch on the parent node - rdar://4196646 (and #76948)
3589  if (targetNode && targetNode->isTextNode()) {
3590  targetNode = targetNode->parentNode();
3591  }
3592 
3593  if (d->underMouse) {
3594  d->underMouse->deref();
3595  }
3596  d->underMouse = targetNode;
3597  if (d->underMouse) {
3598  d->underMouse->ref();
3599  }
3600 
3601  if (d->underMouseNonShared) {
3602  d->underMouseNonShared->deref();
3603  }
3604  d->underMouseNonShared = targetNodeNonShared;
3605  if (d->underMouseNonShared) {
3606  d->underMouseNonShared->ref();
3607  }
3608 
3609  bool isWheelEvent = (mouseEventType == DOM::NodeImpl::MouseWheel);
3610 
3611  int exceptioncode = 0;
3612  int pageX = _mouse->x();
3613  int pageY = _mouse->y();
3614  revertTransforms(pageX, pageY);
3615  int clientX = pageX - contentsX();
3616  int clientY = pageY - contentsY();
3617  int screenX = _mouse->globalX();
3618  int screenY = _mouse->globalY();
3619  int button = -1;
3620  switch (_mouse->button()) {
3621  case Qt::LeftButton:
3622  button = 0;
3623  break;
3624  case Qt::MidButton:
3625  button = 1;
3626  break;
3627  case Qt::RightButton:
3628  button = 2;
3629  break;
3630  default:
3631  break;
3632  }
3633  if (d->accessKeysEnabled && d->accessKeysPreActivate && button != -1) {
3634  d->accessKeysPreActivate = false;
3635  }
3636 
3637  bool ctrlKey = (_mouse->modifiers() & Qt::ControlModifier);
3638  bool altKey = (_mouse->modifiers() & Qt::AltModifier);
3639  bool shiftKey = (_mouse->modifiers() & Qt::ShiftModifier);
3640  bool metaKey = (_mouse->modifiers() & Qt::MetaModifier);
3641 
3642  // mouseout/mouseover
3643  if (setUnder && d->oldUnderMouse != targetNode) {
3644  if (d->oldUnderMouse && d->oldUnderMouse->document() != m_part->xmlDocImpl()) {
3645  d->oldUnderMouse->deref();
3646  d->oldUnderMouse = nullptr;
3647  }
3648  // send mouseout event to the old node
3649  if (d->oldUnderMouse) {
3650  // send mouseout event to the old node
3651  MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
3652  true, true, m_part->xmlDocImpl()->defaultView(),
3653  0, screenX, screenY, clientX, clientY, pageX, pageY,
3654  ctrlKey, altKey, shiftKey, metaKey,
3655  button, targetNode);
3656  me->ref();
3657  d->oldUnderMouse->dispatchEvent(me, exceptioncode, true);
3658  me->deref();
3659  }
3660  // send mouseover event to the new node
3661  if (targetNode) {
3662  MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
3663  true, true, m_part->xmlDocImpl()->defaultView(),
3664  0, screenX, screenY, clientX, clientY, pageX, pageY,
3665  ctrlKey, altKey, shiftKey, metaKey,
3666  button, d->oldUnderMouse);
3667 
3668  me->ref();
3669  targetNode->dispatchEvent(me, exceptioncode, true);
3670  me->deref();
3671  }
3672  if (d->oldUnderMouse) {
3673  d->oldUnderMouse->deref();
3674  }
3675  d->oldUnderMouse = targetNode;
3676  if (d->oldUnderMouse) {
3677  d->oldUnderMouse->ref();
3678  }
3679  }
3680 
3681  bool swallowEvent = false;
3682 
3683  if (targetNode) {
3684  // if the target node is a disabled widget, we don't want any full-blown mouse events
3685  if (targetNode->isGenericFormElement()
3686  && static_cast<HTMLGenericFormElementImpl *>(targetNode)->disabled()) {
3687  return true;
3688  }
3689 
3690  // send the actual event
3691  bool dblclick = (eventId == EventImpl::CLICK_EVENT &&
3692  _mouse->type() == QEvent::MouseButtonDblClick);
3693  MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
3694  true, cancelable, m_part->xmlDocImpl()->defaultView(),
3695  detail, screenX, screenY, clientX, clientY, pageX, pageY,
3696  ctrlKey, altKey, shiftKey, metaKey,
3697  button, nullptr, isWheelEvent ? nullptr : _mouse, dblclick,
3698  isWheelEvent ? static_cast<MouseEventImpl::Orientation>(orient) : MouseEventImpl::ONone);
3699  me->ref();
3700  if (!d->m_mouseEventsTarget && RenderLayer::gScrollBar && eventId == EventImpl::MOUSEDOWN_EVENT)
3701  // button is pressed inside a layer scrollbar, so make it the target for future mousemove events until released
3702  {
3703  d->m_mouseEventsTarget = RenderLayer::gScrollBar;
3704  }
3705  if (d->m_mouseEventsTarget && qobject_cast<QScrollBar *>(d->m_mouseEventsTarget) &&
3706  dynamic_cast<KHTMLWidget *>(static_cast<QWidget *>(d->m_mouseEventsTarget))) {
3707  // we have a sticky mouse event target and it is a layer's scrollbar. Forward events manually.
3708  // ### should use the dom
3709  KHTMLWidget *w = dynamic_cast<KHTMLWidget *>(static_cast<QWidget *>(d->m_mouseEventsTarget));
3710  QPoint p = w->m_kwp->absolutePos();
3711  QMouseEvent fw(_mouse->type(), QPoint(pageX, pageY) - p, _mouse->button(), _mouse->buttons(), _mouse->modifiers());
3712  static_cast<RenderWidget::EventPropagator *>(static_cast<QWidget *>(d->m_mouseEventsTarget))->sendEvent(&fw);
3713  if (_mouse->type() == QMouseEvent::MouseButtonPress && _mouse->button() == Qt::RightButton) {
3715  static_cast<RenderWidget::EventPropagator *>(static_cast<QWidget *>(d->m_mouseEventsTarget))->sendEvent(&cme);
3716  d->m_mouseEventsTarget = nullptr;
3717  }
3718  swallowEvent = true;
3719  } else {
3720  targetNode->dispatchEvent(me, exceptioncode, true);
3721  bool defaultHandled = me->defaultHandled();
3722  if (defaultHandled || me->defaultPrevented()) {
3723  swallowEvent = true;
3724  }
3725  }
3726  if (eventId == EventImpl::MOUSEDOWN_EVENT && !me->defaultPrevented()) {
3727  // Focus should be shifted on mouse down, not on a click. -dwh
3728  // Blur current focus node when a link/button is clicked; this
3729  // is expected by some sites that rely on onChange handlers running
3730  // from form fields before the button click is processed.
3731  DOM::NodeImpl *nodeImpl = targetNode;
3732  for (; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode()) {
3733  }
3734  if (nodeImpl && nodeImpl->isMouseFocusable()) {
3735  m_part->xmlDocImpl()->setFocusNode(nodeImpl);
3736  } else if (!nodeImpl || !nodeImpl->focused()) {
3737  m_part->xmlDocImpl()->setFocusNode(nullptr);
3738  }
3739  }
3740  me->deref();
3741  }
3742 
3743  return swallowEvent;
3744 }
3745 
3746 void KHTMLView::setIgnoreWheelEvents(bool e)
3747 {
3748  d->ignoreWheelEvents = e;
3749 }
3750 
3751 #ifndef QT_NO_WHEELEVENT
3752 
3753 void KHTMLView::wheelEvent(QWheelEvent *e)
3754 {
3755  // check if we should reset the state of the indicator describing if
3756  // we are currently scrolling the view as a result of wheel events
3757  if (d->scrollingFromWheel != QPoint(-1, -1) && d->scrollingFromWheel != QCursor::pos()) {
3758  d->scrollingFromWheel = d->scrollingFromWheelTimerId ? QCursor::pos() : QPoint(-1, -1);
3759  }
3760 
3761  if (d->accessKeysEnabled && d->accessKeysPreActivate) {
3762  d->accessKeysPreActivate = false;
3763  }
3764 
3766  emit zoomView(- e->delta());
3767  e->accept();
3768  } else if (d->firstLayoutPending) {
3769  e->accept();
3770  } else if (!m_kwp->isRedirected() &&
3771  ((e->orientation() == Qt::Vertical &&
3772  ((d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
3773  || (e->delta() > 0 && contentsY() <= 0)
3774  || (e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())))
3775  ||
3776  (e->orientation() == Qt::Horizontal &&
3777  ((d->ignoreWheelEvents && !horizontalScrollBar()->isVisible())
3778  || (e->delta() > 0 && contentsX() <= 0)
3779  || (e->delta() < 0 && contentsX() >= contentsWidth() - visibleWidth()))))
3780  && m_part->parentPart()) {
3781  if (m_part->parentPart()->view()) {
3782  m_part->parentPart()->view()->wheelEvent(e);
3783  }
3784  e->ignore();
3785  } else {
3786  int xm = e->x();
3787  int ym = e->y();
3788  revertTransforms(xm, ym);
3789 
3790  DOM::NodeImpl::MouseEvent mev(e->buttons(), DOM::NodeImpl::MouseWheel);
3791  m_part->xmlDocImpl()->prepareMouseEvent(false, xm, ym, &mev);
3792 
3793  MouseEventImpl::Orientation o = MouseEventImpl::OVertical;
3794  if (e->orientation() == Qt::Horizontal) {
3795  o = MouseEventImpl::OHorizontal;
3796  }
3797 
3798  QMouseEvent _mouse(QEvent::MouseMove, e->pos(), Qt::NoButton, e->buttons(), e->modifiers());
3799  bool swallow = dispatchMouseEvent(EventImpl::KHTML_MOUSEWHEEL_EVENT, mev.innerNode.handle(), mev.innerNonSharedNode.handle(),
3800  true, -e->delta() / 40, &_mouse, true, DOM::NodeImpl::MouseWheel, o);
3801 
3802  if (swallow) {
3803  return;
3804  }
3805 
3806  d->scrollBarMoved = true;
3807  d->scrollingFromWheel = QCursor::pos();
3808  if (d->smoothScrollMode != SSMDisabled) {
3809  d->shouldSmoothScroll = true;
3810  }
3811  if (d->scrollingFromWheelTimerId) {
3812  killTimer(d->scrollingFromWheelTimerId);
3813  }
3814  d->scrollingFromWheelTimerId = startTimer(400);
3815 
3816  if (m_part->parentPart()) {
3817  // don't propagate if we are a sub-frame and our scrollbars are already at end of range
3818  bool h = (static_cast<QWheelEvent *>(e)->orientation() == Qt::Horizontal);
3819  bool d = (static_cast<QWheelEvent *>(e)->delta() < 0);
3821  QScrollBar *vsb = verticalScrollBar();
3822  if ((h && ((d && hsb->value() == hsb->maximum()) || (!d && hsb->value() == hsb->minimum()))) ||
3823  (!h && ((d && vsb->value() == vsb->maximum()) || (!d && vsb->value() == vsb->minimum())))) {
3824  e->accept();
3825  return;
3826  }
3827  }
3829  }
3830 
3831 }
3832 #endif
3833 
3834 void KHTMLView::dragEnterEvent(QDragEnterEvent *ev)
3835 {
3836  // Still overridden for BC reasons only...
3838 }
3839 
3840 void KHTMLView::dropEvent(QDropEvent *ev)
3841 {
3842  // Still overridden for BC reasons only...
3844 }
3845 
3846 void KHTMLView::focusInEvent(QFocusEvent *e)
3847 {
3848  DOM::NodeImpl *fn = m_part->xmlDocImpl() ? m_part->xmlDocImpl()->focusNode() : nullptr;
3849  if (fn && fn->renderer() && fn->renderer()->isWidget() &&
3850  (e->reason() != Qt::MouseFocusReason) &&
3851  static_cast<khtml::RenderWidget *>(fn->renderer())->widget()) {
3852  static_cast<khtml::RenderWidget *>(fn->renderer())->widget()->setFocus();
3853  }
3854  m_part->setSelectionVisible();
3856 }
3857 
3858 void KHTMLView::focusOutEvent(QFocusEvent *e)
3859 {
3860  if (m_part) {
3861  m_part->stopAutoScroll();
3862  m_part->setSelectionVisible(false);
3863  }
3864 
3865  if (d->cursorIconWidget) {
3866  d->cursorIconWidget->hide();
3867  }
3868 
3870 }
3871 
3872 void KHTMLView::scrollContentsBy(int dx, int dy)
3873 {
3874  if (!dx && !dy) {
3875  return;
3876  }
3877 
3878  if (!d->firstLayoutPending && !d->complete && m_part->xmlDocImpl() &&
3879  d->layoutSchedulingEnabled) {
3880  // contents scroll while we are not complete: we need to check our layout *now*
3881  khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
3882  if (root && root->needsLayout()) {
3883  unscheduleRelayout();
3884  layout();
3885  }
3886  }
3887 
3888  if (d->shouldSmoothScroll && d->smoothScrollMode != SSMDisabled && m_part->xmlDocImpl() &&
3889  m_part->xmlDocImpl()->renderer() && (d->smoothScrollMode != SSMWhenEfficient || d->smoothScrollMissedDeadlines != sWayTooMany)) {
3890 
3891  bool doSmoothScroll = (!d->staticWidget || d->smoothScrollMode == SSMEnabled);
3892 
3893  int numStaticPixels = 0;
3894  QRegion r = static_cast<RenderCanvas *>(m_part->xmlDocImpl()->renderer())->staticRegion();
3895 
3896  // only do smooth scrolling if static region is relatively small
3897  if (!doSmoothScroll && d->staticWidget == KHTMLViewPrivate::SBPartial && r.rects().size() <= 10) {
3898  foreach (const QRect &rr, r.rects()) {
3899  numStaticPixels += rr.width() * rr.height();
3900  }
3901  if ((numStaticPixels < sSmoothScrollMinStaticPixels) || (numStaticPixels * 8 < visibleWidth()*visibleHeight())) {
3902  doSmoothScroll = true;
3903  }
3904  }
3905  if (doSmoothScroll) {
3906  setupSmoothScrolling(dx, dy);
3907  return;
3908  }
3909  }
3910 
3911  if (underMouse() && QToolTip::isVisible()) {
3913  }
3914 
3915  if (!d->scrollingSelf) {
3916  d->scrollBarMoved = true;
3917  d->contentsMoving = true;
3918  // ensure quick reset of contentsMoving flag
3919  scheduleRepaint(0, 0, 0, 0);
3920  }
3921 
3922  if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->documentElement()) {
3923  m_part->xmlDocImpl()->documentElement()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false);
3924  }
3925 
3927  dx = -dx;
3928  }
3929 
3930  if (!d->smoothScrolling) {
3931  d->updateContentsXY();
3932  } else {
3933  d->contentsX -= dx;
3934  d->contentsY -= dy;
3935  }
3936  if (widget()->pos() != QPoint(0, 0)) {
3937  // qCDebug(KHTML_LOG) << "Static widget wasn't positioned at (0,0). This should NOT happen. Please report this event to developers.";
3938  widget()->move(0, 0);
3939  }
3940 
3941  QWidget *w = widget();
3942  QPoint off;
3943  if (m_kwp->isRedirected()) {
3944  // This is a redirected sub frame. Translate to root view context
3945  KHTMLView *v = m_kwp->rootViewPos(off);
3946  if (v) {
3947  w = v->widget();
3948  }
3949  off = viewport()->mapTo(this, off);
3950  }
3951 
3952  if (d->staticWidget) {
3953 
3954  // now remove from view the external widgets that must have completely
3955  // disappeared after dx/dy scroll delta is effective
3956  if (!d->visibleWidgets.isEmpty()) {
3957  checkExternalWidgetsPosition();
3958  }
3959 
3960  if (d->staticWidget == KHTMLViewPrivate::SBPartial
3961  && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer()) {
3962  // static objects might be selectively repainted, like stones in flowing water
3963  QRegion r = static_cast<RenderCanvas *>(m_part->xmlDocImpl()->renderer())->staticRegion();
3964  r.translate(-contentsX(), -contentsY());
3965  QVector<QRect> ar = r.rects();
3966 
3967  for (int i = 0; i < ar.size(); ++i) {
3968  widget()->update(ar[i]);
3969  }
3970  r = QRegion(QRect(0, 0, visibleWidth(), visibleHeight())) - r;
3971  ar = r.rects();
3972  for (int i = 0; i < ar.size(); ++i) {
3973  w->scroll(dx, dy, ar[i].translated(off));
3974  }
3975  d->scrollExternalWidgets(dx, dy);
3976  } else {
3977  // we can't avoid a full update
3978  widget()->update();
3979  }
3980  if (d->accessKeysActivated) {
3981  d->scrollAccessKeys(dx, dy);
3982  }
3983 
3984  return;
3985  }
3986 
3987  if (m_kwp->isRedirected()) {
3988  const QRect rect(off.x(), off.y(), visibleWidth() * d->zoomLevel / 100, visibleHeight() * d->zoomLevel / 100);
3989  w->scroll(dx, dy, rect);
3990  if (d->zoomLevel != 100) {
3991  w->update(rect); // without this update we are getting bad rendering when an iframe is zoomed in
3992  }
3993  } else {
3994  widget()->scroll(dx, dy, widget()->rect() & viewport()->rect());
3995  }
3996 
3997  d->scrollExternalWidgets(dx, dy);
3998  if (d->accessKeysActivated) {
3999  d->scrollAccessKeys(dx, dy);
4000  }
4001 }
4002 
4003 void KHTMLView::setupSmoothScrolling(int dx, int dy)
4004 {
4005  // old or minimum speed
4006  int ddx = qMax(d->steps ? abs(d->dx) / d->steps : 0, 3);
4007  int ddy = qMax(d->steps ? abs(d->dy) / d->steps : 0, 3);
4008 
4009  // full scroll is remaining scroll plus new scroll
4010  d->dx = d->dx + dx;
4011  d->dy = d->dy + dy;
4012 
4013  if (d->dx == 0 && d->dy == 0) {
4014  d->stopScrolling();
4015  return;
4016  }
4017 
4018  d->steps = (sSmoothScrollTime - 1) / sSmoothScrollTick + 1;
4019 
4020  if (qMax(abs(d->dx), abs(d->dy)) / d->steps < qMax(ddx, ddy)) {
4021  // Don't move slower than average 4px/step in minimum one direction
4022  // This means fewer than normal steps
4023  d->steps = qMax((abs(d->dx) + ddx - 1) / ddx, (abs(d->dy) + ddy - 1) / ddy);
4024  if (d->steps < 1) {
4025  d->steps = 1;
4026  }
4027  }
4028 
4029  d->smoothScrollStopwatch.start();
4030  if (!d->smoothScrolling) {
4031  d->startScrolling();
4032  scrollTick();
4033  }
4034 }
4035 
4036 void KHTMLView::scrollTick()
4037 {
4038  if (d->dx == 0 && d->dy == 0) {
4039  d->stopScrolling();
4040  return;
4041  }
4042 
4043  if (d->steps < 1) {
4044  d->steps = 1;
4045  }
4046  int takesteps = d->smoothScrollStopwatch.restart() / sSmoothScrollTick;
4047  int scroll_x = 0;
4048  int scroll_y = 0;
4049  if (takesteps < 1) {
4050  takesteps = 1;
4051  }
4052  if (takesteps > d->steps) {
4053  takesteps = d->steps;
4054  }
4055  for (int i = 0; i < takesteps; i++) {
4056  int ddx = (d->dx / (d->steps + 1)) * 2;
4057  int ddy = (d->dy / (d->steps + 1)) * 2;
4058 
4059  // limit step to requested scrolling distance
4060  if (abs(ddx) > abs(d->dx)) {
4061  ddx = d->dx;
4062  }
4063  if (abs(ddy) > abs(d->dy)) {
4064  ddy = d->dy;
4065  }
4066 
4067  // update remaining scroll
4068  d->dx -= ddx;
4069  d->dy -= ddy;
4070  scroll_x += ddx;
4071  scroll_y += ddy;
4072  d->steps--;
4073  }
4074 
4075  d->shouldSmoothScroll = false;
4076  scrollContentsBy(scroll_x, scroll_y);
4077 
4078  if (takesteps < 2) {
4079  d->smoothScrollMissedDeadlines = 0;
4080  } else {
4081  if (d->smoothScrollMissedDeadlines != sWayTooMany &&
4082  (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->parsing())) {
4083  d->smoothScrollMissedDeadlines++;
4084  if (d->smoothScrollMissedDeadlines >= sMaxMissedDeadlines) {
4085  // we missed many deadlines in a row!
4086  // time to signal we had enough..
4087  d->smoothScrollMissedDeadlines = sWayTooMany;
4088  }
4089  }
4090  }
4091 }
4092 
4093 void KHTMLView::addChild(QWidget *child, int x, int y)
4094 {
4095  if (!child) {
4096  return;
4097  }
4098 
4099  if (child->parent() != widget()) {
4100  child->setParent(widget());
4101  }
4102 
4103  // ### handle pseudo-zooming of non-redirected widgets (e.g. just resize'em)
4104 
4105  child->move(x - contentsX(), y - contentsY());
4106 }
4107 
4108 void KHTMLView::timerEvent(QTimerEvent *e)
4109 {
4110 // qCDebug(KHTML_LOG) << "timer event " << e->timerId();
4111  if (e->timerId() == d->scrollTimerId) {
4112  if (d->scrollSuspended) {
4113  return;
4114  }
4115  switch (d->scrollDirection) {
4116  case KHTMLViewPrivate::ScrollDown:
4117  if (contentsY() + visibleHeight() >= contentsHeight()) {
4118  d->newScrollTimer(this, 0);
4119  } else {
4120  verticalScrollBar()->setValue(verticalScrollBar()->value() + d->scrollBy);
4121  }
4122  break;
4123  case KHTMLViewPrivate::ScrollUp:
4124  if (contentsY() <= 0) {
4125  d->newScrollTimer(this, 0);
4126  } else {
4127  verticalScrollBar()->setValue(verticalScrollBar()->value() - d->scrollBy);
4128  }
4129  break;
4130  case KHTMLViewPrivate::ScrollRight:
4131  if (contentsX() + visibleWidth() >= contentsWidth()) {
4132  d->newScrollTimer(this, 0);
4133  } else {
4134  horizontalScrollBar()->setValue(horizontalScrollBar()->value() + d->scrollBy);
4135  }
4136  break;
4137  case KHTMLViewPrivate::ScrollLeft:
4138  if (contentsX() <= 0) {
4139  d->newScrollTimer(this, 0);
4140  } else {
4141  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - d->scrollBy);
4142  }
4143  break;
4144  }
4145  return;
4146  } else if (e->timerId() == d->scrollingFromWheelTimerId) {
4147  killTimer(d->scrollingFromWheelTimerId);
4148  d->scrollingFromWheelTimerId = 0;
4149  } else if (e->timerId() == d->layoutTimerId) {
4150  if (d->firstLayoutPending && d->layoutAttemptCounter < 4
4151  && (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->readyForLayout())) {
4152  d->layoutAttemptCounter++;
4153  killTimer(d->layoutTimerId);
4154  d->layoutTimerId = 0;
4155  scheduleRelayout();
4156  return;
4157  }
4158  layout();
4159  d->scheduledLayoutCounter++;
4160  if (d->firstLayoutPending) {
4161  d->firstLayoutPending = false;
4162  verticalScrollBar()->setEnabled(true);
4164  }
4165  }
4166 
4167  d->contentsMoving = false;
4168  if (m_part->xmlDocImpl()) {
4169  DOM::DocumentImpl *document = m_part->xmlDocImpl();
4170  khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
4171 
4172  if (root && root->needsLayout()) {
4173  if (d->repaintTimerId) {
4174  killTimer(d->repaintTimerId);
4175  }
4176  d->repaintTimerId = 0;
4177  scheduleRelayout();
4178  return;
4179  }
4180  }
4181 
4182  if (d->repaintTimerId) {
4183  killTimer(d->repaintTimerId);
4184  }
4185  d->repaintTimerId = 0;
4186 
4187  QRect updateRegion;
4188  const QVector<QRect> rects = d->updateRegion.rects();
4189 
4190  d->updateRegion = QRegion();
4191 
4192  if (rects.size()) {
4193  updateRegion = rects[0];
4194  }
4195 
4196  for (int i = 1; i < rects.size(); ++i) {
4197  QRect newRegion = updateRegion.united(rects[i]);
4198  if (2 * newRegion.height() > 3 * updateRegion.height()) {
4199  repaintContents(updateRegion);
4200  updateRegion = rects[i];
4201  } else {
4202  updateRegion = newRegion;
4203  }
4204  }
4205 
4206  if (!updateRegion.isNull()) {
4207  repaintContents(updateRegion);
4208  }
4209 
4210  // As widgets can only be accurately positioned during painting, every layout might
4211  // dissociate a widget from its RenderWidget. E.g: if a RenderWidget was visible before layout, but the layout
4212  // pushed it out of the viewport, it will not be repainted, and consequently it's associated widget won't be repositioned.
4213  // Thus we need to check each supposedly 'visible' widget at the end of layout, and remove it in case it's no more in sight.
4214 
4215  if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
4216  checkExternalWidgetsPosition();
4217  }
4218 
4219  d->dirtyLayout = false;
4220 
4221  emit repaintAccessKeys();
4222  if (d->emitCompletedAfterRepaint) {
4223  bool full = d->emitCompletedAfterRepaint == KHTMLViewPrivate::CSFull;
4224  d->emitCompletedAfterRepaint = KHTMLViewPrivate::CSNone;
4225  if (full) {
4226  emit m_part->completed();
4227  } else {
4228  emit m_part->completed(true);
4229  }
4230  }
4231 }
4232 
4233 void KHTMLView::checkExternalWidgetsPosition()
4234 {
4235  QWidget *w;
4236  QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
4237  QList<RenderWidget *> toRemove;
4238  QHashIterator<void *, QWidget *> it(d->visibleWidgets);
4239  while (it.hasNext()) {
4240  int xp = 0, yp = 0;
4241  it.next();
4242  RenderWidget *rw = static_cast<RenderWidget *>(it.key());
4243  if (!rw->absolutePosition(xp, yp) ||
4244  !visibleRect.intersects(QRect(xp, yp, it.value()->width(), it.value()->height()))) {
4245  toRemove.append(rw);
4246  }
4247  }
4248  foreach (RenderWidget *r, toRemove)
4249  if ((w = d->visibleWidgets.take(r))) {
4250  w->move(0, -500000);
4251  }
4252 }
4253 
4254 void KHTMLView::scheduleRelayout(khtml::RenderObject * /*clippedObj*/)
4255 {
4256  if (!d->layoutSchedulingEnabled || d->layoutTimerId) {
4257  return;
4258  }
4259 
4260  int time = 0;
4261  if (d->firstLayoutPending) {
4262  // Any repaint happening while we have no content blanks the viewport ("white flash").
4263  // Hence the need to delay the first layout as much as we can.
4264  // Only if the document gets stuck for too long in incomplete state will we allow the blanking.
4265  time = d->layoutAttemptCounter ?
4266  sLayoutAttemptDelay + sLayoutAttemptIncrement * d->layoutAttemptCounter : sFirstLayoutDelay;
4267  } else if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()) {
4268  // Delay between successive layouts in parsing mode.
4269  // Increment reflects the decaying importance of visual feedback over time.
4270  time = qMin(2000, sParsingLayoutsInterval + d->scheduledLayoutCounter * sParsingLayoutsIncrement);
4271  }
4272  d->layoutTimerId = startTimer(time);
4273 }
4274 
4275 void KHTMLView::unscheduleRelayout()
4276 {
4277  if (!d->layoutTimerId) {
4278  return;
4279  }
4280 
4281  killTimer(d->layoutTimerId);
4282  d->layoutTimerId = 0;
4283 }
4284 
4285 void KHTMLView::unscheduleRepaint()
4286 {
4287  if (!d->repaintTimerId) {
4288  return;
4289  }
4290 
4291  killTimer(d->repaintTimerId);
4292  d->repaintTimerId = 0;
4293 }
4294 
4295 void KHTMLView::scheduleRepaint(int x, int y, int w, int h, bool asap)
4296 {
4297  bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
4298 
4299 // qCDebug(KHTML_LOG) << "parsing " << parsing;
4300 // qCDebug(KHTML_LOG) << "complete " << d->complete;
4301 
4302  int time = parsing && !d->firstLayoutPending ? 150 : (!asap ? (!d->complete ? 80 : 20) : 0);
4303 
4304 #ifdef DEBUG_FLICKER
4305  QPainter p;
4306  p.begin(viewport());
4307 
4308  int vx, vy;
4309  contentsToViewport(x, y, vx, vy);
4310  p.fillRect(vx, vy, w, h, Qt::red);
4311  p.end();
4312 #endif
4313 
4314  d->updateRegion = d->updateRegion.united(QRect(x, y, w, h));
4315 
4316  if (asap && !parsing) {
4317  unscheduleRepaint();
4318  }
4319 
4320  if (!d->repaintTimerId) {
4321  d->repaintTimerId = startTimer(time);
4322  }
4323 
4324 // qCDebug(KHTML_LOG) << "starting timer " << time;
4325 }
4326 
4327 void KHTMLView::complete(bool pendingAction)
4328 {
4329 // qCDebug(KHTML_LOG) << "KHTMLView::complete()";
4330 
4331  d->complete = true;
4332 
4333  // is there a relayout pending?
4334  if (d->layoutTimerId) {
4335 // qCDebug(KHTML_LOG) << "requesting relayout now";
4336  // do it now
4337  killTimer(d->layoutTimerId);
4338  d->layoutTimerId = startTimer(0);
4339  d->emitCompletedAfterRepaint = pendingAction ?
4340  KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
4341  }
4342 
4343  // is there a repaint pending?
4344  if (d->repaintTimerId) {
4345 // qCDebug(KHTML_LOG) << "requesting repaint now";
4346  // do it now
4347  killTimer(d->repaintTimerId);
4348  d->repaintTimerId = startTimer(0);
4349  d->emitCompletedAfterRepaint = pendingAction ?
4350  KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
4351  }
4352 
4353  if (!d->emitCompletedAfterRepaint) {
4354  if (!pendingAction) {
4355  emit m_part->completed();
4356  } else {
4357  emit m_part->completed(true);
4358  }
4359  }
4360 
4361 }
4362 
4363 void KHTMLView::updateScrollBars()
4364 {
4365  const QWidget *view = widget();
4366  if (!view) {
4367  return;
4368  }
4369 
4370  QSize p = viewport()->size();
4371  QSize m = maximumViewportSize();
4372 
4373  if (m.expandedTo(view->size()) == m) {
4374  p = m; // no scroll bars needed
4375  }
4376 
4377  QSize v = view->size();
4378  horizontalScrollBar()->setRange(0, v.width() - p.width());
4380  verticalScrollBar()->setRange(0, v.height() - p.height());
4382  if (!d->smoothScrolling) {
4383  d->updateContentsXY();
4384  }
4385 }
4386 
4387 void KHTMLView::slotMouseScrollTimer()
4388 {
4389  horizontalScrollBar()->setValue(horizontalScrollBar()->value() + d->m_mouseScroll_byX);
4390  verticalScrollBar()->setValue(verticalScrollBar()->value() + d->m_mouseScroll_byY);
4391 }
4392 
4393 static DOM::Position positionOfLineBoundary(const DOM::Position &pos, bool toEnd)
4394 {
4395  Selection sel = pos;
4396  sel.expandUsingGranularity(Selection::LINE);
4397  return toEnd ? sel.end() : sel.start();
4398 }
4399 
4400 inline static DOM::Position positionOfLineBegin(const DOM::Position &pos)
4401 {
4402  return positionOfLineBoundary(pos, false);
4403 }
4404 
4405 inline static DOM::Position positionOfLineEnd(const DOM::Position &pos)
4406 {
4407  return positionOfLineBoundary(pos, true);
4408 }
4409 
4410 bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
4411 {
4412  EditorContext *ec = &m_part->d->editor_context;
4413  Selection &caret = ec->m_selection;
4414  Position old_pos = caret.caretPos();
4415  Position pos = old_pos;
4416  bool recalcXPos = true;
4417  bool handled = true;
4418 
4419  bool ctrl = _ke->modifiers() & Qt::ControlModifier;
4420  bool shift = _ke->modifiers() & Qt::ShiftModifier;
4421 
4422  switch (_ke->key()) {
4423 
4424  // -- Navigational keys
4425  case Qt::Key_Down:
4426  pos = old_pos.nextLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
4427  recalcXPos = false;
4428  break;
4429 
4430  case Qt::Key_Up:
4431  pos = old_pos.previousLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
4432  recalcXPos = false;
4433  break;
4434 
4435  case Qt::Key_Left:
4436  pos = ctrl ? old_pos.previousWordPosition() : old_pos.previousCharacterPosition();
4437  break;
4438 
4439  case Qt::Key_Right:
4440  pos = ctrl ? old_pos.nextWordPosition() : old_pos.nextCharacterPosition();
4441  break;
4442 
4443  case Qt::Key_PageDown:
4444 // moveCaretNextPage(); ###
4445  break;
4446 
4447  case Qt::Key_PageUp:
4448 // moveCaretPrevPage(); ###
4449  break;
4450 
4451  case Qt::Key_Home:
4452  if (ctrl)
4453  /*moveCaretToDocumentBoundary(false)*/; // ###
4454  else {
4455  pos = positionOfLineBegin(old_pos);
4456  }
4457  break;
4458 
4459  case Qt::Key_End:
4460  if (ctrl)
4461  /*moveCaretToDocumentBoundary(true)*/; // ###
4462  else {
4463  pos = positionOfLineEnd(old_pos);
4464  }
4465  break;
4466 
4467  default:
4468  handled = false;
4469 
4470  }/*end switch*/
4471 
4472  if (pos != old_pos) {
4473  m_part->clearCaretRectIfNeeded();
4474 
4475  caret.moveTo(shift ? caret.nonCaretPos() : pos, pos);
4476  int old_x = caret.xPosForVerticalArrowNavigation(Selection::CARETPOS);
4477 
4478  m_part->selectionLayoutChanged();
4479 
4480  // restore old x-position to prevent recalculation
4481  if (!recalcXPos) {
4482  m_part->d->editor_context.m_xPosForVerticalArrowNavigation = old_x;
4483  }
4484 
4485  m_part->emitCaretPositionChanged(pos);
4486  // ### check when to emit it
4487  m_part->notifySelectionChanged();
4488 
4489  }
4490 
4491  if (handled) {
4492  _ke->accept();
4493  }
4494  return handled;
4495 }
4496 
4497 #undef DEBUG_CARETMODE
bool isRightToLeft()
void setBrush(QPalette::ColorRole role, const QBrush &brush)
SmoothScrollingMode smoothScrollingMode() const
Retrieve the current smooth scrolling mode.
Definition: khtmlview.cpp:1139
void resize(int w, int h)
void updateContents(const QRect &r)
Requests an update of the content area.
Definition: khtmlview.cpp:805
ScrollBarAsNeeded
SmoothScrollingMode
Smooth Scrolling Mode enumeration.
Definition: khtmlview.h:330
bool close()
bool sync() override
NoModifier
bool underMouse() const const
Qt::KeyboardModifiers modifiers() const const
virtual QSize sizeHint() const const override
void setViewport(const QRect &rectangle)
void setWidget(QWidget *widget)
QSize size() const const
StrongFocus
QEvent::Type type() const const
int doubleClickInterval()
const QPalette & palette() const const
QString toUpper() const const
QLinkedList::iterator erase(QLinkedList::iterator pos)
virtual void reject()
int width() const const
QCursor urlCursor() const
Returns the cursor which is used when the cursor is on a link.
T * data() const const
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:278
void ensureVisible(int x, int y, int xmargin, int ymargin)
int width() const const
QString writableLocation(QStandardPaths::StandardLocation type)
bool end()
bool contains(const Key &key) const const
void setCursor(const QCursor &)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setSmoothScrollingMode(SmoothScrollingMode m)
Set the smooth scrolling mode.
Definition: khtmlview.cpp:1118
QAbstractEventDispatcher * instance(QThread *thread)
void translate(int dx, int dy)
QString toString(Qt::DateFormat format) const const
void append(const T &value)
void fill(const QColor &color)
virtual void keyReleaseEvent(QKeyEvent *event)
QVector::iterator begin()
int right() const const
QRect window() const const
void setRange(int min, int max)
const Key & key() const const
Qt::WindowModality windowModality() const const
void setFocusPolicy(Qt::FocusPolicy policy)
QWidget * widget() const const
Qt::MouseButtons buttons() const const
DefaultLocaleShortDate
int count() const const
QString & prepend(QChar ch)
bool hasNext() const const
QLinkedList::iterator begin()
QStyle * style() const const
This file is part of the HTML rendering engine for KDE.
void updateStyleSelector(bool shallow=false)
Called when one or more stylesheets in the document may have been added, removed or changed...
int contentsY() const
Returns the y coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:714
void scale(qreal sx, qreal sy)
int x() const const
int y() const const
QPoint contentsToViewport(const QPoint &p) const
Returns a point translated to viewport coordinates.
Definition: khtmlview.cpp:767
const QObjectList & children() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QString simplified() const const
bool frameExists(const QString &frameName)
Returns whether a frame with the specified name is exists or not.
int y() const const
This class is khtml&#39;s main class.
Definition: khtml_part.h:208
void translate(int dx, int dy)
bool isVisible() const const
bool intersects(const QRect &rectangle) const const
void save()
NoButton
QPoint pos() const const
const QPoint & pos() const const
void setAttribute(Qt::WidgetAttribute attribute, bool on)
virtual void wheelEvent(QWheelEvent *e) override
QWidget * viewport() const const
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
QList::iterator erase(QList::iterator pos)
int height() const const
QRect boundingRect() const const
int x() const const
int y() const const
void setPageStep(int)
bool hasFocus() const const
void setClipRegion(const QRegion &region, Qt::ClipOperation operation)
int x() const const
int y() const const
MouseFocusReason
Qt::MouseButtons buttons() const const
bool isAutoRepeat() const const
void setFrameStyle(int style)
virtual void dragEnterEvent(QDragEnterEvent *event) override
void setLineWidth(int)
void setContentsPos(int x, int y)
Place the contents area point x/y at the top left of the viewport.
Definition: khtmlview.cpp:751
void adjustSize()
void showText(const QPoint &pos, const QString &text, QWidget *w)
virtual void focusOutEvent(QFocusEvent *event)
void setParent(QWidget *parent)
QLinkedList::iterator end()
void update()
AlignLeft
int x() const const
int y() const const
bool isNull() const const
bool viewTransformEnabled() const const
int width() const const
QList< T > findChildren(const QString &name, Qt::FindChildOptions options) const const
void resetTransform()
KHTMLView * view() const
Returns a pointer to the HTML document&#39;s view.
KHTMLPart * part() const
Returns a pointer to the KHTMLPart that is rendering the page.
Definition: khtmlview.h:139
bool allowWidgetPaintEvents
This file is part of the HTML widget for KDE.
const QRect & rect() const const
void setWindow(const QRect &rectangle)
Qt::FocusReason reason() const const
int visibleWidth() const
Returns the width of the viewport.
Definition: khtmlview.cpp:719
int visibleHeight() const
Returns the height of the viewport.
Definition: khtmlview.cpp:735
void setFont(const QFont &font)
void layout()
ensure the display is up to date
Definition: khtmlview.cpp:981
bool testAttribute(Qt::WidgetAttribute attribute) const const
void setEnabled(bool)
virtual void showEvent(QShowEvent *event)
int count(const T &value) const const
void append(const T &value)
QPoint globalPos() const const
bool isSpace() const const
bool isAccepted() const const
void ignore()
bool isVisible()
void installEventFilter(QObject *filterObj)
void setCreator(const QString &creator)
int x() const const
QRectF boundingRect(const QRectF &rectangle, int flags, const QString &text)
virtual void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
Sets vertical scrollbar mode.
Definition: khtmlview.cpp:3468
virtual bool viewportEvent(QEvent *event)
int top() const const
QString convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)
QRegion clipRegion() const const
void setPen(const QColor &color)
void setWorldTransform(const QTransform &matrix, bool combine)
const QPoint & globalPos() const const
void setFocus()
void drawEllipse(const QRectF &rectangle)
virtual bool focusNextPrevChild(bool next)
virtual void hideEvent(QHideEvent *event)
int contentsHeight() const
Returns the contents area&#39;s height.
Definition: khtmlview.cpp:693
int left() const const
WhiteSpaceNormal
Qt::MouseButton button() const const
CaseInsensitive
void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy)
virtual bool event(QEvent *e) override
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
bool isEmpty() const const
virtual void focusInEvent(QFocusEvent *event)
void setFocusProxy(QWidget *w)
void setWidth(int width)
bool isEmpty() const const
int removeAll(const T &value)
QString trimmed() const const
bool sendEvent(QObject *receiver, QEvent *event)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString text() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QPaintDevice * device() const const
ArrowCursor
void drawText(const QPointF &position, const QString &text)
void setDocName(const QString &name)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
QRect translated(int dx, int dy) const const
Qt::Orientation orientation() const const
T & front()
KCOREADDONS_EXPORT QString csqueeze(const QString &str, int maxlen=40)
void sendPostedEvents(QObject *receiver, int event_type)
QMap::iterator end()
PE_IndicatorArrowUp
virtual bool eventFilter(QObject *o, QEvent *e) override
QScrollBar * verticalScrollBar() const const
QRect intersected(const QRect &rectangle) const const
int indexOf(QStringView str, int from) const const
const QTransform & worldTransform() const const
QMap::iterator begin()
virtual bool event(QEvent *event) override
bool isWindow() const const
QPixmap loadIcon(const QString &name, KIconLoader::Group group, int size=0, int state=KIconLoader::DefaultState, const QStringList &overlays=QStringList(), QString *path_store=nullptr, bool canReturnNull=false) const
QRect rect() const const
void setMarginWidth(int x)
Sets a margin in x direction.
Definition: khtmlview.cpp:969
void setAcceptDrops(bool on)
int logicalDpiY() const const
Qt::KeyboardModifiers modifiers() const const
void scrollBy(int x, int y)
Scrolls the content area by a given amount.
Definition: khtmlview.cpp:758
bool isNull() const const
QList::iterator end()
QString toLower() const const
int key() const const
void accept()
int manhattanLength() const const
QHashIterator::Item next()
void setFullPage(bool fp)
int height() const const
void setValue(int)
bool isEmpty() const const
bool contains(const T &value) const const
void hideText()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
bool isValid() const const
QPoint viewportToContents(const QPoint &p) const
Returns a point translated to contents area coordinates.
Definition: khtmlview.cpp:780
virtual bool newPage() override
void move(int x, int y)
void repaint()
QRect viewport() const const
all geometry managing stuff is only in the block elements.
Definition: render_flow.h:44
void restore()
void setZoomLevel(int percent)
Apply a zoom level to the content area.
Definition: khtmlview.cpp:1100
WA_NoSystemBackground
QString i18n(const char *text, const TYPE &arg...)
bool isNull() const const
This library provides a full-featured HTML parser and widget.
int startTimer(int interval, Qt::TimerType timerType)
virtual void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
Sets horizontal scrollbar mode.
Definition: khtmlview.cpp:3478
int width() const const
void setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
QPoint pos()
int globalX() const const
int globalY() const const
QPoint mapTo(const QWidget *parent, const QPoint &pos) const const
QStyle * style()
QChar toUpper() const const
void setX(int x)
void setY(int y)
QSize expandedTo(const QSize &otherSize) const const
QPalette palette()
QFontMetrics fontMetrics() const const
void setHeight(int height)
void finishedLayout()
This signal is used for internal layouting.
QWidget * parentWidget() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QDate currentDate()
QPoint mapFromGlobal(const QPoint &pos) const const
QWidget(QWidget *parent, Qt::WindowFlags f)
void setWorldMatrixEnabled(bool enable)
int contentsX() const
Returns the x coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:709
typedef ConstIterator
int height() const const
void adjust(int dx1, int dy1, int dx2, int dy2)
void clear()
bool worldMatrixEnabled() const const
int bottom() const const
Base Class for all rendering tree objects.
QPoint topLeft() const const
int length() const const
void translate(const QPointF &offset)
void setMouseTracking(bool enable)
int timerId() const const
virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const =0
bool isEmpty() const const
QBitmap createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode) const const
QScrollBar * horizontalScrollBar() const const
void print(bool quick=false)
Prints the HTML document.
Definition: khtmlview.cpp:3096
QSize maximumViewportSize() const const
void prepend(const T &value)
void setAutoFillBackground(bool enabled)
void show()
Vertical
KGuiItem reset()
void scroll(int dx, int dy)
int contentsWidth() const
Returns the contents area&#39;s width.
Definition: khtmlview.cpp:688
virtual void closeEvent(QCloseEvent *event)
QPoint pos() const const
QVector< QRect > rects() const const
void setViewTransformEnabled(bool enable)
virtual void dropEvent(QDropEvent *event) override
int height() const const
const T & value() const const
void nodeActivated(const DOM::Node &)
This signal is emitted when an element retrieves the keyboard focus.
bool isWidgetType() const const
ApplicationModal
transparent
void repaintContents(const QRect &r)
Requests an immediate repaint of the content area.
Definition: khtmlview.cpp:822
void postEvent(QObject *receiver, QEvent *event, int priority)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
NodeImpl * handle() const
Definition: dom_node.h:936
T qobject_cast(QObject *object)
QObject * parent() const const
int size() const const
bool begin(QPaintDevice *device)
int delta() const const
QRect rect() const const
virtual bool event(QEvent *event) override
void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy)
QVector::iterator end()
QFuture< void > map(Sequence &sequence, MapFunctor function)
T readEntry(const QString &key, const T &aDefault) const
bool removeOne(const T &value)
QRect united(const QRect &rectangle) const const
X11BypassWindowManagerHint
virtual bool event(QEvent *e) override
void killTimer(int id)
void getRect(int *x, int *y, int *width, int *height) const const
bool isNumber() const const
QList::iterator begin()
NodeImpl * nextFocusNode(NodeImpl *fromNode)
Searches through the document, starting from fromNode, for the next selectable element that comes aft...
const KHTMLSettings * settings() const
NodeImpl * previousFocusNode(NodeImpl *fromNode)
Searches through the document, starting from fromNode, for the previous selectable element (that come...
Key_Control
KHTMLView(KHTMLPart *part, QWidget *parent)
Constructs a KHTMLView.
Definition: khtmlview.cpp:563
int lineSpacing() const const
int zoomLevel() const
Retrieve the current zoom level.
Definition: khtmlview.cpp:1113
virtual void resizeContents(int w, int h)
Resize the contents area.
Definition: khtmlview.cpp:698
QRegion mask() const const
void displayAccessKeys()
Display all accesskeys in small tooltips.
Definition: khtmlview.cpp:2528
void append(const T &value)
typedef QObjectList
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
int startDragDistance()
Qt::CursorShape shape() const const
void setContentsMargins(int left, int top, int right, int bottom)
virtual bool unregisterTimers(QObject *object)=0
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:47:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.