📄 render_frames.cpp
字号:
/**
* This file is part of the KDE project.
*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2000 Simon Hausmann <hausmann@kde.org>
* (C) 2000 Stefan Schimanski (1Stein@gmx.de)
* Copyright (C) 2004 Apple Computer, Inc.
* Copyright (c) 2005 Nokia Corporation, Inc.
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
//#define DEBUG_LAYOUT
#include "rendering/render_frames.h"
#include "css/cssproperties.h"
#include "rendering/render_canvas.h"
#include "html/html_baseimpl.h"
#include "html/html_objectimpl.h"
#include "html/htmltokenizer.h"
#include "misc/htmlattrs.h"
#include "xml/dom2_eventsimpl.h"
#include "xml/dom_docimpl.h"
#include "dom/dom_doc.h"
#include "misc/htmltags.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "render_arena.h"
#include "html/html_documentimpl.h"
#include <kapplication.h>
#include <kcursor.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include <klocale.h>
#include <kdebug.h>
#include <kglobal.h>
#include <qtimer.h>
#include <qpainter.h>
#include "qdict.h"
using namespace khtml;
using namespace DOM;
RenderFrameSet::RenderFrameSet( HTMLFrameSetElementImpl *frameSet)
: RenderContainer(frameSet)
{
// init RenderObject attributes
setInline(false);
for (int k = 0; k < 2; ++k) {
m_gridLen[k] = -1;
m_gridDelta[k] = 0;
m_gridLayout[k] = 0;
}
m_resizing = m_clientresizing= false;
m_hSplit = -1;
m_vSplit = -1;
m_hSplitVar = 0;
m_vSplitVar = 0;
}
RenderFrameSet::~RenderFrameSet()
{
#ifndef __OOM__
for (int k = 0; k < 2; ++k) {
if (m_gridLayout[k]) delete [] m_gridLayout[k];
if (m_gridDelta[k]) delete [] m_gridDelta[k];
}
if (m_hSplitVar)
delete [] m_hSplitVar;
if (m_vSplitVar)
delete [] m_vSplitVar;
#else
for (int k = 0; k < 2; ++k) {
if (m_gridLayout[k]) MemoryManager::Free( m_gridLayout[k] );
if (m_gridDelta[k]) MemoryManager::Free( m_gridDelta[k] );
}
if (m_hSplitVar)
MemoryManager::Free( m_hSplitVar );
if (m_vSplitVar)
MemoryManager::Free( m_vSplitVar );
#endif
}
bool RenderFrameSet::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
HitTestAction hitTestAction)
{
if (hitTestAction != HitTestForeground)
return false;
bool inside = RenderContainer::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction) ||
m_resizing || canResize(_x, _y);
if (inside && element() && !element()->noResize() && !info.readonly() && !info.innerNode()) {
info.setInnerNode(element());
info.setInnerNonSharedNode(element());
}
return inside || m_clientresizing;
}
#if NOKIA_CHANGES
void RenderFrameSet::calcMinMaxWidth()
{
// alternative minmax calculation for framesets
// this expands the frames to eliminate scrollbars from subframes to make frame usable
// on small screen devices
KHTMLAssert( !minMaxKnown() );
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << renderName() << "(RenderFrameSet)::calcMinMaxWidth() this=" << this << endl;
#endif
m_minWidth = 0;
m_maxWidth = 0;
RenderObject *child = firstChild();
int xMin = 0;
bool out = false;
for(int r = 0; r < element()->totalRows() && !out; r++)
{
int tempXMin = 0;
for(int c = 0; c < element()->totalCols(); c++)
{
if ( !child ) {
out = true;
break;
}
#ifdef DEBUG_LAYOUT
kdDebug(0) << "r=" << r << " c=" << c << endl;
#endif
child->setMinMaxKnown(false);
child->calcMinMaxWidth();
int w = child->minWidth();
if (element()->m_cols && element()->m_cols[c].type == Fixed)
{
// for fixed width columns, use fixed value as minimum
w = QMAX(w,element()->m_cols[c].value);
}
tempXMin += w + element()->border();
#ifdef DEBUG_LAYOUT
kdDebug(0) << " tempXMin=" << tempXMin << endl;
#endif
child = child->nextSibling();
}
tempXMin-=element()->border();
if (tempXMin>xMin)
xMin = tempXMin;
}
// make the top level frameset at least this wide
if (!parent()->isFrameSet() && !canvas()->view()->part()->parentPart())
xMin = QMAX(xMin,800);
m_minWidth = m_maxWidth = xMin;
setMinMaxKnown();
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << "RenderFrameSet::calcMinMaxWidth(" << this << "): min = " << m_minWidth << " max = " << m_maxWidth << endl;
#endif
}
#endif
void RenderFrameSet::layout( )
{
KHTMLAssert( needsLayout() );
KHTMLAssert( minMaxKnown() );
if ( !parent()->isFrameSet() ) {
KHTMLView* view = canvas()->view();
m_width = view->visibleWidth();
m_height = view->visibleHeight();
#if NOKIA_CHANGES
m_width = QMAX(m_width, m_minWidth);
// make the top level frameset at least this high
if (!canvas()->view()->part()->parentPart())
m_height = QMAX(m_height, 600);
#endif
}
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << renderName() << "(FrameSet)::layout( ) width=" << width() << ", height=" << height() << endl;
#endif
int remainingLen[2];
remainingLen[1] = m_width - (element()->totalCols()-1)*element()->border();
if(remainingLen[1]<0) remainingLen[1]=0;
remainingLen[0] = m_height - (element()->totalRows()-1)*element()->border();
if(remainingLen[0]<0) remainingLen[0]=0;
int availableLen[2];
availableLen[0] = remainingLen[0];
availableLen[1] = remainingLen[1];
if (m_gridLen[0] != element()->totalRows() || m_gridLen[1] != element()->totalCols()) {
// number of rows or cols changed
// need to zero out the deltas
m_gridLen[0] = element()->totalRows();
m_gridLen[1] = element()->totalCols();
#ifndef __OOM__
for (int k = 0; k < 2; ++k) {
if (m_gridDelta[k]) delete [] m_gridDelta[k];
m_gridDelta[k] = new int[m_gridLen[k]];
if (m_gridLayout[k]) delete [] m_gridLayout[k];
m_gridLayout[k] = new int[m_gridLen[k]];
for (int i = 0; i < m_gridLen[k]; ++i)
m_gridDelta[k][i] = 0;
}
#else
for (int k = 0; k < 2; ++k) {
if (m_gridDelta[k]) MemoryManager::Free( m_gridDelta[k] );
m_gridDelta[k] = (int*)MemoryManager::Calloc( m_gridLen[k], sizeof( int ) );
if (m_gridLayout[k]) MemoryManager::Free( m_gridLayout[k] );
m_gridLayout[k] = (int*)MemoryManager::Calloc( m_gridLen[k], sizeof( int ) );
}
#endif
}
for (int k = 0; k < 2; ++k) {
int totalRelative = 0;
int totalFixed = 0;
int totalPercent = 0;
int countRelative = 0;
int countPercent = 0;
int gridLen = m_gridLen[k];
int* gridDelta = m_gridDelta[k];
khtml::Length* grid = k ? element()->m_cols : element()->m_rows;
int* gridLayout = m_gridLayout[k];
if (grid) {
// first distribute the available width for fixed rows, then handle the
// percentage ones and distribute remaining over relative
for(int i = 0; i< gridLen; ++i) {
if (grid[i].isFixed()) {
gridLayout[i] = kMin(grid[i].value > 0 ? grid[i].value : 0, remainingLen[k]);
remainingLen[k] -= gridLayout[i];
totalFixed += gridLayout[i];
}
else if(grid[i].isRelative()) {
totalRelative += grid[i].value > 1 ? grid[i].value : 1;
countRelative++;
}
else if (grid[i].isPercent()) {
totalPercent += grid[i].value >= 0 ? grid[i].value : 0;
countPercent++;
}
}
int currPercent = totalPercent;
int percentLen = (countRelative && currPercent < 100) ? currPercent * remainingLen[k] / 100 : remainingLen[k];
for(int i = 0; i < gridLen; i++)
if (grid[i].isPercent() && grid[i].value >= 0 && currPercent) {
gridLayout[i] = grid[i].value * percentLen / currPercent;
remainingLen[k] -= gridLayout[i];
percentLen -= gridLayout[i];
currPercent -= grid[i].value;
}
assert(remainingLen[k] >= 0);
if (countRelative) {
int remaining = remainingLen[k];
for (int i = 0; i < gridLen; ++i)
if (grid[i].isRelative()) {
gridLayout[i] = ((grid[i].value > 1 ? grid[i].value : 1) * remaining) / totalRelative;
remainingLen[k] -= gridLayout[i];
}
}
// distribute the rest
if (remainingLen[k]) {
LengthType distributeType = countPercent ? Percent : Fixed;
int total = countPercent ? totalPercent : totalFixed;
if (!total) total = 1;
for (int i = 0; i < gridLen; ++i)
if (grid[i].type == distributeType) {
int toAdd = (remainingLen[k] * grid[i].value) / total;
gridLayout[i] += toAdd;
}
}
// now we have the final layout, distribute the delta over it
bool worked = true;
for (int i = 0; i < gridLen; ++i) {
if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
worked = false;
gridLayout[i] += gridDelta[i];
}
// now the delta's broke something, undo it and reset deltas
if (!worked)
for (int i = 0; i < gridLen; ++i) {
gridLayout[i] -= gridDelta[i];
gridDelta[i] = 0;
}
}
else
gridLayout[0] = remainingLen[k];
}
positionFrames();
RenderObject *child = firstChild();
if ( !child )
goto end2;
if(!m_hSplitVar && !m_vSplitVar)
{
#ifdef DEBUG_LAYOUT
kdDebug( 6031 ) << "calculationg fixed Splitters" << endl;
#endif
if(!m_vSplitVar && element()->totalCols() > 1)
{
#ifndef __OOM__
m_vSplitVar = new bool[element()->totalCols()];
#else
m_vSplitVar = (bool*)MemoryManager::Alloc( element()->totalCols() * sizeof( bool ) );
#endif
for(int i = 0; i < element()->totalCols(); i++) m_vSplitVar[i] = true;
}
if(!m_hSplitVar && element()->totalRows() > 1)
{
#ifndef __OOM__
m_hSplitVar = new bool[element()->totalRows()];
#else
m_hSplitVar = (bool*)MemoryManager::Alloc( element()->totalRows() * sizeof( bool ) );
#endif
for(int i = 0; i < element()->totalRows(); i++) m_hSplitVar[i] = true;
}
for(int r = 0; r < element()->totalRows(); r++)
{
for(int c = 0; c < element()->totalCols(); c++)
{
bool fixed = false;
if ( child->isFrameSet() )
fixed = static_cast<RenderFrameSet *>(child)->element()->noResize();
else
fixed = static_cast<RenderFrame *>(child)->element()->noResize();
if(fixed)
{
#ifdef DEBUG_LAYOUT
kdDebug( 6031 ) << "found fixed cell " << r << "/" << c << "!" << endl;
#endif
if( element()->totalCols() > 1)
{
if(c>0) m_vSplitVar[c-1] = false;
m_vSplitVar[c] = false;
}
if( element()->totalRows() > 1)
{
if(r>0) m_hSplitVar[r-1] = false;
m_hSplitVar[r] = false;
}
child = child->nextSibling();
if(!child) goto end2;
}
#ifdef DEBUG_LAYOUT
else
kdDebug( 6031 ) << "not fixed: " << r << "/" << c << "!" << endl;
#endif
}
}
}
RenderContainer::layout();
end2:
setNeedsLayout(false);
}
void RenderFrameSet::positionFrames()
{
int r;
int c;
RenderObject *child = firstChild();
if ( !child )
return;
// NodeImpl *child = _first;
// if(!child) return;
int yPos = 0;
#if NOKIA_CHANGES
// calculate frameset height based on actual content height to eliminate scrolling
bool out = false;
int widest = 0;
for(r = 0; r < element()->totalRows() && !out; r++)
{
int highest = 0;
int xPos = 0;
for(c = 0; c < element()->totalCols(); c++)
{
if ( !child ) {
out = true;
break;
}
child->setPos( xPos, yPos );
#ifdef DEBUG_LAYOUT
kdDebug(6040) << "child frame at (" << xPos << "/" << yPos << ") size (" << m_gridLayout[1][c] << "/" << m_gridLayout[0][r] << ")" << endl;
#endif
// has to be resized and itself resize its contents
child->setWidth( m_gridLayout[1][c] );
child->setHeight( m_gridLayout[0][r] );
child->setNeedsLayout(true);
child->layout();
if (highest<child->height())
highest = child->height();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -