(*** This bug was imported into bugs.kde.org ***) Package: khtml Version: KDE 3.0.0 Severity: wishlist Installed from: Mandrake RPMs Compiler: gcc 2.95 OS: Linux OS/Compiler notes: Not Specified Konqueror has a beautiful feature in that it provides a feature that will scale up/down the fon sizes in a document. This is IMMENSELY useful for sites with tiny fonts or those of us with high resolution displays. However there also needs to be a facility to scale the bitmaps contained in the document for a similar reason. Often times bitmaps contain text or other info that is obscurred when viewed at higher resolution. The code already exists in khtml to scale all the images (as is done explicitly when image sizes are specified in the HTML). There should also be a scale/zoom factor to which all other measurements are multiplied. For example click on a button to increase the zoom level 10% or 20% so a graphic that is specified to be 100x200 will be 110x220 or 120x240. Not only should this be easy to implement but to the best of my knowledge is a feature not available with any other browser. This could be keyed to a DPI setting etc. too. Better do it before someone patents the idea... (Submitted via bugs.kde.org)
*** Bug 83359 has been marked as a duplicate of this bug. ***
*** Bug 87728 has been marked as a duplicate of this bug. ***
Opera has this feature.
There exists an extension for Firefox/Mozilla which provides per-image zoom functionality as described above.
Yes, it would be great to have this feature in kde-4.0, specially for people using a great resolution. All objects (text, images, flash objects, etc.) should zoom accordingly, Opera does it really wel. As the original poster already sayed it shouldn't be so difficult to implement.
*** Bug 100284 has been marked as a duplicate of this bug. ***
*** Bug 112324 has been marked as a duplicate of this bug. ***
*** Bug 115115 has been marked as a duplicate of this bug. ***
*** This bug has been confirmed by popular vote. ***
*** Bug 87862 has been marked as a duplicate of this bug. ***
SVN commit 630479 by ggarand: A simple "page scaling" zoom à la Opera. For now, it replaces the font scaling action, as the method names used for it in KHTML part are better suited to a real zoom (e.g. setZoomFactor). Need to reintroduce pure font-scaling under another name.. Also introduce an alternate, non-blitting painting mode for being able to do fixed positioning again. QScrollArea's quite a bit on the terse side, so there was no such thing ;( Should fix widget jittering issues as a bonus. BUG: 42029, 68721 M +2 -2 css/cssstyleselector.cpp M +9 -4 khtml_part.cpp M +111 -18 khtmlview.cpp M +20 -1 khtmlview.h M +15 -8 rendering/render_canvas.cpp M +1 -1 rendering/render_replaced.cpp M +2 -0 xml/dom_nodeimpl.cpp --- trunk/KDE/kdelibs/khtml/css/cssstyleselector.cpp #630478:630479 @@ -749,7 +749,7 @@ // FIXME: We only need to invalidate the fixed regions when scrolling. It's total overkill to // prevent the entire view from blitting on a scroll. if (style->hasFixedBackgroundImage() && view) - view->useSlowRepaints(); + view->setHasStaticBackground(); } unsigned int CSSStyleSelector::addInlineDeclarations(DOM::ElementImpl* e, @@ -2414,7 +2414,7 @@ p = ABSOLUTE; break; case CSS_VAL_FIXED: { - view->useSlowRepaints(); + view->setHasStaticBackground(); p = FIXED; break; } --- trunk/KDE/kdelibs/khtml/khtml_part.cpp #630478:630479 @@ -5754,11 +5754,16 @@ if (d->m_zoomFactor == percent) return; d->m_zoomFactor = percent; - if(d->m_doc) { + if(d->m_view) { QApplication::setOverrideCursor( Qt::WaitCursor ); - if (d->m_doc->styleSelector()) - d->m_doc->styleSelector()->computeFontSizes(d->m_doc->paintDeviceMetrics(), d->m_zoomFactor); - d->m_doc->recalcStyle( NodeImpl::Force ); + +// ### make the increasing/decreasing of font size a separate setting +// +// if (d->m_doc->styleSelector()) +// d->m_doc->styleSelector()->computeFontSizes(d->m_doc->paintDeviceMetrics(), d->m_zoomFactor); +// d->m_doc->recalcStyle( NodeImpl::Force ); + + d->m_view->setZoomLevel( d->m_zoomFactor ); QApplication::restoreOverrideCursor(); } --- trunk/KDE/kdelibs/khtml/khtmlview.cpp #630478:630479 @@ -186,10 +186,11 @@ oldUnderMouse->deref(); oldUnderMouse = 0; linkPressed = false; - useSlowRepaints = false; + staticWidget = false; tabMovePending = false; lastTabbingDirection = true; pseudoFocusNode = PFNone; + zoomLevel = 100; #ifndef KHTML_NO_SCROLLBARS //We don't turn off the toolbars here //since if the user turns them @@ -287,6 +288,8 @@ scrollSuspended = false; } + bool haveZoom() const { return zoomLevel != 100; } + #ifndef KHTML_NO_CARET /** this function returns an instance of the caret view context. If none * exists, it will be instantiated. @@ -324,9 +327,10 @@ Qt::ScrollBarPolicy hpolicy; bool prevScrollbarVisible:1; bool linkPressed:1; - bool useSlowRepaints:1; + bool staticWidget:1; bool ignoreWheelEvents:1; + int zoomLevel; int borderX, borderY; KSimpleConfig *formCompletions; @@ -510,9 +514,13 @@ QSize s = viewport()->size(); resizeContents(s.width(), s.height()); - // ### we'll enable redirection of khtmlview here - // when event and painting issues have been thoroughly worked out - // m_kwp->setIsRedirected(true); + // ### we'll enable redirection of khtmlview + // when event issues have been thoroughly worked out + + bool redirect = false; // m_part->parentPart() && !isFrame() ... + + m_kwp->setIsRedirected( redirect ); + d->staticWidget = redirect; } void KHTMLView::clear() @@ -640,6 +648,7 @@ void KHTMLView::updateContents(int x, int y, int w, int h) { + applyTransforms(x, y, w, h); widget()->update(x, y, w, h); } @@ -650,6 +659,7 @@ void KHTMLView::repaintContents(int x, int y, int w, int h) { + applyTransforms(x, y, w, h); widget()->repaint(x, y, w, h); } @@ -658,6 +668,42 @@ repaintContents( r.x(), r.y(), r.width(), r.height() ); } +void KHTMLView::applyTransforms( int& x, int& y, int& w, int& h) const +{ + if (d->staticWidget) { + x -= contentsX(); + y -= contentsY(); + } + if (d->haveZoom()) { + const int z = d->zoomLevel; + x = x*z/100; + y = y*z/100; + w = w*z/100; + h = h*z/100; + } +} + +void KHTMLView::revertTransforms( int& x, int& y, int& w, int& h) const +{ + if (d->staticWidget) { + x += contentsX(); + y += contentsY(); + } + if (d->haveZoom()) { + const int z = d->zoomLevel; + x = x*100/z; + y = y*100/z; + w = w*100/z; + h = h*100/z; + } +} + +void KHTMLView::revertTransforms( int& x, int& y ) const +{ + int dummy = 0; + revertTransforms(x, y, dummy, dummy); +} + void KHTMLView::resizeEvent (QResizeEvent* e) { int dw = e->oldSize().width() - e->size().width(); @@ -692,16 +738,30 @@ QRect r = e->rect(); QRect v(contentsX(), contentsY(), visibleWidth(), visibleHeight()); + if (d->staticWidget) { + QPoint off(contentsX(),contentsY()); + p.translate(-off); + r.translate(off); + } r = r.intersect(v); if (!r.isValid() || r.isEmpty()) return; - p.setClipRect(v); + + if (d->haveZoom()) { + p.scale( d->zoomLevel/100., d->zoomLevel/100.); + r.setX(r.x()*100/d->zoomLevel); + r.setY(r.y()*100/d->zoomLevel); + r.setWidth(r.width()*100/d->zoomLevel); + r.setHeight(r.height()*100/d->zoomLevel); + } + p.setClipRect(r); + int ex = r.x(); int ey = r.y(); int ew = r.width(); int eh = r.height(); - + if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) { p.fillRect(ex, ey, ew, eh, palette().brush(QPalette::Active, QPalette::Base)); return; @@ -882,6 +942,23 @@ QScrollArea::closeEvent( ev ); } +void KHTMLView::setZoomLevel(int percent) +{ + percent = percent < 20 ? 20 : (percent > 800 ? 800 : percent); + int oldpercent = d->zoomLevel; + d->zoomLevel = percent; + if (percent != oldpercent) { + if (d->layoutSchedulingEnabled) + layout(); + widget()->update(); + } +} + +int KHTMLView::zoomLevel() const +{ + return d->zoomLevel; +} + // // Event Handling // @@ -898,6 +975,7 @@ int xm = _mouse->x(); int ym = _mouse->y(); + revertTransforms(xm, ym); // kDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()-contentsX()<<"/"<<_mouse->y()-contentsY()<<"), contents=(" << xm << "/" << ym << ")\n"; @@ -1018,6 +1096,7 @@ int xm = _mouse->x(); int ym = _mouse->y(); + revertTransforms(xm, ym); // kDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl; @@ -1087,6 +1166,7 @@ int xm = _mouse->x(); int ym = _mouse->y(); + revertTransforms(xm, ym); DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseMove ); // Do not modify :hover/:active state while mouse is pressed. @@ -1240,6 +1320,7 @@ int xm = _mouse->x(); int ym = _mouse->y(); + revertTransforms(xm, ym); DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseRelease ); @@ -3001,10 +3082,11 @@ } -void KHTMLView::useSlowRepaints() +void KHTMLView::setHasStaticBackground() { - d->useSlowRepaints = true; -// setStaticBackground(true); ### ?? FIXME + if (!d->staticWidget) + widget()->move(0,0); + d->staticWidget = true; } @@ -3136,6 +3218,7 @@ int exceptioncode = 0; int pageX = _mouse->x(); int pageY = _mouse->y(); + revertTransforms(pageX, pageY); int clientX = pageX - contentsX(); int clientY = pageY - contentsY(); int screenX = _mouse->globalX(); @@ -3164,7 +3247,7 @@ // mouseout/mouseover if (setUnder && d->oldUnderMouse != targetNode) { - if (d->oldUnderMouse && d->oldUnderMouse->getDocument() != targetNode->getDocument()) { + if (d->oldUnderMouse && d->oldUnderMouse->getDocument() != m_part->xmlDocImpl()) { d->oldUnderMouse->deref(); d->oldUnderMouse = 0; } @@ -3436,16 +3519,29 @@ horizontalScrollBar()->maximum()-horizontalScrollBar()->value() : horizontalScrollBar()->value(); d->contentsY = verticalScrollBar()->value(); - if (d->useSlowRepaints) { - widget()->blockSignals( true ); - widget()->move( widget()->pos().x() + dx, widget()->pos().y() +dy ); - widget()->blockSignals( false ); + if ( d->staticWidget ) { widget()->repaint(); return; } QScrollArea::scrollContentsBy(dx, dy); } +void KHTMLView::addChild(QWidget * child, int x, int y) +{ + if (!child) + return; + + if (child->parent() != widget()) + child->setParent( widget() ); + + // ### handle pseudo-zooming of non-redirected widgets (e.g. just resize'em) + + if (!d->staticWidget) + child->move(x, y); + else + child->move(x-contentsX(), y-contentsY()); +} + void KHTMLView::timerEvent ( QTimerEvent *e ) { // kDebug() << "timer event " << e->timerId() << endl; @@ -3518,9 +3614,6 @@ } } -// setStaticBackground(d->useSlowRepaints); ?? ### FIXME - -// kDebug() << "scheduled repaint "<< d->repaintTimerId << endl; if (d->repaintTimerId) killTimer(d->repaintTimerId); d->repaintTimerId = 0; --- trunk/KDE/kdelibs/khtml/khtmlview.h #630478:630479 @@ -98,6 +98,7 @@ friend class DOM::HTMLFormElementImpl; friend class DOM::HTMLAnchorElementImpl; friend class DOM::HTMLInputElementImpl; + friend class DOM::NodeImpl; friend class DOM::DocumentImpl; friend class KHTMLPart; friend class khtml::RenderCanvas; @@ -257,6 +258,8 @@ */ void updateContents( const QRect& r ); void updateContents(int x, int y, int w, int h); + + void addChild(QWidget *child, int dx, int dy); /** * Requests an immediate repaint of the content area @@ -264,6 +267,18 @@ */ void repaintContents( const QRect& r ); void repaintContents(int x, int y, int w, int h); + + /** + * Apply a zoom level to the content area + * @param percent a zoom level expressed as a percentage + */ + void setZoomLevel( int percent ); + + /** + * Retrieve the current zoom level + * + */ + int zoomLevel() const; public Q_SLOTS: /** @@ -393,7 +408,10 @@ QMap< DOM::ElementImpl*, QChar > buildFallbackAccessKeys() const; void displayAccessKeys( KHTMLView* caller, KHTMLView* origview, QVector< QChar >& taken, bool use_fallbacks ); - void useSlowRepaints(); + void setHasStaticBackground(); + void applyTransforms( int& x, int& y, int& w, int& h) const; + void revertTransforms( int& x, int& y, int& w, int& h) const; + void revertTransforms( int& x, int& y ) const; void setIgnoreWheelEvents(bool e); @@ -699,6 +717,7 @@ void setWidgetVisible(::khtml::RenderWidget*, bool visible); + int _width; int _height; --- trunk/KDE/kdelibs/khtml/rendering/render_canvas.cpp #630478:630479 @@ -220,35 +220,42 @@ // update our cached document size int hDocH = m_cachedDocHeight = docHeight(); int hDocW = m_cachedDocWidth = docWidth(); + + int zLevel = m_view? m_view->zoomLevel() : 100; + hDocW = hDocW*zLevel/100; + hDocH = hDocH*zLevel/100; if (!m_pagedMode && m_view) { bool vss = !m_view->verticalScrollBar()->isHidden(); bool hss = !m_view->horizontalScrollBar()->isHidden(); QSize s = m_view->maximumViewportSize(); - if ( m_cachedDocWidth > s.width() ) + + int zoomedDocWidth = m_cachedDocWidth*zLevel/100; + int zoomedDocHeight = m_cachedDocHeight*zLevel/100; + if ( zoomedDocWidth > s.width() ) s.setWidth( s.width()-m_view->verticalScrollBar()->sizeHint().width() ); - if ( m_cachedDocHeight > s.height() ) + if ( zoomedDocHeight > s.height() ) s.setHeight( s.height()-m_view->horizontalScrollBar()->sizeHint().height() ); // if we are about to show a scrollbar, and the document is sized to the viewport w or h, // then reserve the scrollbar space so that it doesn't trigger the _other_ scrollbar if (!vss && m_width - m_view->verticalScrollBar()->sizeHint().width() == s.width() && - m_cachedDocWidth <= m_width) - hDocW = qMin( m_cachedDocWidth, s.width() ); + zoomedDocWidth <= m_width) + hDocW = qMin( zoomedDocWidth, s.width() ); if (!hss && m_height - m_view->horizontalScrollBar()->sizeHint().height() == s.height() && - m_cachedDocHeight <= m_height) - hDocH = qMin( m_cachedDocHeight, s.height() ); + zoomedDocHeight <= m_height) + hDocH = qMin( zoomedDocHeight, s.height() ); // likewise, if a scrollbar is shown, and we have a cunning plan to turn it off, // think again if we are falling downright in the hysteresis zone - if (vss && s.width() > m_cachedDocWidth && m_cachedDocWidth > m_view->visibleWidth()) + if (vss && s.width() > zoomedDocWidth && zoomedDocWidth > m_view->visibleWidth()) hDocW = s.width()+1; - if (hss && s.height() > m_cachedDocHeight && m_cachedDocHeight > m_view->visibleHeight()) + if (hss && s.height() > zoomedDocHeight && zoomedDocHeight > m_view->visibleHeight()) hDocH = s.height()+1; m_view->resizeContents(hDocW, hDocH); --- trunk/KDE/kdelibs/khtml/rendering/render_replaced.cpp #630478:630479 @@ -524,7 +524,7 @@ } m_view->setWidgetVisible(this, true); if (!khtmlw) - m_widget->move( xPos, yPos ); + m_view->addChild( m_widget, xPos, yPos ); else m_widget->move( xPos, -500000 +yPos); m_widget->show(); --- trunk/KDE/kdelibs/khtml/xml/dom_nodeimpl.cpp #630478:630479 @@ -503,6 +503,8 @@ int exceptioncode = 0; int pageX = _mouse->x(); int pageY = _mouse->y(); + if ( getDocument()->view() ) + getDocument()->view()->revertTransforms( pageX, pageY ); int clientX = pageX; int clientY = pageY; if ( getDocument()->view() )