📄 render_replaced.cpp
字号:
/** * This file is part of the HTML widget for KDE. * * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) * Copyright (C) 2000-2003 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003 Apple Computer, Inc. * Copyright (C) 2004 Germain Garand (germain@ebooksfrance.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "render_replaced.h"#include "render_canvas.h"#include "render_line.h"#include "render_arena.h"#include <assert.h>#include <qwidget.h>#include <qpainter.h>#include <qevent.h>#include <qapplication.h>#include <qlineedit.h>#include <kglobalsettings.h>#include <qobjectlist.h>#include <qvaluevector.h>#include "khtml_ext.h"#include "khtmlview.h"#include "xml/dom2_eventsimpl.h"#include "khtml_part.h"#include "xml/dom_docimpl.h"#include <kdebug.h>bool khtml::allowWidgetPaintEvents = false;using namespace khtml;using namespace DOM;RenderReplaced::RenderReplaced(DOM::NodeImpl* node) : RenderBox(node){ // init RenderObject attributes setReplaced(true); m_intrinsicWidth = 200; m_intrinsicHeight = 150;}void RenderReplaced::calcMinMaxWidth(){ KHTMLAssert( !minMaxKnown());#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << "RenderReplaced::calcMinMaxWidth() known=" << minMaxKnown() << endl;#endif m_width = calcReplacedWidth(); m_width = calcBoxWidth( m_width ); if ( style()->width().isPercent() || style()->height().isPercent() || style()->maxWidth().isPercent() || style()->maxHeight().isPercent() || style()->minWidth().isPercent() || style()->minHeight().isPercent() ) { m_minWidth = 0; m_maxWidth = m_width; } else m_minWidth = m_maxWidth = m_width; setMinMaxKnown();}void RenderReplaced::position(InlineBox* box, int /*from*/, int /*len*/, bool /*reverse*/){ setPos( box->xPos(), box->yPos() );}// -----------------------------------------------------------------------------RenderWidget::RenderWidget(DOM::NodeImpl* node) : RenderReplaced(node){ m_widget = 0; // a widget doesn't support being anonymous assert(!isAnonymous()); m_view = node->getDocument()->view(); m_resizePending = false; m_discardResizes = false; // this is no real reference counting, its just there // to make sure that we're not deleted while we're recursed // in an eventFilter of the widget ref();}void RenderWidget::detach(){ remove(); deleteInlineBoxes(); if ( m_widget ) { if ( m_view ) { m_view->setWidgetVisible(this, false); m_view->removeChild( m_widget ); } m_widget->removeEventFilter( this ); m_widget->setMouseTracking( false ); } deref();}RenderWidget::~RenderWidget(){ KHTMLAssert( refCount() <= 0 ); if(m_widget) { m_widget->hide(); m_widget->deleteLater(); }}class QWidgetResizeEvent : public QEvent{public: enum { Type = QEvent::User + 0xbee }; QWidgetResizeEvent( int _w, int _h ) : QEvent( ( QEvent::Type ) Type ), w( _w ), h( _h ) {} int w; int h;};void RenderWidget::resizeWidget( int w, int h ){ // ugly hack to limit the maximum size of the widget ( as X11 has problems if // its bigger ) h = kMin( h, 3072 ); w = kMin( w, 2000 ); if (m_widget->width() != w || m_widget->height() != h) { m_resizePending = !strcmp(m_widget->name(), "__khtml"); ref(); element()->ref(); QApplication::postEvent( this, new QWidgetResizeEvent( w, h ) ); element()->deref(); deref(); }}void RenderWidget::cancelPendingResize(){ if (!m_widget) return; m_discardResizes = true; QApplication::sendPostedEvents(this, QWidgetResizeEvent::Type); m_discardResizes = false;}bool RenderWidget::event( QEvent *e ){ if ( m_widget && (e->type() == (QEvent::Type)QWidgetResizeEvent::Type) ) { m_resizePending = false; if (m_discardResizes) return true; QWidgetResizeEvent *re = static_cast<QWidgetResizeEvent *>(e); m_widget->resize( re->w, re->h ); repaint(); } // eat all events - except if this is a frame (in which case KHTMLView handles it all) if ( ::qt_cast<KHTMLView *>( m_widget ) ) return QObject::event( e ); return true;}void RenderWidget::flushWidgetResizes() //static{ QApplication::sendPostedEvents( 0, QWidgetResizeEvent::Type );}void RenderWidget::setQWidget(QWidget *widget){ if (widget != m_widget) { if (m_widget) { m_widget->removeEventFilter(this); disconnect( m_widget, SIGNAL( destroyed()), this, SLOT( slotWidgetDestructed())); delete m_widget; m_widget = 0; } m_widget = widget; if (m_widget) { connect( m_widget, SIGNAL( destroyed()), this, SLOT( slotWidgetDestructed())); m_widget->installEventFilter(this); if ( !strcmp(m_widget->name(), "__khtml") && !::qt_cast<QFrame*>(m_widget)) m_widget->setBackgroundMode( QWidget::NoBackground ); if (m_widget->focusPolicy() > QWidget::StrongFocus) m_widget->setFocusPolicy(QWidget::StrongFocus); // if we've already received a layout, apply the calculated space to the // widget immediately, but we have to have really been full constructed (with a non-null // style pointer). if (!needsLayout() && style()) { resizeWidget( m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom() ); } else setPos(xPos(), -500000); } m_view->setWidgetVisible(this, false); m_view->addChild( m_widget, 0, -500000); if ( m_widget ) m_widget->hide(); m_resizePending = false; }}void RenderWidget::layout( ){ KHTMLAssert( needsLayout() ); KHTMLAssert( minMaxKnown() ); if ( m_widget ) resizeWidget( m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom() ); setNeedsLayout(false);}void RenderWidget::updateFromElement(){ if (m_widget) { // Color: QColor color = style()->color(); QColor backgroundColor = style()->backgroundColor(); if ( color.isValid() || backgroundColor.isValid() ) { QPalette pal(QApplication::palette(m_widget)); int contrast_ = KGlobalSettings::contrast(); int highlightVal = 100 + (2*contrast_+4)*16/10; int lowlightVal = 100 + (2*contrast_+4)*10; if (backgroundColor.isValid()) { if (strcmp(widget()->name(), "__khtml")) widget()->setEraseColor(backgroundColor ); for ( int i = 0; i < QPalette::NColorGroups; ++i ) { pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Background, backgroundColor ); pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Light, backgroundColor.light(highlightVal) ); pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Dark, backgroundColor.dark(lowlightVal) ); pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Mid, backgroundColor.dark(120) ); pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Midlight, backgroundColor.light(110) ); pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Button, backgroundColor ); pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Base, backgroundColor ); } } if ( color.isValid() ) { struct ColorSet { QPalette::ColorGroup cg; QColorGroup::ColorRole cr; }; const struct ColorSet toSet [] = { { QPalette::Active, QColorGroup::Foreground }, { QPalette::Active, QColorGroup::ButtonText }, { QPalette::Active, QColorGroup::Text }, { QPalette::Inactive, QColorGroup::Foreground }, { QPalette::Inactive, QColorGroup::ButtonText }, { QPalette::Inactive, QColorGroup::Text }, { QPalette::Disabled,QColorGroup::ButtonText }, { QPalette::NColorGroups, QColorGroup::NColorRoles }, }; const ColorSet *set = toSet; while( set->cg != QPalette::NColorGroups ) { pal.setColor( set->cg, set->cr, color ); ++set; } QColor disfg = color; int h, s, v; disfg.hsv( &h, &s, &v ); if (v > 128) // dark bg, light fg - need a darker disabled fg disfg = disfg.dark(lowlightVal); else if (disfg != Qt::black) // light bg, dark fg - need a lighter disabled fg - but only if !black disfg = disfg.light(highlightVal); else // black fg - use darkgray disabled fg disfg = Qt::darkGray; pal.setColor(QPalette::Disabled,QColorGroup::Foreground,disfg); } m_widget->setPalette(pal); } else m_widget->unsetPalette(); // Border: QFrame* frame = ::qt_cast<QFrame*>(m_widget); if (frame) { if (shouldPaintBackgroundOrBorder()) { frame->setFrameShape(QFrame::NoFrame); } } } RenderReplaced::updateFromElement();}void RenderWidget::slotWidgetDestructed(){ if (m_view) m_view->setWidgetVisible(this, false); m_widget = 0;}void RenderWidget::setStyle(RenderStyle *_style){ RenderReplaced::setStyle(_style); if(m_widget) { m_widget->setFont(style()->font()); if (style()->visibility() != VISIBLE) { if (m_view) m_view->setWidgetVisible(this, false); m_widget->hide(); } } // Don't paint borders if the border-style is native // or borders are not supported on this widget if (!canHaveBorder() || (style()->borderLeftStyle() == BNATIVE && style()->borderRightStyle() == BNATIVE && style()->borderTopStyle() == BNATIVE && style()->borderBottomStyle() == BNATIVE)) { setShouldPaintBackgroundOrBorder(false); }}void RenderWidget::paint(PaintInfo& paintInfo, int _tx, int _ty){ _tx += m_x; _ty += m_y; if (shouldPaintBackgroundOrBorder() && (paintInfo.phase == PaintActionChildBackground || paintInfo.phase == PaintActionChildBackgrounds)) paintBoxDecorations(paintInfo, _tx, _ty); if (!m_widget || !m_view || paintInfo.phase != PaintActionForeground) return; // not visible or not even once layouted if (style()->visibility() != VISIBLE || m_y <= -500000 || m_resizePending ) return; if ( (_ty > paintInfo.r.bottom()) || (_ty + m_height <= paintInfo.r.top()) || (_tx + m_width <= paintInfo.r.left()) || (_tx > paintInfo.r.right()) ) return; int xPos = _tx+borderLeft()+paddingLeft(); int yPos = _ty+borderTop()+paddingTop(); bool khtmlw = !strcmp(m_widget->name(), "__khtml"); int childw = m_widget->width(); int childh = m_widget->height(); if ( (childw == 2000 || childh == 3072) && m_widget->inherits( "KHTMLView" ) ) { KHTMLView *vw = static_cast<KHTMLView *>(m_widget); int cy = m_view->contentsY(); int ch = m_view->visibleHeight(); int childx = m_view->childX( m_widget ); int childy = m_view->childY( m_widget ); int xNew = xPos; int yNew = childy; // qDebug("cy=%d, ch=%d, childy=%d, childh=%d", cy, ch, childy, childh ); if ( childh == 3072 ) { if ( cy + ch > childy + childh ) { yNew = cy + ( ch - childh )/2; } else if ( cy < childy ) { yNew = cy + ( ch - childh )/2; }// qDebug("calculated yNew=%d", yNew); } yNew = kMin( yNew, yPos + m_height - childh ); yNew = kMax( yNew, yPos ); if ( yNew != childy || xNew != childx ) { if ( vw->contentsHeight() < yNew - yPos + childh ) vw->resizeContents( vw->contentsWidth(), yNew - yPos + childh ); vw->setContentsPos( xNew - xPos, yNew - yPos ); } xPos = xNew; yPos = yNew; } m_view->setWidgetVisible(this, true); m_view->addChild(m_widget, xPos, yPos ); m_widget->show(); if (khtmlw) paintWidget(paintInfo, m_widget, xPos, yPos);}#include <private/qinternal_p.h>// The PaintBuffer class provides a shared buffer for widget painting.//// It will grow to encompass the biggest widget encountered, in order to avoid// constantly resizing.// When it grows over maxPixelBuffering, it periodically checks if such a size// is still needed. If not, it shrinks down to the biggest size < maxPixelBuffering// that was requested during the overflow lapse.class PaintBuffer: public QObject{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -