diff options
Diffstat (limited to 'khtml/rendering')
61 files changed, 0 insertions, 37464 deletions
diff --git a/khtml/rendering/CMakeLists.txt b/khtml/rendering/CMakeLists.txt deleted file mode 100644 index fe3301265..000000000 --- a/khtml/rendering/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -################################################# -# -# (C) 2010 Serghei Amelian -# serghei (DOT) amelian (AT) gmail.com -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -include_directories( - ${TQT_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_BINARY_DIR}/tdecore - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/khtml - ${CMAKE_SOURCE_DIR}/tdecore - ${CMAKE_SOURCE_DIR}/tdeui - ${CMAKE_SOURCE_DIR}/kio - ${CMAKE_SOURCE_DIR}/kio/kio - ${CMAKE_SOURCE_DIR}/kio/kfile - ${CMAKE_SOURCE_DIR}/kutils -) - - -##### khtmlrender-static ######################### - -set( target khtmlrender ) - -set( ${target}_SRCS - bidi.cpp break_lines.cpp render_block.cpp render_inline.cpp - render_style.cpp render_object.cpp render_container.cpp render_box.cpp - render_flow.cpp render_text.cpp render_arena.cpp render_layer.cpp - render_image.cpp render_table.cpp table_layout.cpp - render_replaced.cpp render_form.cpp render_list.cpp - render_canvas.cpp render_frames.cpp render_br.cpp - render_body.cpp font.cpp render_line.cpp render_generated.cpp - enumerate.cpp counter_tree.cpp -) - -tde_add_library( ${target} STATIC_PIC AUTOMOC - SOURCES ${${target}_SRCS} -) diff --git a/khtml/rendering/Makefile.am b/khtml/rendering/Makefile.am deleted file mode 100644 index d41638f27..000000000 --- a/khtml/rendering/Makefile.am +++ /dev/null @@ -1,57 +0,0 @@ -# This file is part of the KDE libraries -# Copyright (C) 1997 Martin Jones (mjones@kde.org) -# (C) 1997 Torben Weis (weis@kde.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. - -KDE_CXXFLAGS = $(WOVERLOADED_VIRTUAL) - -noinst_LTLIBRARIES = libkhtmlrender.la -libkhtmlrender_la_SOURCES = \ - bidi.cpp break_lines.cpp render_block.cpp render_inline.cpp \ - render_style.cpp render_object.cpp render_container.cpp render_box.cpp \ - render_flow.cpp render_text.cpp render_arena.cpp render_layer.cpp \ - render_image.cpp render_table.cpp table_layout.cpp \ - render_replaced.cpp render_form.cpp render_list.cpp \ - render_canvas.cpp render_frames.cpp render_br.cpp \ - render_body.cpp font.cpp render_line.cpp render_generated.cpp \ - enumerate.cpp counter_tree.cpp - -libkhtmlrender_la_METASOURCES = AUTO - -noinst_HEADERS = \ - bidi.h break_lines.h \ - render_arena.h render_layer.h \ - render_style.h render_object.h render_container.h render_box.h \ - render_flow.h render_text.h render_table.h render_replaced.h \ - render_form.h render_list.h render_canvas.h render_frames.h \ - render_br.h render_applet.h font.h table_layout.h render_line.h \ - render_generated.h enumerate.h - -INCLUDES = -I$(top_srcdir)/kimgio -I$(top_srcdir)/kio -I$(top_srcdir)/dcop \ - -I$(top_srcdir)/kfile -I$(top_srcdir)/khtml -I$(top_srcdir)/kutils -I$(top_srcdir) $(all_includes) - -SRCDOC_DEST=$(kde_htmldir)/en/tdelibs/khtml - -## generate lib documentation -srcdoc: - $(mkinstalldirs) $(SRCDOC_DEST) - kdoc -H -d $(SRCDOC_DEST) tdecore -lqt - -## maintainer: regen loading icon -loading-icon: - bin2c -sploading_icon $(srcdir)/img-loading.png > $(srcdir)/loading_icon.cpp - diff --git a/khtml/rendering/bidi.cpp b/khtml/rendering/bidi.cpp deleted file mode 100644 index 2dcfe48c9..000000000 --- a/khtml/rendering/bidi.cpp +++ /dev/null @@ -1,2250 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org) - * (C) 2003-2005 Apple Computer, Inc. - * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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 "rendering/bidi.h" -#include "rendering/break_lines.h" -#include "rendering/render_block.h" -#include "rendering/render_text.h" -#include "rendering/render_arena.h" -#include "rendering/render_layer.h" -#include "rendering/render_canvas.h" -#include "xml/dom_docimpl.h" - -#include "kdebug.h" -#include "tqdatetime.h" -#include "tqfontmetrics.h" - -#define BIDI_DEBUG 0 -//#define DEBUG_LINEBREAKS -//#define PAGE_DEBUG - -namespace khtml { - - -// an iterator which goes through a BidiParagraph -struct BidiIterator -{ - BidiIterator() : par(0), obj(0), pos(0), endOfInline(0) {} - BidiIterator(RenderBlock *_par, RenderObject *_obj, unsigned int _pos, bool eoi=false) : par(_par), obj(_obj), pos(_pos), endOfInline(eoi) {} - - void increment( BidiState &bidi, bool skipInlines=true ); - - bool atEnd() const; - - const TQChar ¤t() const; - TQChar::Direction direction() const; - - RenderBlock *par; - RenderObject *obj; - unsigned int pos; - bool endOfInline; -}; - - -struct BidiStatus { - BidiStatus() : eor(TQChar::DirON), lastStrong(TQChar::DirON), last(TQChar::DirON) {} - - TQChar::Direction eor; - TQChar::Direction lastStrong; - TQChar::Direction last; -}; - -struct BidiState { - BidiState() : context(0) {} - - BidiIterator sor; - BidiIterator eor; - BidiIterator last; - BidiIterator current; - BidiContext *context; - BidiStatus status; -}; - -// Used to track a list of chained bidi runs. -static BidiRun* sFirstBidiRun; -static BidiRun* sLastBidiRun; -static int sBidiRunCount; -static BidiRun* sCompactFirstBidiRun; -static BidiRun* sCompactLastBidiRun; -static int sCompactBidiRunCount; -static bool sBuildingCompactRuns; - -// Midpoint globals. The goal is not to do any allocation when dealing with -// these midpoints, so we just keep an array around and never clear it. We track -// the number of items and position using the two other variables. -static TQMemArray<BidiIterator> *smidpoints; -static uint sNumMidpoints; -static uint sCurrMidpoint; -static bool betweenMidpoints; - -static bool isLineEmpty = true; -static bool previousLineBrokeAtBR = true; -static TQChar::Direction dir; -static bool adjustEmbedding; -static bool emptyRun = true; -static int numSpaces; - -static void embed( TQChar::Direction d, BidiState &bidi ); -static void appendRun( BidiState &bidi ); - -static int getBPMWidth(int childValue, Length cssUnit) -{ - if (!cssUnit.isVariable()) - return (cssUnit.isFixed() ? cssUnit.value() : childValue); - return 0; -} - -static int getBorderPaddingMargin(RenderObject* child, bool endOfInline) -{ - RenderStyle* cstyle = child->style(); - int result = 0; - bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline; - result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()), - (leftSide ? cstyle->marginLeft() : - cstyle->marginRight())); - result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()), - (leftSide ? cstyle->paddingLeft() : - cstyle->paddingRight())); - result += leftSide ? child->borderLeft() : child->borderRight(); - return result; -} - -#ifndef NDEBUG -static bool inBidiRunDetach; -#endif - -void BidiRun::detach(RenderArena* renderArena) -{ -#ifndef NDEBUG - inBidiRunDetach = true; -#endif - delete this; -#ifndef NDEBUG - inBidiRunDetach = false; -#endif - - // Recover the size left there for us by operator delete and free the memory. - renderArena->free(*(size_t *)this, this); -} - -void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw() -{ - return renderArena->allocate(sz); -} - -void BidiRun::operator delete(void* ptr, size_t sz) -{ - assert(inBidiRunDetach); - - // Stash size where detach can find it. - *(size_t*)ptr = sz; -} - -static void deleteBidiRuns(RenderArena* arena) -{ - if (!sFirstBidiRun) - return; - - BidiRun* curr = sFirstBidiRun; - while (curr) { - BidiRun* s = curr->nextRun; - curr->detach(arena); - curr = s; - } - - sFirstBidiRun = 0; - sLastBidiRun = 0; - sBidiRunCount = 0; -} - -// --------------------------------------------------------------------- - -/* a small helper class used internally to resolve Bidi embedding levels. - Each line of text caches the embedding level at the start of the line for faster - relayouting -*/ -BidiContext::BidiContext(unsigned char l, TQChar::Direction e, BidiContext *p, bool o) - : level(l) , override(o), dir(e) -{ - parent = p; - if(p) { - p->ref(); - basicDir = p->basicDir; - } else - basicDir = e; - count = 0; -} - -BidiContext::~BidiContext() -{ - if(parent) parent->deref(); -} - -void BidiContext::ref() const -{ - count++; -} - -void BidiContext::deref() const -{ - count--; - if(count <= 0) delete this; -} - -// --------------------------------------------------------------------- - -inline bool operator==( const BidiIterator &it1, const BidiIterator &it2 ) -{ - if(it1.pos != it2.pos) return false; - if(it1.obj != it2.obj) return false; - return true; -} - -inline bool operator!=( const BidiIterator &it1, const BidiIterator &it2 ) -{ - if(it1.pos != it2.pos) return true; - if(it1.obj != it2.obj) return true; - return false; -} - -// when modifying this function, make sure you check InlineMinMaxIterator::next() as well. -static inline RenderObject *Bidinext(RenderObject *par, RenderObject *current, BidiState &bidi, - bool skipInlines = true, bool *endOfInline = 0 ) -{ - RenderObject *next = 0; - bool oldEndOfInline = endOfInline ? *endOfInline : false; - if (oldEndOfInline) - *endOfInline = false; - - while(current != 0) - { - //kdDebug( 6040 ) << "current = " << current << endl; - if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) { - next = current->firstChild(); - if ( next && adjustEmbedding ) { - EUnicodeBidi ub = next->style()->unicodeBidi(); - if ( ub != UBNormal && !emptyRun ) { - EDirection dir = next->style()->direction(); - TQChar::Direction d = ( ub == Embed ? ( dir == RTL ? TQChar::DirRLE : TQChar::DirLRE ) - : ( dir == RTL ? TQChar::DirRLO : TQChar::DirLRO ) ); - embed( d, bidi ); - } - } - } - if (!next) { - if (!skipInlines && !oldEndOfInline && current->isInlineFlow() && endOfInline) { - next = current; - *endOfInline = true; - break; - } - - while (current && current != par) { - next = current->nextSibling(); - if (next) break; - if ( adjustEmbedding && current->style()->unicodeBidi() != UBNormal && !emptyRun ) { - embed( TQChar::DirPDF, bidi ); - } - current = current->parent(); - if (!skipInlines && current && current != par && current->isInlineFlow() && endOfInline) { - next = current; - *endOfInline = true; - break; - } - } - } - - if (!next) break; - - if (next->isText() || next->isBR() || next->isFloating() || next->isReplaced() || next->isPositioned() || next->isGlyph() - || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines. - && next->isInlineFlow())) - break; - current = next; - } - return next; -} - -static RenderObject *first( RenderObject *par, BidiState &bidi, bool skipInlines = true ) -{ - if(!par->firstChild()) return 0; - RenderObject *o = par->firstChild(); - - if (o->isInlineFlow()) { - if (skipInlines && o->firstChild()) - o = Bidinext( par, o, bidi, skipInlines ); - else - return o; // Never skip empty inlines. - } - - if (o && !o->isText() && !o->isBR() && !o->isReplaced() && !o->isFloating() && !o->isPositioned() && !o->isGlyph()) - o = Bidinext( par, o, bidi, skipInlines ); - return o; -} - -inline void BidiIterator::increment (BidiState &bidi, bool skipInlines) -{ - if(!obj) return; - if(obj->isText()) { - pos++; - if(pos >= static_cast<RenderText *>(obj)->stringLength()) { - obj = Bidinext( par, obj, bidi, skipInlines ); - pos = 0; - } - } else { - obj = Bidinext( par, obj, bidi, skipInlines, &endOfInline ); - pos = 0; - } -} - -inline bool BidiIterator::atEnd() const -{ - if(!obj) return true; - return false; -} - -const TQChar &BidiIterator::current() const -{ - static TQChar nonBreakingSpace(0xA0); - - if (!obj || !obj->isText()) - return nonBreakingSpace; - - RenderText* text = static_cast<RenderText*>(obj); - if (!text->text()) - return nonBreakingSpace; - - return text->text()[pos]; -} - -inline TQChar::Direction BidiIterator::direction() const -{ - if(!obj || !obj->isText() ) return TQChar::DirON; - - RenderText *renderTxt = static_cast<RenderText *>( obj ); - if ( pos >= renderTxt->stringLength() ) - return TQChar::DirON; - return renderTxt->text()[pos].direction(); -} - -// ------------------------------------------------------------------------------------------------- - -static void addRun(BidiRun* bidiRun) -{ - if (!sFirstBidiRun) - sFirstBidiRun = sLastBidiRun = bidiRun; - else { - sLastBidiRun->nextRun = bidiRun; - sLastBidiRun = bidiRun; - } - sBidiRunCount++; - bidiRun->compact = sBuildingCompactRuns; - - // Compute the number of spaces in this run, - if (bidiRun->obj && bidiRun->obj->isText()) { - RenderText* text = static_cast<RenderText*>(bidiRun->obj); - if (text->text()) { - for (int i = bidiRun->start; i < bidiRun->stop; i++) { - const TQChar c = text->text()[i]; - if (c.category() == TQChar::Separator_Space || c == '\n') - numSpaces++; - } - } - } -} - -static void reverseRuns(int start, int end) -{ - if (start >= end) - return; - - assert(start >= 0 && end < sBidiRunCount); - - // Get the item before the start of the runs to reverse and put it in - // |beforeStart|. |curr| should point to the first run to reverse. - BidiRun* curr = sFirstBidiRun; - BidiRun* beforeStart = 0; - int i = 0; - while (i < start) { - i++; - beforeStart = curr; - curr = curr->nextRun; - } - - BidiRun* startRun = curr; - while (i < end) { - i++; - curr = curr->nextRun; - } - BidiRun* endRun = curr; - BidiRun* afterEnd = curr->nextRun; - - i = start; - curr = startRun; - BidiRun* newNext = afterEnd; - while (i <= end) { - // Do the reversal. - BidiRun* next = curr->nextRun; - curr->nextRun = newNext; - newNext = curr; - curr = next; - i++; - } - - // Now hook up beforeStart and afterEnd to the newStart and newEnd. - if (beforeStart) - beforeStart->nextRun = endRun; - else - sFirstBidiRun = endRun; - - startRun->nextRun = afterEnd; - if (!afterEnd) - sLastBidiRun = startRun; -} - -static void chopMidpointsAt(RenderObject* obj, uint pos) -{ - if (!sNumMidpoints) return; - BidiIterator* midpoints = smidpoints->data(); - for (uint i = 0; i < sNumMidpoints; i++) { - const BidiIterator& point = midpoints[i]; - if (point.obj == obj && point.pos == pos) { - sNumMidpoints = i; - break; - } - } -} - -static void checkMidpoints(BidiIterator& lBreak, BidiState &bidi) -{ - // Check to see if our last midpoint is a start point beyond the line break. If so, - // shave it off the list, and shave off a trailing space if the previous end point isn't - // white-space: pre. - if (lBreak.obj && sNumMidpoints && sNumMidpoints%2 == 0) { - BidiIterator* midpoints = smidpoints->data(); - BidiIterator& endpoint = midpoints[sNumMidpoints-2]; - const BidiIterator& startpoint = midpoints[sNumMidpoints-1]; - BidiIterator currpoint = endpoint; - while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) - currpoint.increment( bidi ); - if (currpoint == lBreak) { - // We hit the line break before the start point. Shave off the start point. - sNumMidpoints--; - if (!endpoint.obj->style()->preserveWS()) { - if (endpoint.obj->isText()) { - // Don't shave a character off the endpoint if it was from a soft hyphen. - RenderText* textObj = static_cast<RenderText*>(endpoint.obj); - if (endpoint.pos+1 < textObj->length() && - textObj->text()[endpoint.pos+1].unicode() == SOFT_HYPHEN) - return; - } - endpoint.pos--; - } - } - } -} - -static void addMidpoint(const BidiIterator& midpoint) -{ - if (!smidpoints) - return; - - if (smidpoints->size() <= sNumMidpoints) - smidpoints->resize(sNumMidpoints+10); - - BidiIterator* midpoints = smidpoints->data(); - midpoints[sNumMidpoints++] = midpoint; -} - -static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState &bidi) -{ - if (start > end || obj->isFloating() || - (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY())) - return; - - bool haveNextMidpoint = (smidpoints && sCurrMidpoint < sNumMidpoints); - BidiIterator nextMidpoint; - if (haveNextMidpoint) - nextMidpoint = smidpoints->at(sCurrMidpoint); - if (betweenMidpoints) { - if (!(haveNextMidpoint && nextMidpoint.obj == obj)) - return; - // This is a new start point. Stop ignoring objects and - // adjust our start. - betweenMidpoints = false; - start = nextMidpoint.pos; - sCurrMidpoint++; - if (start < end) - return appendRunsForObject(start, end, obj, bidi); - } - else { - if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) { - addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, dir)); - return; - } - - // An end midpoint has been encountered within our object. We - // need to go ahead and append a run with our endpoint. - if (int(nextMidpoint.pos+1) <= end) { - betweenMidpoints = true; - sCurrMidpoint++; - if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it. - addRun(new (obj->renderArena()) - BidiRun(start, nextMidpoint.pos+1, obj, bidi.context, dir)); - return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi); - } - } - else - addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, dir)); - } -} - -static void appendRun( BidiState &bidi ) -{ - if ( emptyRun ) return; -#if BIDI_DEBUG > 1 - kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl; -#endif - - bool b = adjustEmbedding; - adjustEmbedding = false; - - int start = bidi.sor.pos; - RenderObject *obj = bidi.sor.obj; - while( obj && obj != bidi.eor.obj ) { - appendRunsForObject(start, obj->length(), obj, bidi); - start = 0; - obj = Bidinext( bidi.sor.par, obj, bidi ); - } - if (obj) - appendRunsForObject(start, bidi.eor.pos+1, obj, bidi); - - bidi.eor.increment( bidi ); - bidi.sor = bidi.eor; - dir = TQChar::DirON; - bidi.status.eor = TQChar::DirON; - adjustEmbedding = b; -} - -static void embed( TQChar::Direction d, BidiState &bidi ) -{ -#if BIDI_DEBUG > 1 - tqDebug("*** embed dir=%d emptyrun=%d", d, emptyRun ); -#endif - bool b = adjustEmbedding ; - adjustEmbedding = false; - if ( d == TQChar::DirPDF ) { - BidiContext *c = bidi.context->parent; - if (c) { - if ( bidi.eor != bidi.last ) { - appendRun( bidi ); - bidi.eor = bidi.last; - } - appendRun( bidi ); - emptyRun = true; - bidi.status.last = bidi.context->dir; - bidi.context->deref(); - bidi.context = c; - if(bidi.context->override) - dir = bidi.context->dir; - else - dir = TQChar::DirON; - bidi.status.lastStrong = bidi.context->dir; - } - } else { - TQChar::Direction runDir; - if( d == TQChar::DirRLE || d == TQChar::DirRLO ) - runDir = TQChar::DirR; - else - runDir = TQChar::DirL; - bool override; - if( d == TQChar::DirLRO || d == TQChar::DirRLO ) - override = true; - else - override = false; - - unsigned char level = bidi.context->level; - if ( runDir == TQChar::DirR ) { - if(level%2) // we have an odd level - level += 2; - else - level++; - } else { - if(level%2) // we have an odd level - level++; - else - level += 2; - } - - if(level < 61) { - if ( bidi.eor != bidi.last ) { - appendRun( bidi ); - bidi.eor = bidi.last; - } - appendRun( bidi ); - emptyRun = true; - - bidi.context = new BidiContext(level, runDir, bidi.context, override); - bidi.context->ref(); - dir = runDir; - bidi.status.last = runDir; - bidi.status.lastStrong = runDir; - bidi.status.eor = runDir; - } - } - adjustEmbedding = b; -} - -InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj) -{ - // See if we have an unconstructed line box for this object that is also - // the last item on the line. - KHTMLAssert(obj->isInlineFlow() || obj == this); - RenderFlow* flow = static_cast<RenderFlow*>(obj); - - // Get the last box we made for this render object. - InlineFlowBox* box = flow->lastLineBox(); - - // If this box is constructed then it is from a previous line, and we need - // to make a new box for our line. If this box is unconstructed but it has - // something following it on the line, then we know we have to make a new box - // as well. In this situation our inline has actually been split in two on - // the same line (this can happen with very fancy language mixtures). - if (!box || box->isConstructed() || box->nextOnLine()) { - // We need to make a new box for this render object. Once - // made, we need to place it at the end of the current line. - InlineBox* newBox = obj->createInlineBox(false, obj == this); - KHTMLAssert(newBox->isInlineFlowBox()); - box = static_cast<InlineFlowBox*>(newBox); - box->setFirstLineStyleBit(m_firstLine); - - // We have a new box. Append it to the inline box we get by constructing our - // parent. If we have hit the block itself, then |box| represents the root - // inline box for the line, and it doesn't have to be appended to any parent - // inline. - if (obj != this) { - InlineFlowBox* parentBox = createLineBoxes(obj->parent()); - parentBox->addToLine(box); - } - } - - return box; -} - -InlineFlowBox* RenderBlock::constructLine(const BidiIterator &/*start*/, const BidiIterator &end) -{ - if (!sFirstBidiRun) - return 0; // We had no runs. Don't make a root inline box at all. The line is empty. - - InlineFlowBox* parentBox = 0; - for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) { - // Create a box for our object. - r->box = r->obj->createInlineBox(r->obj->isPositioned(), false); - - // If we have no parent box yet, or if the run is not simply a sibling, - // then we need to construct inline boxes as necessary to properly enclose the - // run's inline box. - if (!parentBox || (parentBox->object() != r->obj->parent())) - // Create new inline boxes all the way back to the appropriate insertion point. - parentBox = createLineBoxes(r->obj->parent()); - - // Append the inline box to this line. - parentBox->addToLine(r->box); - } - - // We should have a root inline box. It should be unconstructed and - // be the last continuation of our line list. - KHTMLAssert(lastLineBox() && !lastLineBox()->isConstructed()); - - // Set bits on our inline flow boxes that indicate which sides should - // paint borders/margins/padding. This knowledge will ultimately be used when - // we determine the horizontal positions and widths of all the inline boxes on - // the line. - RenderObject* endObject = 0; - bool lastLine = !end.obj; - if (end.obj && end.pos == 0) - endObject = end.obj; - lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject); - - // Now mark the line boxes as being constructed. - lastLineBox()->setConstructed(); - - // Return the last line. - return lastLineBox(); -} - -void RenderBlock::computeHorizontalPositionsForLine(InlineFlowBox* lineBox, BidiState &bidi) -{ - // First determine our total width. - int totWidth = lineBox->getFlowSpacingWidth(); - BidiRun* r = 0; - for (r = sFirstBidiRun; r; r = r->nextRun) { - if (r->obj->isPositioned()) - continue; // Positioned objects are only participating to figure out their - // correct static x position. They have no effect on the width. - if (r->obj->isText()) - r->box->setWidth(static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, m_firstLine)); - else if (!r->obj->isInlineFlow()) { - r->obj->calcWidth(); - r->box->setWidth(r->obj->width()); - totWidth += r->obj->marginLeft() + r->obj->marginRight(); - } - totWidth += r->box->width(); - } - - // Armed with the total width of the line (without justification), - // we now examine our text-align property in order to determine where to position the - // objects horizontally. The total width of the line can be increased if we end up - // justifying text. - int x = leftOffset(m_height); - int availableWidth = lineWidth(m_height); - switch(style()->textAlign()) { - case LEFT: - case KHTML_LEFT: - numSpaces = 0; - break; - case JUSTIFY: - if (numSpaces != 0 && !bidi.current.atEnd() && !bidi.current.obj->isBR() ) - break; - // fall through - case TAAUTO: - numSpaces = 0; - // for right to left fall through to right aligned - if (bidi.context->basicDir == TQChar::DirL) - break; - case RIGHT: - case KHTML_RIGHT: - x += availableWidth - totWidth; - numSpaces = 0; - break; - case CENTER: - case KHTML_CENTER: - int xd = (availableWidth - totWidth)/2; - x += xd >0 ? xd : 0; - numSpaces = 0; - break; - } - - if (numSpaces > 0) { - for (r = sFirstBidiRun; r; r = r->nextRun) { - int spaceAdd = 0; - if (numSpaces > 0 && r->obj->isText()) { - // get the number of spaces in the run - int spaces = 0; - for ( int i = r->start; i < r->stop; i++ ) { - const TQChar c = static_cast<RenderText *>(r->obj)->text()[i]; - if (c.category() == TQChar::Separator_Space || c == '\n') - spaces++; - } - - KHTMLAssert(spaces <= numSpaces); - - // Only justify text with white-space: normal. - if (r->obj->style()->whiteSpace() == NORMAL) { - spaceAdd = (availableWidth - totWidth)*spaces/numSpaces; - static_cast<InlineTextBox*>(r->box)->setSpaceAdd(spaceAdd); - totWidth += spaceAdd; - } - numSpaces -= spaces; - } - } - } - - // The widths of all runs are now known. We can now place every inline box (and - // compute accurate widths for the inline flow boxes). - int rightPos = lineBox->placeBoxesHorizontally(x); - if (rightPos > m_overflowWidth) - m_overflowWidth = rightPos; // FIXME: Work for rtl overflow also. - if (x < 0) - m_overflowLeft = kMin(m_overflowLeft, x); -} - -void RenderBlock::computeVerticalPositionsForLine(InlineFlowBox* lineBox) -{ - lineBox->verticallyAlignBoxes(m_height); -// lineBox->setBlockHeight(m_height); - - // Check for page-breaks - if (canvas()->pagedMode() && !lineBox->afterPageBreak()) - // If we get a page-break we might need to redo the line-break - if (clearLineOfPageBreaks(lineBox) && hasFloats()) return; - - // See if the line spilled out. If so set overflow height accordingly. - int bottomOfLine = lineBox->bottomOverflow(); - if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight) - m_overflowHeight = bottomOfLine; - - bool beforeContent = true; - - // Now make sure we place replaced render objects correctly. - for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) { - - // For positioned placeholders, cache the static Y position an object with non-inline display would have. - // Either it is unchanged if it comes before any real linebox, or it must clear the current line (already accounted in m_height). - // This value will be picked up by position() if relevant. - if (r->obj->isPositioned()) - r->box->setYPos( beforeContent && r->obj->isBox() ? static_cast<RenderBox*>(r->obj)->staticY() : m_height ); - else if (beforeContent) - beforeContent = false; - - // Position is used to properly position both replaced elements and - // to update the static normal flow x/y of positioned elements. - r->obj->position(r->box, r->start, r->stop - r->start, r->level%2); - } -} - -bool RenderBlock::clearLineOfPageBreaks(InlineFlowBox* lineBox) -{ - bool doPageBreak = false; - // Check for physical page-breaks - int xpage = crossesPageBreak(lineBox->topOverflow(), lineBox->bottomOverflow()); - if (xpage) { -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << " Line crosses to page " << xpage << endl; - kdDebug(6040) << renderName() << " at pos " << lineBox->yPos() << " height " << lineBox->height() << endl; -#endif - - doPageBreak = true; - // check page-break-inside - if (!style()->pageBreakInside()) { - if (parent()->canClear(this, PageBreakNormal)) { - setNeedsPageClear(true); - doPageBreak = false; - } -#ifdef PAGE_DEBUG - else - kdDebug(6040) << "Ignoring page-break-inside: avoid" << endl; -#endif - } - // check orphans - int orphans = 0; - InlineRunBox* box = lineBox->prevLineBox(); - while (box && orphans < style()->orphans()) { - orphans++; - box = box->prevLineBox(); - } - - if (orphans == 0) { - setNeedsPageClear(true); - doPageBreak = false; - } else - if (orphans < style()->orphans() ) { -#ifdef PAGE_DEBUG - kdDebug(6040) << "Orphans: " << orphans << endl; -#endif - // Orphans is a level 2 page-break rule and can be broken only - // if the break is physically required. - if (parent()->canClear(this, PageBreakHarder)) { - // move block instead - setNeedsPageClear(true); - doPageBreak = false; - } -#ifdef PAGE_DEBUG - else - kdDebug(6040) << "Ignoring violated orphans" << endl; -#endif - } - if (doPageBreak) { - int pTop = pageTopAfter(lineBox->yPos()); - - m_height = pTop; - lineBox->setAfterPageBreak(true); - lineBox->verticallyAlignBoxes(m_height); - if (lineBox->yPos() < pTop) { - // ### serious crap. render_line is sometimes placing lines too high - kdDebug(6040) << "page top overflow by repositioned line" << endl; - int heightIncrease = pTop - lineBox->yPos(); - m_height = pTop + heightIncrease; - lineBox->verticallyAlignBoxes(m_height); - } -#ifdef PAGE_DEBUG - kdDebug(6040) << "Cleared line " << lineBox->yPos() - oldYPos << "px" << endl; -#endif - setContainsPageBreak(true); - } - } - return doPageBreak; -} - -// collects one line of the paragraph and transforms it to visual order -void RenderBlock::bidiReorderLine(const BidiIterator &start, const BidiIterator &end, BidiState &bidi) -{ - if ( start == end ) { - if ( start.current() == '\n' ) { - m_height += lineHeight( m_firstLine ); - } - return; - } - -#if BIDI_DEBUG > 1 - kdDebug(6041) << "reordering Line from " << start.obj << "/" << start.pos << " to " << end.obj << "/" << end.pos << endl; -#endif - - sFirstBidiRun = 0; - sLastBidiRun = 0; - sBidiRunCount = 0; - - // context->ref(); - - dir = TQChar::DirON; - emptyRun = true; - - numSpaces = 0; - - bidi.current = start; - bidi.last = bidi.current; - bool atEnd = false; - while( 1 ) { - - TQChar::Direction dirCurrent; - if (atEnd) { - //kdDebug(6041) << "atEnd" << endl; - BidiContext *c = bidi.context; - if ( bidi.current.atEnd()) - while ( c->parent ) - c = c->parent; - dirCurrent = c->dir; - } else { - dirCurrent = bidi.current.direction(); - } - -#ifndef QT_NO_UNICODETABLES - -#if BIDI_DEBUG > 1 - kdDebug(6041) << "directions: dir=" << (int)dir << " current=" << (int)dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << (int)context->dir << " level =" << (int)context->level << endl; -#endif - - switch(dirCurrent) { - - // embedding and overrides (X1-X9 in the Bidi specs) - case TQChar::DirRLE: - case TQChar::DirLRE: - case TQChar::DirRLO: - case TQChar::DirLRO: - case TQChar::DirPDF: - embed( dirCurrent, bidi ); - break; - - // strong types - case TQChar::DirL: - if(dir == TQChar::DirON) - dir = TQChar::DirL; - switch(bidi.status.last) - { - case TQChar::DirL: - bidi.eor = bidi.current; bidi.status.eor = TQChar::DirL; break; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirEN: - case TQChar::DirAN: - appendRun( bidi ); - break; - case TQChar::DirES: - case TQChar::DirET: - case TQChar::DirCS: - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if( bidi.status.eor != TQChar::DirL ) { - //last stuff takes embedding dir - if(bidi.context->dir == TQChar::DirL || bidi.status.lastStrong == TQChar::DirL) { - if ( bidi.status.eor != TQChar::DirEN && bidi.status.eor != TQChar::DirAN && bidi.status.eor != TQChar::DirON ) - appendRun( bidi ); - dir = TQChar::DirL; - bidi.eor = bidi.current; - bidi.status.eor = TQChar::DirL; - } else { - if ( bidi.status.eor == TQChar::DirEN || bidi.status.eor == TQChar::DirAN ) - { - dir = bidi.status.eor; - appendRun( bidi ); - } - dir = TQChar::DirR; - bidi.eor = bidi.last; - appendRun( bidi ); - dir = TQChar::DirL; - bidi.status.eor = TQChar::DirL; - } - } else { - bidi.eor = bidi.current; bidi.status.eor = TQChar::DirL; - } - default: - break; - } - bidi.status.lastStrong = TQChar::DirL; - break; - case TQChar::DirAL: - case TQChar::DirR: - if(dir == TQChar::DirON) dir = TQChar::DirR; - switch(bidi.status.last) - { - case TQChar::DirR: - case TQChar::DirAL: - bidi.eor = bidi.current; bidi.status.eor = TQChar::DirR; break; - case TQChar::DirL: - case TQChar::DirEN: - case TQChar::DirAN: - appendRun( bidi ); - dir = TQChar::DirR; - bidi.eor = bidi.current; - bidi.status.eor = TQChar::DirR; - break; - case TQChar::DirES: - case TQChar::DirET: - case TQChar::DirCS: - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if( !(bidi.status.eor == TQChar::DirR) && !(bidi.status.eor == TQChar::DirAL) ) { - //last stuff takes embedding dir - if(bidi.context->dir == TQChar::DirR || bidi.status.lastStrong == TQChar::DirR - || bidi.status.lastStrong == TQChar::DirAL) { - appendRun( bidi ); - dir = TQChar::DirR; - bidi.eor = bidi.current; - bidi.status.eor = TQChar::DirR; - } else { - dir = TQChar::DirL; - bidi.eor = bidi.last; - appendRun( bidi ); - dir = TQChar::DirR; - bidi.status.eor = TQChar::DirR; - } - } else { - bidi.eor = bidi.current; bidi.status.eor = TQChar::DirR; - } - default: - break; - } - bidi.status.lastStrong = dirCurrent; - break; - - // weak types: - - case TQChar::DirNSM: - // ### if @sor, set dir to dirSor - break; - case TQChar::DirEN: - if(!(bidi.status.lastStrong == TQChar::DirAL)) { - // if last strong was AL change EN to AN - if(dir == TQChar::DirON) { - dir = TQChar::DirL; - } - switch(bidi.status.last) - { - case TQChar::DirET: - if ( bidi.status.lastStrong == TQChar::DirR || bidi.status.lastStrong == TQChar::DirAL ) { - appendRun( bidi ); - dir = TQChar::DirEN; - bidi.status.eor = TQChar::DirEN; - } - // fall through - case TQChar::DirEN: - case TQChar::DirL: - bidi.eor = bidi.current; - bidi.status.eor = dirCurrent; - break; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirAN: - appendRun( bidi ); - bidi.status.eor = TQChar::DirEN; - dir = TQChar::DirEN; break; - case TQChar::DirES: - case TQChar::DirCS: - if(bidi.status.eor == TQChar::DirEN) { - bidi.eor = bidi.current; break; - } - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if(bidi.status.eor == TQChar::DirR) { - // neutrals go to R - bidi.eor = bidi.last; - appendRun( bidi ); - dir = TQChar::DirEN; - bidi.status.eor = TQChar::DirEN; - } - else if( bidi.status.eor == TQChar::DirL || - (bidi.status.eor == TQChar::DirEN && bidi.status.lastStrong == TQChar::DirL)) { - bidi.eor = bidi.current; bidi.status.eor = dirCurrent; - } else { - // numbers on both sides, neutrals get right to left direction - if(dir != TQChar::DirL) { - appendRun( bidi ); - bidi.eor = bidi.last; - dir = TQChar::DirR; - appendRun( bidi ); - dir = TQChar::DirEN; - bidi.status.eor = TQChar::DirEN; - } else { - bidi.eor = bidi.current; bidi.status.eor = dirCurrent; - } - } - default: - break; - } - break; - } - case TQChar::DirAN: - dirCurrent = TQChar::DirAN; - if(dir == TQChar::DirON) dir = TQChar::DirAN; - switch(bidi.status.last) - { - case TQChar::DirL: - case TQChar::DirAN: - bidi.eor = bidi.current; bidi.status.eor = TQChar::DirAN; break; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirEN: - appendRun( bidi ); - dir = TQChar::DirAN; bidi.status.eor = TQChar::DirAN; - break; - case TQChar::DirCS: - if(bidi.status.eor == TQChar::DirAN) { - bidi.eor = bidi.current; break; - } - case TQChar::DirES: - case TQChar::DirET: - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if(bidi.status.eor == TQChar::DirR) { - // neutrals go to R - bidi.eor = bidi.last; - appendRun( bidi ); - dir = TQChar::DirAN; - bidi.status.eor = TQChar::DirAN; - } else if( bidi.status.eor == TQChar::DirL || - (bidi.status.eor == TQChar::DirEN && bidi.status.lastStrong == TQChar::DirL)) { - bidi.eor = bidi.current; bidi.status.eor = dirCurrent; - } else { - // numbers on both sides, neutrals get right to left direction - if(dir != TQChar::DirL) { - appendRun( bidi ); - bidi.eor = bidi.last; - dir = TQChar::DirR; - appendRun( bidi ); - dir = TQChar::DirAN; - bidi.status.eor = TQChar::DirAN; - } else { - bidi.eor = bidi.current; bidi.status.eor = dirCurrent; - } - } - default: - break; - } - break; - case TQChar::DirES: - case TQChar::DirCS: - break; - case TQChar::DirET: - if(bidi.status.last == TQChar::DirEN) { - dirCurrent = TQChar::DirEN; - bidi.eor = bidi.current; bidi.status.eor = dirCurrent; - break; - } - break; - - // boundary neutrals should be ignored - case TQChar::DirBN: - break; - // neutrals - case TQChar::DirB: - // ### what do we do with newline and paragraph seperators that come to here? - break; - case TQChar::DirS: - // ### implement rule L1 - break; - case TQChar::DirWS: - break; - case TQChar::DirON: - break; - default: - break; - } - - //cout << " after: dir=" << // dir << " current=" << dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << context->dir << endl; - - if(bidi.current.atEnd()) break; - - // set status.last as needed. - switch(dirCurrent) - { - case TQChar::DirET: - case TQChar::DirES: - case TQChar::DirCS: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - switch(bidi.status.last) - { - case TQChar::DirL: - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirEN: - case TQChar::DirAN: - bidi.status.last = dirCurrent; - break; - default: - bidi.status.last = TQChar::DirON; - } - break; - case TQChar::DirNSM: - case TQChar::DirBN: - // ignore these - break; - case TQChar::DirEN: - if ( bidi.status.last == TQChar::DirL ) { - break; - } - // fall through - default: - bidi.status.last = dirCurrent; - } -#endif - - if ( atEnd ) break; - bidi.last = bidi.current; - - if ( emptyRun ) { - bidi.sor = bidi.current; - bidi.eor = bidi.current; - emptyRun = false; - } - - // this causes the operator ++ to open and close embedding levels as needed - // for the CSS unicode-bidi property - adjustEmbedding = true; - bidi.current.increment( bidi ); - adjustEmbedding = false; - - if ( bidi.current == end ) { - if ( emptyRun ) - break; - atEnd = true; - } - } - -#if BIDI_DEBUG > 0 - kdDebug(6041) << "reached end of line current=" << current.obj << "/" << current.pos - << ", eor=" << eor.obj << "/" << eor.pos << endl; -#endif - if ( !emptyRun && bidi.sor != bidi.current ) { - bidi.eor = bidi.last; - appendRun( bidi ); - } - - // reorder line according to run structure... - - // first find highest and lowest levels - uchar levelLow = 128; - uchar levelHigh = 0; - BidiRun *r = sFirstBidiRun; - while ( r ) { - if ( r->level > levelHigh ) - levelHigh = r->level; - if ( r->level < levelLow ) - levelLow = r->level; - r = r->nextRun; - } - - // implements reordering of the line (L2 according to Bidi spec): - // L2. From the highest level found in the text to the lowest odd level on each line, - // reverse any contiguous sequence of characters that are at that level or higher. - - // reversing is only done up to the lowest odd level - if( !(levelLow%2) ) levelLow++; - -#if BIDI_DEBUG > 0 - kdDebug(6041) << "lineLow = " << (uint)levelLow << ", lineHigh = " << (uint)levelHigh << endl; - kdDebug(6041) << "logical order is:" << endl; - TQPtrListIterator<BidiRun> it2(runs); - BidiRun *r2; - for ( ; (r2 = it2.current()); ++it2 ) - kdDebug(6041) << " " << r2 << " start=" << r2->start << " stop=" << r2->stop << " level=" << (uint)r2->level << endl; -#endif - - int count = sBidiRunCount - 1; - - // do not reverse for visually ordered web sites - if(!style()->visuallyOrdered()) { - while(levelHigh >= levelLow) { - int i = 0; - BidiRun* currRun = sFirstBidiRun; - while ( i < count ) { - while(i < count && currRun && currRun->level < levelHigh) { - i++; - currRun = currRun->nextRun; - } - int start = i; - while(i <= count && currRun && currRun->level >= levelHigh) { - i++; - currRun = currRun->nextRun; - } - int end = i-1; - reverseRuns(start, end); - } - levelHigh--; - } - } - -#if BIDI_DEBUG > 0 - kdDebug(6041) << "visual order is:" << endl; - for (BidiRun* curr = sFirstRun; curr; curr = curr->nextRun) - kdDebug(6041) << " " << curr << endl; -#endif -} - -void RenderBlock::layoutInlineChildren(bool relayoutChildren, int breakBeforeLine) -{ - BidiState bidi; - - m_overflowHeight = 0; - - invalidateVerticalPositions(); -#ifdef DEBUG_LAYOUT - TQTime qt; - qt.start(); - kdDebug( 6040 ) << renderName() << " layoutInlineChildren( " << this <<" )" << endl; -#endif -#if BIDI_DEBUG > 1 || defined( DEBUG_LINEBREAKS ) - kdDebug(6041) << " ------- bidi start " << this << " -------" << endl; -#endif - - m_height = borderTop() + paddingTop(); - int toAdd = borderBottom() + paddingBottom(); - if (m_layer && scrollsOverflowX() && style()->height().isVariable()) - toAdd += m_layer->horizontalScrollbarHeight(); - - // Clear out our line boxes. - deleteInlineBoxes(); - - // Text truncation only kicks in if your overflow isn't visible and your - // text-overflow-mode isn't clip. - bool hasTextOverflow = style()->textOverflow() && hasOverflowClip(); - - // Walk all the lines and delete our ellipsis line boxes if they exist. - if (hasTextOverflow) - deleteEllipsisLineBoxes(); - - if (firstChild()) { - // layout replaced elements - RenderObject *o = first( this, bidi, false ); - while ( o ) { - if (o->markedForRepaint()) { - o->repaintDuringLayout(); - o->setMarkedForRepaint(false); - } - if (o->isReplaced() || o->isFloating() || o->isPositioned()) { - // clear the placeHolderBox - if (o->isBox()) - static_cast<RenderBox*>(o)->RenderBox::deleteInlineBoxes(); - - //kdDebug(6041) << "layouting replaced or floating child" << endl; - if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent()) - o->setChildNeedsLayout(true, false); - if (o->isPositioned()) - o->containingBlock()->insertPositionedObject(o); - else - o->layoutIfNeeded(); - } - else { - o->deleteInlineBoxes(); - o->setNeedsLayout(false); - } - o = Bidinext( this, o, bidi, false ); - } - - BidiContext *startEmbed; - if( style()->direction() == LTR ) { - startEmbed = new BidiContext( 0, TQChar::DirL ); - bidi.status.eor = TQChar::DirL; - } else { - startEmbed = new BidiContext( 1, TQChar::DirR ); - bidi.status.eor = TQChar::DirR; - } - startEmbed->ref(); - - bidi.status.lastStrong = TQChar::DirON; - bidi.status.last = TQChar::DirON; - - bidi.context = startEmbed; - adjustEmbedding = true; - BidiIterator start(this, first(this, bidi), 0); - adjustEmbedding = false; - BidiIterator end = start; - - m_firstLine = true; - - if (!smidpoints) - smidpoints = new TQMemArray<BidiIterator>; - - sNumMidpoints = 0; - sCurrMidpoint = 0; - sCompactFirstBidiRun = sCompactLastBidiRun = 0; - sCompactBidiRunCount = 0; - - previousLineBrokeAtBR = true; - - int lineCount = 0; - bool pagebreakHint = false; - int oldPos = 0; - BidiIterator oldStart; - BidiState oldBidi; - const bool pagedMode = canvas()->pagedMode(); -// - while( !end.atEnd() ) { - start = end; - lineCount++; - betweenMidpoints = false; - isLineEmpty = true; - pagebreakHint = false; - if (pagedMode) { - oldPos = m_height; - oldStart = start; - oldBidi = bidi; - } - if (lineCount == breakBeforeLine) { - m_height = pageTopAfter(oldPos); - pagebreakHint = true; - } -redo_linebreak: - end = findNextLineBreak(start, bidi); - if( start.atEnd() ) break; - if (!isLineEmpty) { - bidiReorderLine(start, end, bidi); - - // Now that the runs have been ordered, we create the line boxes. - // At the same time we figure out where border/padding/margin should be applied for - // inline flow boxes. - - if (sBidiRunCount) { - InlineFlowBox* lineBox = constructLine(start, end); - if (lineBox) { - if (pagebreakHint) lineBox->setAfterPageBreak(true); - - // Now we position all of our text runs horizontally. - computeHorizontalPositionsForLine(lineBox, bidi); - - // Now position our text runs vertically. - computeVerticalPositionsForLine(lineBox); - - deleteBidiRuns(renderArena()); - - if (lineBox->afterPageBreak() && hasFloats() && !pagebreakHint) { - start = end = oldStart; - bidi = oldBidi; - m_height = pageTopAfter(oldPos); - deleteLastLineBox(renderArena()); - pagebreakHint = true; - goto redo_linebreak; - } - } - } - - if( end == start || (end.obj && end.obj->isBR() && !start.obj->isBR() ) ) { - adjustEmbedding = true; - end.increment(bidi); - adjustEmbedding = false; - } else if (end.obj && end.obj->style()->preserveLF() && end.current() == TQChar('\n')) { - adjustEmbedding = true; - end.increment(bidi); - adjustEmbedding = false; - } - - m_firstLine = false; - newLine(); - } - - sNumMidpoints = 0; - sCurrMidpoint = 0; - sCompactFirstBidiRun = sCompactLastBidiRun = 0; - sCompactBidiRunCount = 0; - } - startEmbed->deref(); - //embed->deref(); - } - - sNumMidpoints = 0; - sCurrMidpoint = 0; - - // If we violate widows page-breaking rules, we set a hint and relayout. - // Note that the widows rule might still be violated afterwards if the lines have become wider - if (canvas()->pagedMode() && containsPageBreak() && breakBeforeLine == 0) - { - int orphans = 0; - int widows = 0; - // find breaking line - InlineRunBox* lineBox = firstLineBox(); - while (lineBox) { - if (lineBox->isInlineFlowBox()) { - InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(lineBox); - if (flowBox->afterPageBreak()) break; - } - orphans++; - lineBox = lineBox->nextLineBox(); - } - InlineFlowBox* pageBreaker = static_cast<InlineFlowBox*>(lineBox); - if (!pageBreaker) goto no_break; - // count widows - while (lineBox && widows < style()->widows()) { - if (lineBox->hasTextChildren()) - widows++; - lineBox = lineBox->nextLineBox(); - } - // Widows rule broken and more orphans left to use - if (widows < style()->widows() && orphans > 0) { - kdDebug( 6040 ) << "Widows: " << widows << endl; - // Check if we have enough orphans after respecting widows count - int newOrphans = orphans - (style()->widows() - widows); - if (newOrphans < style()->orphans()) { - if (parent()->canClear(this,PageBreakHarder)) { - // Relayout to remove incorrect page-break - setNeedsPageClear(true); - setContainsPageBreak(false); - layoutInlineChildren(relayoutChildren, -1); - return; - } - } else { - // Set hint and try again - layoutInlineChildren(relayoutChildren, newOrphans+1); - return; - } - } - } - no_break: - - // in case we have a float on the last line, it might not be positioned up to now. - // This has to be done before adding in the bottom border/padding, or the float will - // include the padding incorrectly. -dwh - positionNewFloats(); - - // Now add in the bottom border/padding. - m_height += toAdd; - - // Always make sure this is at least our height. - m_overflowHeight = kMax(m_height, m_overflowHeight); - - // See if any lines spill out of the block. If so, we need to update our overflow width. - checkLinesForOverflow(); - - // See if we have any lines that spill out of our block. If we do, then we will - // possibly need to truncate text. - if (hasTextOverflow) - checkLinesForTextOverflow(); - -#if BIDI_DEBUG > 1 - kdDebug(6041) << " ------- bidi end " << this << " -------" << endl; -#endif - //kdDebug() << "RenderBlock::layoutInlineChildren time used " << qt.elapsed() << endl; - //kdDebug(6040) << "height = " << m_height <<endl; -} - -static void setStaticPosition( RenderBlock* p, RenderObject *o, bool *needToSetStaticX = 0, bool *needToSetStaticY = 0 ) -{ - // If our original display wasn't an inline type, then we can - // determine our static x position now. - bool nssx, nssy; - bool isInlineType = o->style()->isOriginalDisplayInlineType(); - nssx = o->hasStaticX(); - if (nssx && !isInlineType && o->isBox()) { - static_cast<RenderBox*>(o)->setStaticX(o->parent()->style()->direction() == LTR ? - p->borderLeft()+p->paddingLeft() : - p->borderRight()+p->paddingRight()); - nssx = false; - } - - // If our original display was an INLINE type, then we can - // determine our static y position now. - nssy = o->hasStaticY(); - if (nssy && o->isBox()) { - static_cast<RenderBox*>(o)->setStaticY(p->height()); - nssy = !isInlineType; - } - if (needToSetStaticX) *needToSetStaticX = nssx; - if (needToSetStaticY) *needToSetStaticY = nssy; -} - -BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi) -{ - int width = lineWidth(m_height); - int w = 0; - int tmpW = 0; -#ifdef DEBUG_LINEBREAKS - kdDebug(6041) << "findNextLineBreak: line at " << m_height << " line width " << width << endl; - kdDebug(6041) << "sol: " << start.obj << " " << start.pos << endl; -#endif - - BidiIterator posStart = start; - bool hadPosStart = false; - - // eliminate spaces at beginning of line - // remove leading spaces. Any inline flows we encounter will be empty and should also - // be skipped. - while (!start.atEnd() && (start.obj->isInlineFlow() || (!start.obj->style()->preserveWS() && !start.obj->isBR() && -#ifndef QT_NO_UNICODETABLES - ( (start.current().unicode() == (ushort)0x0020) || // ASCII space - (start.current().unicode() == (ushort)0x0009) || // ASCII tab - (start.current().unicode() == (ushort)0x000A) || // ASCII line feed - (start.current().unicode() == (ushort)0x000C) || // ASCII form feed - (start.current().unicode() == (ushort)0x200B) || // Zero-width space - start.obj->isFloatingOrPositioned() ) -#else - ( start.current() == ' ' || start.current() == '\n' || start.obj->isFloatingOrPositioned() ) -#endif - ))) { - if( start.obj->isFloatingOrPositioned() ) { - RenderObject *o = start.obj; - // add to special objects... - if (o->isFloating()) { - insertFloatingObject(o); - positionNewFloats(); - width = lineWidth(m_height); - } - else if (o->isBox() && o->isPositioned()) { - if (!hadPosStart) { - hadPosStart = true; - posStart = start; - // end - addMidpoint(BidiIterator(0, o, 0)); - } else { - // start/end - addMidpoint(BidiIterator(0, o, 0)); - addMidpoint(BidiIterator(0, o, 0)); - } - setStaticPosition(this, o); - } - } - adjustEmbedding = true; - start.increment(bidi, false /*skipInlines*/); - adjustEmbedding = false; - } - - if (hadPosStart && !start.atEnd()) - addMidpoint(start); - - if ( start.atEnd() ){ - if (hadPosStart) { - start = posStart; - posStart.increment(bidi); - return posStart; - } - return start; - } - - // This variable says we have encountered an object after which initial whitespace should be ignored (e.g. InlineFlows at the begining of a line). - // Either we have nothing to do, if there is no whitespace after the object... or we have to enter the ignoringSpaces state. - // This dilemma will be resolved when we have a peek at the next object. - bool checkShouldIgnoreInitialWhitespace = false; - - // This variable is used only if whitespace isn't set to PRE, and it tells us whether - // or not we are currently ignoring whitespace. - bool ignoringSpaces = false; - BidiIterator ignoreStart; - - // This variable tracks whether the very last character we saw was a space. We use - // this to detect when we encounter a second space so we know we have to terminate - // a run. - bool currentCharacterIsSpace = false; - RenderObject* trailingSpaceObject = 0; - - BidiIterator lBreak = start; - - InlineMinMaxIterator it(start.par, start.obj, start.endOfInline, false /*skipPositioned*/); - InlineMinMaxIterator lastIt = it; - int pos = start.pos; - - bool prevLineBrokeCleanly = previousLineBrokeAtBR; - previousLineBrokeAtBR = false; - - RenderObject* o = it.current; - while( o ) { -#ifdef DEBUG_LINEBREAKS - kdDebug(6041) << "new object "<< o <<" width = " << w <<" tmpw = " << tmpW << endl; -#endif - if(o->isBR()) { - if( w + tmpW <= width ) { - lBreak.obj = o; - lBreak.pos = 0; - lBreak.endOfInline = it.endOfInline; - - // A <br> always breaks a line, so don't let the line be collapsed - // away. Also, the space at the end of a line with a <br> does not - // get collapsed away. It only does this if the previous line broke - // cleanly. Otherwise the <br> has no effect on whether the line is - // empty or not. - if (prevLineBrokeCleanly) - isLineEmpty = false; - trailingSpaceObject = 0; - previousLineBrokeAtBR = true; - - if (!isLineEmpty) { - // only check the clear status for non-empty lines. - EClear clear = o->style()->clear(); - if(clear != CNONE) - m_clearStatus = (EClear) (m_clearStatus | clear); - } - } - goto end; - } - if( o->isFloatingOrPositioned() ) { - // add to special objects... - if(o->isFloating()) { - insertFloatingObject(o); - // check if it fits in the current line. - // If it does, position it now, otherwise, position - // it after moving to next line (in newLine() func) - if (o->width()+o->marginLeft()+o->marginRight()+w+tmpW <= width) { - positionNewFloats(); - width = lineWidth(m_height); - } - } - else if (o->isPositioned()) { - bool needToSetStaticX; - bool needToSetStaticY; - setStaticPosition(this, o, &needToSetStaticX, &needToSetStaticY); - - // If we're ignoring spaces, we have to stop and include this object and - // then start ignoring spaces again. - if (needToSetStaticX || needToSetStaticY) { - trailingSpaceObject = 0; - ignoreStart.obj = o; - ignoreStart.pos = 0; - if (ignoringSpaces) { - addMidpoint(ignoreStart); // Stop ignoring spaces. - addMidpoint(ignoreStart); // Start ignoring again. - } - } - } - } else if (o->isInlineFlow()) { - tmpW += getBorderPaddingMargin(o, it.endOfInline); - if (isLineEmpty) isLineEmpty = !tmpW; - if (o->isWordBreak()) { // #### shouldn't be an InlineFlow! - w += tmpW; - tmpW = 0; - lBreak.obj = o; - lBreak.pos = 0; - lBreak.endOfInline = it.endOfInline; - } else if (!it.endOfInline) { - // this is the beginning of the line (other non-initial inline flows are handled directly when - // incrementing the iterator below). We want to skip initial whitespace as much as possible. - checkShouldIgnoreInitialWhitespace = true; - } - } else if ( o->isReplaced() || o->isGlyph() ) { - EWhiteSpace currWS = o->style()->whiteSpace(); - EWhiteSpace lastWS = lastIt.current->style()->whiteSpace(); - - // WinIE marquees have different whitespace characteristics by default when viewed from - // the outside vs. the inside. Text inside is NOWRAP, and so we altered the marquee's - // style to reflect this, but we now have to get back to the original whitespace value - // for the marquee when checking for line breaking. - if (o->isHTMLMarquee() && o->layer() && o->layer()->marquee()) - currWS = o->layer()->marquee()->whiteSpace(); - if (lastIt.current->isHTMLMarquee() && lastIt.current->layer() && lastIt.current->layer()->marquee()) - lastWS = lastIt.current->layer()->marquee()->whiteSpace(); - - // Break on replaced elements if either has normal white-space. - if (currWS == NORMAL || lastWS == NORMAL) { - w += tmpW; - tmpW = 0; - lBreak.obj = o; - lBreak.pos = 0; - lBreak.endOfInline = false; - } - - tmpW += o->width()+o->marginLeft()+o->marginRight(); - if (ignoringSpaces) { - BidiIterator startMid( 0, o, 0 ); - addMidpoint(startMid); - } - isLineEmpty = false; - ignoringSpaces = false; - currentCharacterIsSpace = false; - trailingSpaceObject = 0; - - if (o->isListMarker() && o->style()->listStylePosition() == OUTSIDE) { - checkShouldIgnoreInitialWhitespace = true; - } - } else if ( o->isText() ) { - RenderText *t = static_cast<RenderText *>(o); - int strlen = t->stringLength(); - int len = strlen - pos; - TQChar *str = t->text(); - - const Font *f = t->htmlFont( m_firstLine ); - // proportional font, needs a bit more work. - int lastSpace = pos; - bool autoWrap = o->style()->autoWrap(); - bool preserveWS = o->style()->preserveWS(); - bool preserveLF = o->style()->preserveLF(); -#ifdef APPLE_CHANGES - int wordSpacing = o->style()->wordSpacing(); -#endif - bool nextIsSoftBreakable = false; - bool checkBreakWord = autoWrap && (o->style()->wordWrap() == WWBREAKWORD); - - while(len) { - bool previousCharacterIsSpace = currentCharacterIsSpace; - bool isSoftBreakable = nextIsSoftBreakable; - nextIsSoftBreakable = false; - const TQChar c = str[pos]; - currentCharacterIsSpace = c == ' '; - checkBreakWord &= !w; // only break words when no other breaking opportunity exists earlier - // on the line (even within the text object we are currently processing) - - if (preserveWS || !currentCharacterIsSpace) - isLineEmpty = false; - - // Check for soft hyphens. Go ahead and ignore them. - if (c.unicode() == SOFT_HYPHEN && pos > 0) { - nextIsSoftBreakable = true; - if (!ignoringSpaces) { - // Ignore soft hyphens - BidiIterator endMid(0, o, pos-1); - addMidpoint(endMid); - - // Add the width up to but not including the hyphen. - tmpW += t->width(lastSpace, pos - lastSpace, f); - - // For wrapping text only, include the hyphen. We need to ensure it will fit - // on the line if it shows when we break. - if (o->style()->autoWrap()) - tmpW += t->width(pos, 1, f); - - BidiIterator startMid(0, o, pos+1); - addMidpoint(startMid); - } - - pos++; - len--; - lastSpace = pos; // Cheesy hack to prevent adding in widths of the run twice. - continue; - } -#ifdef APPLE_CHANGES // KDE applies wordspacing differently - bool applyWordSpacing = false; -#endif - if (ignoringSpaces) { - // We need to stop ignoring spaces, if we encounter a non-space or - // a run that doesn't collapse spaces. - if (!currentCharacterIsSpace || preserveWS) { - // Stop ignoring spaces and begin at this - // new point. - ignoringSpaces = false; - lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - BidiIterator startMid ( 0, o, pos ); - addMidpoint(startMid); - } - else { - // Just keep ignoring these spaces. - pos++; - len--; - continue; - } - } - - const bool isbreakablePosition = (preserveLF && c == '\n') || (autoWrap && - (isBreakable( str, pos, strlen ) || isSoftBreakable)); - if ( isbreakablePosition || checkBreakWord ) { - - tmpW += t->width(lastSpace, pos - lastSpace, f); -#ifdef APPLE_CHANGES - applyWordSpacing = (wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace && - !t->containsOnlyWhitespace(pos+1, strlen-(pos+1))); -#endif -#ifdef DEBUG_LINEBREAKS - kdDebug(6041) << "found space at " << pos << " in string '" << TQString( str, strlen ).latin1() << "' adding " << tmpW << " new width = " << w << endl; -#endif - if ( autoWrap && w + tmpW > width && w == 0 ) { - int fb = nearestFloatBottom(m_height); - int newLineWidth = lineWidth(fb); - // See if |tmpW| will fit on the new line. As long as it does not, - // keep adjusting our float bottom until we find some room. - int lastFloatBottom = m_height; - while (lastFloatBottom < fb && tmpW > newLineWidth) { - lastFloatBottom = fb; - fb = nearestFloatBottom(fb); - newLineWidth = lineWidth(fb); - } - - if(!w && m_height < fb && width < newLineWidth) { - m_height = fb; - width = newLineWidth; -#ifdef DEBUG_LINEBREAKS - kdDebug() << "RenderBlock::findNextLineBreak new position at " << m_height << " newWidth " << width << endl; -#endif - } - } - - if (autoWrap) { - if (w+tmpW > width) { - if (checkBreakWord && pos) { - lBreak.obj = o; - lBreak.pos = pos-1; - lBreak.endOfInline = false; - } - goto end; - } else if ( (pos > 1 && str[pos-1].unicode() == SOFT_HYPHEN) ) - // Subtract the width of the soft hyphen out since we fit on a line. - tmpW -= t->width(pos-1, 1, f); - } - - if( preserveLF && *(str+pos) == '\n' ) { - lBreak.obj = o; - lBreak.pos = pos; - lBreak.endOfInline = false; - -#ifdef DEBUG_LINEBREAKS - kdDebug(6041) << "forced break sol: " << start.obj << " " << start.pos << " end: " << lBreak.obj << " " << lBreak.pos << " width=" << w << endl; -#endif - return lBreak; - } - - if ( autoWrap && isbreakablePosition ) { - w += tmpW; - tmpW = 0; - lBreak.obj = o; - lBreak.pos = pos; - lBreak.endOfInline = false; - } - - lastSpace = pos; -#ifdef APPLE_CHANGES - if (applyWordSpacing) - w += wordSpacing; -#endif - } - - if (!ignoringSpaces && !preserveWS) { - // If we encounter a second space, we need to go ahead and break up this run - // and enter a mode where we start collapsing spaces. - if (currentCharacterIsSpace && previousCharacterIsSpace) { - ignoringSpaces = true; - - // We just entered a mode where we are ignoring - // spaces. Create a midpoint to terminate the run - // before the second space. - addMidpoint(ignoreStart); - lastSpace = pos; - } - } - - if (currentCharacterIsSpace && !previousCharacterIsSpace) { - ignoreStart.obj = o; - ignoreStart.pos = pos; - } - - if (!preserveWS && currentCharacterIsSpace && !ignoringSpaces) - trailingSpaceObject = o; - else if (preserveWS || !currentCharacterIsSpace) - trailingSpaceObject = 0; - - pos++; - len--; - } - - if (!ignoringSpaces) { - // We didn't find any space that would be beyond the line |width|. - // Lets add to |tmpW| the remaining width since the last space we found. - // Before we test this new |tmpW| however, we will have to look ahead to check - // if the next object/position can serve as a line breaking opportunity. - tmpW += t->width(lastSpace, pos - lastSpace, f); - if (checkBreakWord && !w && pos && tmpW > width) { - // Avoid doing the costly lookahead for break-word, - // since we know we are allowed to break. - lBreak.obj = o; - lBreak.pos = pos-1; - lBreak.endOfInline = false; - goto end; - } - } - } else - KHTMLAssert( false ); - - InlineMinMaxIterator savedIt = lastIt; - lastIt = it; - o = it.next(); - - // advance the iterator to the next non-inline-flow - while (o && o->isInlineFlow() && !o->isWordBreak()) { - tmpW += getBorderPaddingMargin(o, it.endOfInline); - if (isLineEmpty) isLineEmpty = !tmpW; - o = it.next(); - } - - if (checkShouldIgnoreInitialWhitespace) { - // Check if we should switch to ignoringSpaces state - if (!style()->preserveWS() && it.current && it.current->isText()) { - const RenderText* rt = static_cast<RenderText*>(it.current); - if (rt->stringLength() > 0 && (rt->text()[0].category() == TQChar::Separator_Space || rt->text()[0] == '\n')) { - currentCharacterIsSpace = true; - ignoringSpaces = true; - BidiIterator endMid( 0, lastIt.current, 0 ); - addMidpoint(endMid); - } - } - checkShouldIgnoreInitialWhitespace = false; - } - - bool autoWrap = lastIt.current->style()->autoWrap(); - bool checkForBreak = autoWrap; - if (w && w + tmpW > width && lBreak.obj && !lastIt.current->style()->preserveLF() && !autoWrap) - checkForBreak = true; - else if (it.current && lastIt.current->isText() && it.current->isText() && !it.current->isBR()) { - if (autoWrap || it.current->style()->autoWrap()) { - if (currentCharacterIsSpace) - checkForBreak = true; - else { - checkForBreak = false; - RenderText* nextText = static_cast<RenderText*>(it.current); - if (nextText->stringLength() != 0) { - TQChar c = nextText->text()[0]; - if (c == ' ' || c == '\t' || (c == '\n' && !it.current->style()->preserveLF())) { - // If the next item on the line is text, and if we did not end with - // a space, then the next text run continues our word (and so it needs to - // keep adding to |tmpW|. Just update and continue. - checkForBreak = true; - } - } - - bool canPlaceOnLine = (w + tmpW <= width) || !autoWrap; - if (canPlaceOnLine && checkForBreak) { - w += tmpW; - tmpW = 0; - lBreak.obj = it.current; - lBreak.pos = 0; - lBreak.endOfInline = it.endOfInline; - } - } - } - } - - if (checkForBreak && (w + tmpW > width)) { - //kdDebug() << " too wide w=" << w << " tmpW = " << tmpW << " width = " << width << endl; - //kdDebug() << "start=" << start.obj << " current=" << o << endl; - // if we have floats, try to get below them. - if (currentCharacterIsSpace && !ignoringSpaces && !lastIt.current->style()->preserveWS()) - trailingSpaceObject = 0; - - int fb = nearestFloatBottom(m_height); - int newLineWidth = lineWidth(fb); - // See if |tmpW| will fit on the new line. As long as it does not, - // keep adjusting our float bottom until we find some room. - int lastFloatBottom = m_height; - while (lastFloatBottom < fb && tmpW > newLineWidth) { - lastFloatBottom = fb; - fb = nearestFloatBottom(fb); - newLineWidth = lineWidth(fb); - } - if( !w && m_height < fb && width < newLineWidth ) { - m_height = fb; - width = newLineWidth; -#ifdef DEBUG_LINEBREAKS - kdDebug() << "RenderBlock::findNextLineBreak new position at " << m_height << " newWidth " << width << endl; -#endif - } - - // |width| may have been adjusted because we got shoved down past a float (thus - // giving us more room), so we need to retest, and only jump to - // the end label if we still don't fit on the line. -dwh - if (w + tmpW > width) { - it = lastIt; - lastIt = savedIt; - o = it.current; - goto end; - } - } - - if (!lastIt.current->isFloatingOrPositioned() && lastIt.current->isReplaced() && lastIt.current->style()->autoWrap()) { - // Go ahead and add in tmpW. - w += tmpW; - tmpW = 0; - lBreak.obj = o; - lBreak.pos = 0; - lBreak.endOfInline = it.endOfInline; - } - - // Clear out our character space bool, since inline <pre>s don't collapse whitespace - // with adjacent inline normal/nowrap spans. - if (lastIt.current->style()->preserveWS()) - currentCharacterIsSpace = false; - - pos = 0; - } - -#ifdef DEBUG_LINEBREAKS - kdDebug( 6041 ) << "end of par, width = " << width << " linewidth = " << w + tmpW << endl; -#endif - if( w + tmpW <= width || (lastIt.current && !lastIt.current->style()->autoWrap())) { - lBreak.obj = 0; - lBreak.pos = 0; - lBreak.endOfInline = false; - } - - end: - - if( lBreak == start && !lBreak.obj->isBR() ) { - // we just add as much as possible - if ( style()->whiteSpace() == PRE ) { - // FIXME: Don't really understand this case. - if(pos != 0) { - lBreak.obj = o; - lBreak.pos = pos - 1; - lBreak.endOfInline = it.endOfInline; - } else { - lBreak.obj = lastIt.current; - lBreak.pos = lastIt.current->isText() ? lastIt.current->length() : 0; - lBreak.endOfInline = lastIt.endOfInline; - } - } else if( lBreak.obj ) { - if( lastIt.current != o ) { - // better to break between object boundaries than in the middle of a word - lBreak.obj = o; - lBreak.pos = 0; - lBreak.endOfInline = it.endOfInline; - } else { - // Don't ever break in the middle of a word if we can help it. - // There's no room at all. We just have to be on this line, - // even though we'll spill out. - lBreak.obj = o; - lBreak.pos = pos; - lBreak.endOfInline = it.endOfInline; - } - } - } - - if (hadPosStart) - start = posStart; - - // make sure we consume at least one char/object. - // and avoid returning an InlineFlow - // (FIXME: turn those wordbreaks into empty text objects - they shouldn't be inline flows!) - if( lBreak == start || (lBreak.obj && lBreak.obj->isInlineFlow() && !lBreak.obj->isWordBreak())) { - lBreak.increment(bidi); - } - -#ifdef DEBUG_LINEBREAKS - kdDebug(6041) << "regular break sol: " << start.obj << " " << start.pos << " end: " << lBreak.obj << " " << lBreak.pos << " width=" << w << endl; -#endif - - // Sanity check our midpoints. - checkMidpoints(lBreak, bidi); - - if (trailingSpaceObject) { - // This object is either going to be part of the last midpoint, or it is going - // to be the actual endpoint. In both cases we just decrease our pos by 1 level to - // exclude the space, allowing it to - in effect - collapse into the newline. - if (sNumMidpoints%2==1) { - BidiIterator* midpoints = smidpoints->data(); - midpoints[sNumMidpoints-1].pos--; - } - //else if (lBreak.pos > 0) - // lBreak.pos--; - else if (lBreak.obj == 0 && trailingSpaceObject->isText()) { - // Add a new end midpoint that stops right at the very end. - RenderText* text = static_cast<RenderText *>(trailingSpaceObject); - unsigned pos = text->length() >=2 ? text->length() - 2 : UINT_MAX; - BidiIterator endMid ( 0, trailingSpaceObject, pos ); - addMidpoint(endMid); - } - } - - // We might have made lBreak an iterator that points past the end - // of the object. Do this adjustment to make it point to the start - // of the next object instead to avoid confusing the rest of the - // code. - if (lBreak.pos > 0) { - lBreak.pos--; - lBreak.increment(bidi); - } - - if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) { - // For soft hyphens on line breaks, we have to chop out the midpoints that made us - // ignore the hyphen so that it will render at the end of the line. - TQChar c = static_cast<RenderText*>(lBreak.obj)->text()[lBreak.pos-1]; - if (c.unicode() == SOFT_HYPHEN) - chopMidpointsAt(lBreak.obj, lBreak.pos-2); - } - - return lBreak; -} - -void RenderBlock::checkLinesForOverflow() -{ - for (RootInlineBox* curr = static_cast<khtml::RootInlineBox*>(firstLineBox()); curr; curr = static_cast<khtml::RootInlineBox*>(curr->nextLineBox())) { -// m_overflowLeft = min(curr->leftOverflow(), m_overflowLeft); - m_overflowTop = kMin(curr->topOverflow(), m_overflowTop); -// m_overflowWidth = max(curr->rightOverflow(), m_overflowWidth); - m_overflowHeight = kMax(curr->bottomOverflow(), m_overflowHeight); - } -} - -void RenderBlock::deleteEllipsisLineBoxes() -{ - for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) - curr->clearTruncation(); -} - -void RenderBlock::checkLinesForTextOverflow() -{ - // Determine the width of the ellipsis using the current font. - TQChar ellipsis = 0x2026; // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if 0x2026 not renderable - static TQString ellipsisStr(ellipsis); - const Font& firstLineFont = style(true)->htmlFont(); - const Font& font = style()->htmlFont(); - int firstLineEllipsisWidth = firstLineFont.width(&ellipsis, 1, 0); - int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(&ellipsis, 1, 0); - - // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see - // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and - // check the left edge of the line box to see if it is less - // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()" - bool ltr = style()->direction() == LTR; - for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { - int blockEdge = ltr ? rightOffset(curr->yPos()) : leftOffset(curr->yPos()); - int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos(); - if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) { - // This line spills out of our box in the appropriate direction. Now we need to see if the line - // can be truncated. In order for truncation to be possible, the line must have sufficient space to - // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis - // space. - int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth; - if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) - curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width); - } - } -} - -// For --enable-final -#undef BIDI_DEBUG -#undef DEBUG_LINEBREAKS -#undef DEBUG_LAYOUT - -} diff --git a/khtml/rendering/bidi.h b/khtml/rendering/bidi.h deleted file mode 100644 index c8776ce19..000000000 --- a/khtml/rendering/bidi.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -#ifndef BIDI_H -#define BIDI_H - -#include <tqstring.h> -#include "rendering/render_object.h" - -namespace khtml { - class RenderArena; - class RenderBlock; - class RenderObject; - class InlineBox; - - class BidiContext { - public: - BidiContext(unsigned char level, TQChar::Direction embedding, BidiContext *parent = 0, bool override = false); - ~BidiContext(); - - void ref() const; - void deref() const; - - unsigned char level; - bool override : 1; - TQChar::Direction dir : 5; - TQChar::Direction basicDir : 5; - - BidiContext *parent; - - - // refcounting.... - mutable int count; - }; - - struct BidiRun { - BidiRun(int _start, int _stop, RenderObject *_obj, BidiContext *context, TQChar::Direction dir) - : start( _start ), stop( _stop ), obj( _obj ), box(0), nextRun(0) - { - if(dir == TQChar::DirON) dir = context->dir; - - level = context->level; - - // add level of run (cases I1 & I2) - if( level % 2 ) { - if(dir == TQChar::DirL || dir == TQChar::DirAN || dir == TQChar::DirEN) - level++; - } else { - if( dir == TQChar::DirR ) - level++; - else if( dir == TQChar::DirAN || dir == TQChar::DirEN) - level += 2; - } - } - - void detach(RenderArena* renderArena); - - // Overloaded new operator. - void* operator new(size_t sz, RenderArena* renderArena) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* ptr, size_t sz); - -private: - // The normal operator new is disallowed. - void* operator new(size_t sz) throw(); - -public: - int start; - int stop; - - RenderObject *obj; - InlineBox* box; - - // explicit + implicit levels here - uchar level; - - bool compact : 1; - - BidiRun* nextRun; - }; - - struct BidiIterator; - struct BidiState; - - struct InlineMinMaxIterator - { - /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to - inline min/max width calculations. Note the following about the way it walks: - (1) Positioned content is skipped (since it does not contribute to min/max width of a block) - (2) We do not drill into the children of floats or replaced elements, since you can't break - in the middle of such an element. - (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have - distinct borders/margin/padding that contribute to the min/max width. - */ - RenderObject* parent; - RenderObject* current; - bool endOfInline; - bool skipPositioned; - InlineMinMaxIterator(RenderObject* p, RenderObject* o, bool eOI=false, bool skipPos=true) - :parent(p), current(o), endOfInline(eOI), skipPositioned(skipPos) {} - inline RenderObject* next(); - }; - - inline RenderObject* InlineMinMaxIterator::next() - { - RenderObject* result = 0; - bool oldEndOfInline = endOfInline; - endOfInline = false; - while (current != 0 || (current == parent)) - { - //kDebug( 6040 ) << "current = " << current; - if (!oldEndOfInline && - (current == parent || - (!current->isFloating() && !current->isReplaced() && !current->isPositioned()))) - result = current->firstChild(); - if (!result) { - // We hit the end of our inline. (It was empty, e.g., <span></span>.) - if (!oldEndOfInline && current->isInlineFlow()) { - result = current; - endOfInline = true; - break; - } - while (current && current != parent) { - result = current->nextSibling(); - if (result) break; - current = current->parent(); - if (current && current != parent && current->isInlineFlow()) { - result = current; - endOfInline = true; - break; - } - } - } - - if (!result) break; - - if ((!skipPositioned || !result->isPositioned()) && (result->isText() || result->isBR() || - result->isFloatingOrPositioned() || result->isReplaced() || result->isGlyph() || result->isInlineFlow())) - break; - - current = result; - result = 0; - } - - // Update our position. - current = result; - return current; - } - -} - -#endif diff --git a/khtml/rendering/break_lines.cpp b/khtml/rendering/break_lines.cpp deleted file mode 100644 index a0d314cee..000000000 --- a/khtml/rendering/break_lines.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include <break_lines.h> -#include <klibloader.h> -#include "tqcstring.h" -#include <tqtextcodec.h> -#include <tqcleanuphandler.h> -#include <config.h> - - -/* If HAVE_LIBTHAI is defined, libkhtml will link against - * libthai since compile time. Otherwise it will try to - * dlopen at run-time - * - * Ott Pattara Nov 14, 2004 - */ - -#ifndef HAVE_LIBTHAI -typedef int (*th_brk_def)(const unsigned char*, int[], int); -static th_brk_def th_brk; -#else -#include <thai/thailib.h> -#include <thai/thbrk.h> -#endif - -namespace khtml { - struct ThaiCache - { - ThaiCache() { - string = 0; - allocated = 0x400; - wbrpos = (int *) malloc(allocated*sizeof(int)); - numwbrpos = 0; - numisbreakable = 0x400; - isbreakable = (int *) malloc(numisbreakable*sizeof(int)); - library = 0; - } - ~ThaiCache() { - free(wbrpos); - free(isbreakable); - if (library) library->unload(); - } - const TQChar *string; - int *wbrpos; - int *isbreakable; - int allocated; - int numwbrpos,numisbreakable; - KLibrary *library; - }; - static ThaiCache *cache = 0; - - void cleanup_thaibreaks() - { - delete cache; - cache = 0; -#ifndef HAVE_LIBTHAI - th_brk = 0; -#endif - } - - bool isBreakableThai( const TQChar *string, const int pos, const int len) - { - static TQTextCodec *thaiCodec = TQTextCodec::codecForMib(2259); - //printf("Entering isBreakableThai with pos = %d\n", pos); - -#ifndef HAVE_LIBTHAI - - KLibrary *lib = 0; - - /* load libthai dynamically */ - if (( !th_brk ) && thaiCodec ) { - printf("Try to load libthai dynamically...\n"); - KLibLoader *loader = KLibLoader::self(); - lib = loader->library("libthai"); - if (lib && lib->hasSymbol("th_brk")) { - th_brk = (th_brk_def) lib->symbol("th_brk"); - } else { - // indication that loading failed and we shouldn't try to load again - printf("Error, can't load libthai...\n"); - thaiCodec = 0; - if (lib) - lib->unload(); - } - } - - if (!th_brk ) { - return true; - } -#endif - - if (!cache ) { - cache = new ThaiCache; -#ifndef HAVE_LIBTHAI - cache->library = lib; -#endif - } - - // build up string of thai chars - if ( string != cache->string ) { - //fprintf(stderr,"new string found (not in cache), calling libthai\n"); - TQCString cstr = thaiCodec->fromUnicode( TQConstString(string,len).string()); - //printf("About to call libthai::th_brk with str: %s",cstr.data()); - - cache->numwbrpos = th_brk((const unsigned char*) cstr.data(), cache->wbrpos, cache->allocated); - //fprintf(stderr,"libthai returns with value %d\n",cache->numwbrpos); - if (cache->numwbrpos > cache->allocated) { - cache->allocated = cache->numwbrpos; - cache->wbrpos = (int *)realloc(cache->wbrpos, cache->allocated*sizeof(int)); - cache->numwbrpos = th_brk((const unsigned char*) cstr.data(), cache->wbrpos, cache->allocated); - } - if ( len > cache->numisbreakable ) { - cache->numisbreakable=len; - cache->isbreakable = (int *)realloc(cache->isbreakable, cache->numisbreakable*sizeof(int)); - } - for (int i = 0 ; i < len ; ++i) { - cache->isbreakable[i] = 0; - } - if ( cache->numwbrpos > 0 ) { - for (int i = cache->numwbrpos-1; i >= 0; --i) { - cache->isbreakable[cache->wbrpos[i]] = 1; - } - } - cache->string = string; - } - //printf("Returning %d\n", cache->isbreakable[pos]); - return cache->isbreakable[pos]; - } -} diff --git a/khtml/rendering/break_lines.h b/khtml/rendering/break_lines.h deleted file mode 100644 index 5176e5fb0..000000000 --- a/khtml/rendering/break_lines.h +++ /dev/null @@ -1,163 +0,0 @@ -#ifndef BREAK_LINES_H -#define BREAK_LINES_H - -#include <tqstring.h> - -namespace khtml { - - /* - array of unicode codes where breaking shouldn't occur. - (in sorted order because of using with binary search) - these are currently for Japanese, though simply adding - Korean, Chinese ones should work as well - */ - /* - dontbreakbefore[] contains characters not covered by TQChar::Punctuation_Close that shouldn't be broken before. - chars included in TQChar::Punctuation_Close are listed below.(look at UAX #14) - - 3001 ideographic comma - - 3002 ideographic full stop - - FE50 small comma - - FF52 small full stop - - FF0C fullwidth comma - - FF0E fullwidth full stop - - FF61 halfwidth ideographic full stop - - FF64 halfwidth ideographic comma - these character is commented out. - */ - const ushort dontbreakbefore[] = { - //0x3001, //ideographic comma - //0x3002, //ideographic full stop - 0x3005, //ideographic iteration mark - 0x3009, //right angle bracket - 0x300b, //right double angle bracket - 0x300d, //right corner bracket - 0x300f, //right white corner bracket - 0x3011, //right black lenticular bracket - 0x3015, //right tortoise shell bracket - 0x3041, //small a hiragana - 0x3043, //small i hiragana - 0x3045, //small u hiragana - 0x3047, //small e hiragana - 0x3049, //small o hiragana - 0x3063, //small tsu hiragana - 0x3083, //small ya hiragana - 0x3085, //small yu hiragana - 0x3087, //small yo hiragana - 0x308E, //small wa hiragana - 0x309B, //jap voiced sound mark - 0x309C, //jap semi-voiced sound mark - 0x309D, //jap iteration mark hiragana - 0x309E, //jap voiced iteration mark hiragana - 0x30A1, //small a katakana - 0x30A3, //small i katakana - 0x30A5, //small u katakana - 0x30A7, //small e katakana - 0x30A9, //small o katakana - 0x30C3, //small tsu katakana - 0x30E3, //small ya katakana - 0x30E5, //small yu katakana - 0x30E7, //small yo katakana - 0x30EE, //small wa katakana - 0x30F5, //small ka katakana - 0x30F6, //small ke katakana - 0x30FC, //jap prolonged sound mark - 0x30FD, //jap iteration mark katakana - 0x30FE, //jap voiced iteration mark katakana - //0xFE50, //small comma - //0xFF52, //small full stop - 0xFF01, //fullwidth exclamation mark - 0xFF09, //fullwidth right parenthesis - //0xFF0C, //fullwidth comma - 0xFF0D, //fullwidth hypen-minus - //0xFF0E, //fullwidth full stop - 0xFF1F, //fullwidth question mark - 0xFF3D, //fullwidth right square bracket - 0xFF5D, //fullwidth right curly bracket - //0xFF61, //halfwidth ideographic full stop - 0xFF63, //halfwidth right corner bracket - //0xFF64, //halfwidth ideographic comma - 0xFF67, //halfwidth katakana letter small a - 0xFF68, //halfwidth katakana letter small i - 0xFF69, //halfwidth katakana letter small u - 0xFF6a, //halfwidth katakana letter small e - 0xFF6b, //halfwidth katakana letter small o - 0xFF6c, //halfwidth katakana letter small ya - 0xFF6d, //halfwidth katakana letter small yu - 0xFF6e, //halfwidth katakana letter small yo - 0xFF6f, //halfwidth katakana letter small tu - 0xFF70 //halfwidth katakana-hiragana prolonged sound mark - }; - - // characters that aren't covered by TQChar::Punctuation_Open - const ushort dontbreakafter[] = { - 0x3012, //postal mark - 0xFF03, //full width pound mark - 0xFF04, //full width dollar sign - 0xFF20, //full width @ - 0xFFE1, //full width british pound sign - 0xFFE5 //full width yen sign - }; - - inline bool break_bsearch( const ushort* arr, const ushort val ) { - int left = 0; - int right = (sizeof(arr) / sizeof(ushort)) - 1; - - while (1) { - if (left == right) - return val != arr[left]; - - int i = (left + right) >> 1; - if ( val == arr[i] ) - return false; - if ( val < arr[i] ) - right = i; - else - left = i + 1; - } - } - - bool isBreakableThai( const TQChar *string, const int pos, const int len); - void cleanup_thaibreaks(); - - inline bool isBreakable( const TQChar *str, const int pos, int len ) - { - const TQChar *c = str+pos; - unsigned short ch = c->unicode(); - if ( ch > 0xff ) { - // not latin1, need to do more sophisticated checks for asian fonts - unsigned char row = c->row(); - if ( row == 0x0e ) { - // 0e00 - 0e7f == Thai - if ( c->cell() < 0x80 ) { - // consult libthai - return isBreakableThai(str, pos, len); - } else - return false; - } - if ( row > 0x2d && row < 0xfb || row == 0x11 ) { - /* asian line breaking. */ - if ( pos == 0 ) - return false; // never break before first character - - // check for simple punctuation cases - TQChar::Category cat = c->category(); - if ( cat == TQChar::Punctuation_Close || - cat == TQChar::Punctuation_Other || - (str+(pos-1))->category() == TQChar::Punctuation_Open ) - return false; - - // do binary search in dontbreak[] - return break_bsearch(dontbreakbefore, c->unicode()) && - break_bsearch(dontbreakafter, (str+(pos-1))->unicode()); - } else // no asian font - return c->isSpace(); - } else { - if ( ch == ' ' || ch == '\n' ) - return true; - } - return false; - } - -} - -#endif diff --git a/khtml/rendering/counter_tree.cpp b/khtml/rendering/counter_tree.cpp deleted file mode 100644 index 5b178d96e..000000000 --- a/khtml/rendering/counter_tree.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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 "rendering/counter_tree.h" -#include "rendering/render_object.h" - -namespace khtml { - -CounterNode::CounterNode(RenderObject *o) - : m_hasCounters(false), m_isVisual(false), - m_value(0), m_count(0), m_parent(0), m_previous(0), m_next(0), - m_renderer(o) {} - -CounterNode::~CounterNode() -{ - if (m_parent) m_parent->removeChild(this); -} - -void CounterNode::insertAfter ( CounterNode *, CounterNode *) -{ - Q_ASSERT( false); -} - -void CounterNode::removeChild ( CounterNode *) -{ - Q_ASSERT( false); -} - -void CounterNode::remove () -{ - if (m_parent) m_parent->removeChild(this); - else { - Q_ASSERT(isReset()); - Q_ASSERT(!firstChild()); - Q_ASSERT(!lastChild()); - } -} - -void CounterNode::setHasCounters () -{ - m_hasCounters = true; - if (parent()) - parent()->setHasCounters(); -} - -void CounterNode::recount (bool first) -{ - int old_count = m_count; - if (m_previous) - m_count = m_previous->count() + m_value; - else { - assert(m_parent->firstChild() == this); - m_count = m_parent->value() + m_value; - } - if (old_count != m_count && !first) - setSelfDirty(); - if (old_count != m_count || first) { - if (m_parent) m_parent->updateTotal(m_count); - if (m_next) m_next->recount(); - } -} - -void CounterNode::setSelfDirty () -{ - if (m_renderer && m_isVisual) - m_renderer->setNeedsLayoutAndMinMaxRecalc(); -} - -void CounterNode::setParentDirty () -{ - if (m_renderer && m_isVisual && m_hasCounters) - m_renderer->setNeedsLayoutAndMinMaxRecalc(); -} - -CounterReset::CounterReset(RenderObject *o) : CounterNode(o), m_total(0), m_first(0), m_last(0) {} -CounterReset::~CounterReset() {} - -void CounterReset::insertAfter ( CounterNode *newChild, CounterNode *refChild ) -{ - Q_ASSERT( newChild ); - Q_ASSERT( !refChild || refChild->parent() == this ); - - newChild->m_parent = this; - newChild->m_previous = refChild; - - if (refChild) { - newChild->m_next = refChild->m_next; - refChild->m_next = newChild; - } else { - newChild->m_next = m_first; - m_first = newChild; - } - - if (newChild->m_next) { - assert(newChild->m_next->m_previous == refChild); - newChild->m_next->m_previous = newChild; - } - else { - assert (m_last == refChild); - m_last = newChild; - } - - newChild->recount(true); -} - -void CounterReset::removeChild ( CounterNode *oldChild ) -{ - Q_ASSERT( oldChild ); - - CounterNode* next = oldChild->m_next; - CounterNode* prev = oldChild->m_previous; - - if (oldChild->firstChild()) { - CounterNode* first = oldChild->firstChild(); - CounterNode* last = oldChild->lastChild(); - if (prev) { - prev->m_next = first; - first->m_previous = prev; - } - else { - assert ( m_first == oldChild ); - m_first = first; - } - - if (next) { - next->m_previous = last; - last->m_next = next; - } - else { - assert ( m_last == oldChild ); - m_last = last; - } - - next = first; - while (next) { - next->m_parent = this; - if (next == last) break; - next = next->m_next; - } - - first->recount(true); - } - else { - if (prev) prev->m_next = next; - else { - assert ( m_first == oldChild ); - m_first = next; - } - if (next) next->m_previous = prev; - else { - assert ( m_last == oldChild ); - m_last = prev; - } - if (next) - next->recount(); - } - - - oldChild->m_next = 0; - oldChild->m_previous = 0; - oldChild->m_parent = 0; -} - -void CounterReset::recount (bool first) -{ - int old_count = m_count; - if (m_previous) - m_count = m_previous->count(); - else if (m_parent) - m_count = m_parent->value(); - else - m_count = 0; - - updateTotal(m_value); - if (!first) setSelfDirty(); - if (first || m_count != old_count) { - if (m_next) m_next->recount(); - } -} - -void CounterReset::setSelfDirty () -{ - setParentDirty(); -} - -void CounterReset::setParentDirty () -{ - if (hasCounters()) { - if (m_renderer && m_isVisual) m_renderer->setNeedsLayoutAndMinMaxRecalc(); - CounterNode* n = firstChild(); - for(; n; n = n->nextSibling()) - { - n->setParentDirty(); - } - } -} - -void CounterReset::updateTotal (int value) -{ - if (value > m_total) m_total = value; -} - -} // namespace diff --git a/khtml/rendering/counter_tree.h b/khtml/rendering/counter_tree.h deleted file mode 100644 index 55b924b80..000000000 --- a/khtml/rendering/counter_tree.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ -#ifndef _Counter_Tree_h_ -#define _Counter_Tree_h_ - -#include "misc/shared.h" -#include "rendering/render_object.h" - -namespace khtml { - -class CounterReset; - -// This file implements a counter-tree that is used for finding all parents in counters() lookup, -// and for propagating count-changes when nodes are added or removed. -// Please note that only counter-reset and root can be parents here, and that render-tree parents -// are just counter-tree siblings - -// Implementation of counter-increment and counter-content -class CounterNode -{ -public: - CounterNode(RenderObject *o); - virtual ~CounterNode(); - - CounterReset* parent() const { return m_parent; } - CounterNode* previousSibling() const { return m_previous; } - CounterNode* nextSibling() const { return m_next; } - virtual CounterNode* firstChild() const { return 0; } ; - virtual CounterNode* lastChild() const { return 0; }; - virtual void insertAfter ( CounterNode *newChild, CounterNode *refChild ); - virtual void removeChild ( CounterNode *oldChild ); - // Convenient self-refering version of the above - void remove(); - - int value() const { return m_value; }; - void setValue(short v) { m_value = v; }; - int count() const { return m_count; }; - - virtual bool isReset() { return false; }; - virtual void recount( bool first = false ); - virtual void setSelfDirty(); - virtual void setParentDirty(); - - bool hasCounters() const { return m_hasCounters; }; - bool isVisual() const { return m_isVisual; }; - void setHasCounters(); - void setIsVisual() { m_isVisual = true; }; - bool isRoot() { return m_renderer && m_renderer->isRoot(); }; - - void setRenderer(RenderObject *o) { m_renderer = o; }; - RenderObject* renderer() const { return m_renderer; }; - - friend class CounterReset; -protected: - bool m_hasCounters : 1; - bool m_isVisual : 1; - short m_value; - short m_count; - CounterReset *m_parent; - CounterNode *m_previous; - CounterNode *m_next; - RenderObject *m_renderer; -}; - -// Implementation of counter-reset and root -class CounterReset : public CounterNode -{ -public: - CounterReset(RenderObject *o); - virtual ~CounterReset(); - - virtual CounterNode *firstChild() const { return m_first; }; - virtual CounterNode *lastChild() const { return m_last; }; - virtual void insertAfter ( CounterNode *newChild, CounterNode *refChild ); - virtual void removeChild ( CounterNode *oldChild ); - - virtual bool isReset() { return true; }; - virtual void recount( bool first = false ); - virtual void setSelfDirty(); - virtual void setParentDirty(); - - void updateTotal(int value); - // The highest value among children - int total() const { return m_total; }; - -protected: - int m_total; - CounterNode *m_first; - CounterNode *m_last; -}; - -} // namespace - -#endif - diff --git a/khtml/rendering/enumerate.cpp b/khtml/rendering/enumerate.cpp deleted file mode 100644 index 9cfe149ad..000000000 --- a/khtml/rendering/enumerate.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/** - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * (C) Hebrew algorithm by herouth@netvision.net.il - * and schlpbch@iam.unibe.ch - * - * 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 "rendering/enumerate.h" - -#include <tqstring.h> -#include <tqvaluelist.h> - -namespace khtml { - -namespace Enumerate { - -TQString toRoman( int number, bool upper ) -{ - if (number < 1 || number > 3999) return TQString::number(number); - TQString roman; - static const TQChar ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' }; - static const TQChar udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' }; - const TQChar *digits = upper ? udigits : ldigits; - int i, d = 0; - - do - { - int num = number % 10; - - if ( num % 5 < 4 ) - for ( i = num % 5; i > 0; i-- ) - roman.prepend( digits[ d ] ); - - if ( num >= 4 && num <= 8) - roman.prepend( digits[ d+1 ] ); - - if ( num == 9 ) - roman.prepend( digits[ d+2 ] ); - - if ( num % 5 == 4 ) - roman.prepend( digits[ d ] ); - - number /= 10; - d += 2; - } - while ( number ); - - return roman; -} - -TQString toGeorgian( int number ) -{ - TQString georgian; - const TQChar tenthousand = 0x10ef; - static const TQChar thousands[9] = {0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, - 0x10ed, 0x10ee, 0x10f4, 0x10f5 }; - static const TQChar hundreds[9] = {0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10f3, - 0x10e4, 0x10e5, 0x10e6, 0x10e7 }; - static const TQChar tens[9] = {0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, - 0x10f2, 0x10dd, 0x10de, 0x10df }; - static const TQChar units[9] = {0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, - 0x10d5, 0x10d6, 0x10f1, 0x10d7 }; - - if (number < 1 || number > 19999) return TQString::number(number); - if (number >= 10000) { - georgian.append(tenthousand); - number = number - 10000; - } - if (number >= 1000) { - georgian.append(thousands[number/1000-1]); - number = number % 1000; - } - if (number >= 100) { - georgian.append(hundreds[number/100-1]); - number = number % 100; - } - if (number >= 10) { - georgian.append(tens[number/10-1]); - number = number % 10; - } - if (number >= 1) { - georgian.append(units[number-1]); - } - - return georgian; -} - -TQString toArmenian( int number ) -{ - TQString armenian; - int onethousand = 0x57c; - int hundreds = 0x572; - int tens = 0x569; - int units = 0x560; - - // The standard defines values over 1999, but 7000 is very hard to render - if (number < 1 || number > 1999) return TQString::number(number); - if (number >= 1000) { - armenian.append(TQChar(onethousand)); - number = number - 1000; - } - if (number >= 100) { - armenian.append(TQChar(hundreds+number/100)); - number = number % 100; - } - if (number >= 10) { - armenian.append(TQChar(tens+number/10)); - number = number % 10; - } - if (number >= 1) { - armenian.append(TQChar(units+number)); - } - - return armenian; -} - -TQString toHebrew( int number ) { - static const TQChar tenDigit[] = {1497, 1499, 1500, 1502, 1504, 1505, 1506, 1508, 1510}; - - TQString letter; - if (number < 1) return TQString::number(number); - if (number>999) { - letter = toHebrew(number/1000) + TQString::fromLatin1("'"); - number = number%1000; - } - - int hunderts = (number/400); - if (hunderts > 0) { - for(int i=0; i<hunderts; i++) { - letter += TQChar(1511 + 3); - } - } - number = number % 400; - if ((number / 100) != 0) { - letter += TQChar (1511 + (number / 100) -1); - } - number = number % 100; - int tens = number/10; - if (tens > 0 && !(number == 15 || number == 16)) { - letter += tenDigit[tens-1]; - } - if (number == 15 || number == 16) { // special because of religious - letter += TQChar(1487 + 9); // reasons - letter += TQChar(1487 + number - 9); - } else { - number = number % 10; - if (number != 0) { - letter += TQChar (1487 + number); - } - } - return letter; -} - -static inline TQString toLatin( int number, int base ) { - if (number < 1) return TQString::number(number); - TQValueList<TQChar> letters; - while(number > 0) { - number--; // number 0 is letter a - TQChar letter = (TQChar) (base + (number % 26)); - letters.prepend(letter); - number /= 26; - } - TQString str; - str.setLength(letters.size()); - int i=0; - while(!letters.isEmpty()) { - str[i++] = letters.front(); - letters.pop_front(); - } - return str; -} - -TQString toLowerLatin( int number ) { - return toLatin( number, 'a' ); -} - -TQString toUpperLatin( int number ) { - return toLatin( number, 'A' ); -} - -static inline TQString toAlphabetic( int number, int base, const TQChar alphabet[] ) { - if (number < 1) return TQString::number(number); - TQValueList<TQChar> letters; - while(number > 0) { - number--; // number 0 is letter 1 - TQChar letter = alphabet[number % base]; - letters.prepend(letter); - number /= base; - } - TQString str; - str.setLength(letters.size()); - int i=0; - while(!letters.isEmpty()) { - str[i++] = letters.front(); - letters.pop_front(); - } - return str; -} - -TQString toHiragana( int number ) { - static const TQChar hiragana[48] = {0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x304B, 0x304D, - 0x304F, 0x3051, 0x3053, 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, - 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, 0x306A, 0x306B, - 0x306C, 0x306D, 0x306E, 0x306F, 0x3072, 0x3075, 0x3078, - 0x307B, 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, 0x3084, 0x3086, - 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308F, - 0x3090, 0x3091, 0x9092, 0x3093}; - return toAlphabetic( number, 48, hiragana ); -} - -TQString toHiraganaIroha( int number ) { - static const TQChar hiragana[47] = {0x3044, 0x308D, 0x306F, 0x306B, 0x307B, 0x3078, 0x3068, - 0x3061, 0x308A, 0x306C, 0x308B, 0x3092, 0x308F, 0x304B, - 0x3088, 0x305F, 0x308C, 0x305D, 0x3064, 0x306D, 0x306A, - 0x3089, 0x3080, 0x3046, 0x3090, 0x306E, 0x304A, 0x304F, 0x3084, - 0x307E, 0x3051, 0x3075, 0x3053, 0x3048, 0x3066, 0x3042, 0x3055, - 0x304D, 0x3086, 0x3081, 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, - 0x305B, 0x3059 }; - return toAlphabetic( number, 47, hiragana ); -} - -TQString toKatakana( int number ) { - static const TQChar katakana[48] = {0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, - 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, - 0x30BD, 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, - 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, - 0x30D8, 0x30DB, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, - 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, - 0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x90F2, 0x30F3}; - return toAlphabetic( number, 48, katakana ); -} - -TQString toKatakanaIroha( int number ) { - static const TQChar katakana[47] = {0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, 0x30D8, 0x30C8, - 0x30C1, 0x30EA, 0x30CC, 0x30EB, 0x30F2, 0x30EF, 0x30AB, - 0x30E8, 0x30BF, 0x30EC, 0x30ED, 0x30C4, 0x30CD, 0x30CA, - 0x30E9, 0x30E0, 0x30A6, 0x30F0, 0x30CE, 0x30AA, 0x30AF, - 0x30E4, 0x30DE, 0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6, - 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, 0x30DF, 0x30B7, - 0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x90B9}; - return toAlphabetic( number, 47, katakana ); -} - -TQString toLowerGreek( int number ) { - static const TQChar greek[24] = { 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, - 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, - 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, - 0x3C7, 0x3C8, 0x3C0}; - - return toAlphabetic( number, 24, greek ); -} - -TQString toUpperGreek( int number ) { - // The standard claims to be base 24, but only lists 19 letters. - static const TQChar greek[19] = { 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, - 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, - 0x3A0, 0x3A1, 0x3A3, 0x3A9}; - - return toAlphabetic( number, 19, greek ); -} - -static inline TQString toNumeric( int number, int base ) { - TQString letter = TQString::number(number); - for(unsigned int i = 0; i < letter.length(); i++) { - if (letter[i].isDigit()) - letter[i] = TQChar(letter[i].digitValue()+base); - } - return letter; -} - -TQString toArabicIndic( int number ) { - return toNumeric(number, 0x660); -} - -TQString toPersianUrdu( int number ) { - return toNumeric(number, 0x6F0); -} - -TQString toLao( int number ) { - return toNumeric(number, 0xED0); -} - -TQString toThai( int number ) { - return toNumeric(number, 0xE50); -} - -TQString toTibetan( int number ) { - return toNumeric(number, 0xF20); -} - -static inline TQString toIdeographic(int number, const TQChar digits[], const TQChar digitmarkers[]) { - if (number < 0 || number > 9999) return TQString::number(number); - - TQString grp = TQString::number(number); - - // ### Append group markers to handle numbers > 9999 - - TQString str; - - // special case - if (number < 20 && number >= 10) { - str.append(digitmarkers[0]); - str.append(digits[grp[1].digitValue()]); - return str; - } - - int len = grp.length(); - bool collapseZero = false; - for (int i = 0; i < len ; i++) { - int digit = grp[i].digitValue(); - // Add digit markers to digits > 0 - if ((len-i-1) > 0 && digit > 0) - str.append(digitmarkers[(len-i-2)]); - // Add digit, but collapse consecutive zeros - if (!collapseZero || digit > 0) { - str.append(digits[digit]); - - if (digit == 0) - collapseZero = true; - else - collapseZero = false; - } - } - return str; -} - -TQString toTradChineseFormal( int number ) { -// static const TQChar groupMarkers[3] = {0x4e07, 0x4ebf, 0x5146}; - static const TQChar digitMarkers[3] = {0x4e07, 0x4ebf, 0x5146}; - static const TQChar digits[10] = {0x96f6, 0x4e00, - 0x4ebc, 0x4e09, - 0x56db, 0x4e94, - 0x516d, 0x4e03, - 0x516b, 0x4e5d}; - return toIdeographic(number, digits, digitMarkers); -} - -TQString toTradChineseInformal( int number ) { -// static const TQChar groupMarkers[3] = {0x842c, 0x5104, 0x5146}; - static const TQChar digitMarkers[3] = {0x842c, 0x5104, 0x5146}; - static const TQChar digits[10] = {0x96f6, 0x4e00, - 0x4ebc, 0x4e09, - 0x56db, 0x4e94, - 0x516d, 0x4e03, - 0x516b, 0x4e5d}; - return toIdeographic(number, digits, digitMarkers); -} - -TQString toSimpChineseFormal( int number ) { -// static const TQChar groupMarkers[3] = {0x4e07, 0x5104, 0x5146}; - static const TQChar digitMarkers[3] = {0x4e07, 0x4ebf, 0x5146}; - static const TQChar digits[10] = {0x96f6, 0x58f9, - 0x8cb3, 0x53c3, - 0x8086, 0x4f0d, - 0x9678, 0x67d2, - 0x634c, 0x7396}; - return toIdeographic(number, digits, digitMarkers); -} - -TQString toSimpChineseInformal( int number ) { -// static const TQChar groupMarkers[3] = {0x842c, 0x5104, 0x5146}; - static const TQChar digitMarkers[3] = {0x842c, 0x5104, 0x5146}; - static const TQChar digits[10] = {0x96f6, 0x58f9, - 0x8cb3, 0x53c3, - 0x8086, 0x4f0d, - 0x9678, 0x67d2, - 0x634c, 0x7396}; - return toIdeographic(number, digits, digitMarkers); -} - -TQString toJapaneseFormal( int number ) { -// static const TQChar groupMarkers[3] = {0x4e07, 0x5104, 0x5146}; - static const TQChar digitMarkers[3] = {0x62fe, 0x4f70, 0x4edf}; - static const TQChar digits[10] = {0x96f6, 0x58f9, - 0x8cb3, 0x53c3, - 0x8086, 0x4f0d, - 0x9678, 0x67d2, - 0x634c, 0x7396}; - return toIdeographic(number, digits, digitMarkers); -} - -TQString toJapaneseInformal( int number ) { -// static const TQChar groupMarkers[3] = {0x842c, 0x5104, 0x5146}; - static const TQChar digitMarkers[3] = {0x842c, 0x5104, 0x5146}; - static const TQChar digits[10] = {0x96f6, 0x58f9, - 0x8d30, 0x53c1, - 0x8086, 0x4f0d, - 0x9646, 0x67d2, - 0x634c, 0x7396}; - return toIdeographic(number, digits, digitMarkers); -} - -}} // namespace diff --git a/khtml/rendering/enumerate.h b/khtml/rendering/enumerate.h deleted file mode 100644 index c8df6549a..000000000 --- a/khtml/rendering/enumerate.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ - -#ifndef ENUMERATE_H -#define ENUMERATE_H - -class TQChar; -class TQString; - -namespace khtml { - -namespace Enumerate { - -// Numeric - TQString toArabicIndic( int number ); - TQString toLao( int number ); - TQString toPersianUrdu( int number ); - TQString toThai( int number ); - TQString toTibetan( int number ); - -// Alphabetic - TQString toLowerLatin( int number ); - TQString toUpperLatin( int number ); - TQString toLowerGreek( int number ); - TQString toUpperGreek( int number ); - TQString toHiragana( int number ); - TQString toHiraganaIroha( int number ); - TQString toKatakana( int number ); - TQString toKatakanaIroha( int number ); - -// Algorithmic - TQString toRoman( int number, bool upper ); - TQString toHebrew( int number ); - TQString toGeorgian( int number ); - TQString toArmenian( int number ); - -// Ideographic - TQString toJapaneseFormal ( int number ); - TQString toJapaneseInformal ( int number ); - TQString toSimpChineseFormal ( int number ); - TQString toSimpChineseInformal ( int number ); - TQString toTradChineseFormal ( int number ); - TQString toTradChineseInformal ( int number ); - -}} // namespaces - -#endif diff --git a/khtml/rendering/font.cpp b/khtml/rendering/font.cpp deleted file mode 100644 index 1a0591192..000000000 --- a/khtml/rendering/font.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.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 "config.h" - -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#endif - -#include "font.h" -#include "khtml_factory.h" -#include "khtml_settings.h" - -#include <kdebug.h> -#include <kglobal.h> - -#include <tqpainter.h> -#include <tqfontdatabase.h> -#include <tqpaintdevicemetrics.h> - -using namespace khtml; - -/** closes the current word and returns its width in pixels - * @param fm metrics of font to be used - * @param str string - * @param pos zero-indexed position within @p str upon which all other - * indices are based - * @param wordStart relative index pointing to the position where the word started - * @param wordEnd relative index pointing one position after the word ended - * @return the width in pixels. May be 0 if @p wordStart and @p wordEnd were - * equal. - */ -inline int closeWordAndGetWidth(const TQFontMetrics &fm, const TQChar *str, int pos, - int wordStart, int wordEnd) -{ - if (wordEnd <= wordStart) return 0; - - TQConstString s(str + pos + wordStart, wordEnd - wordStart); - return fm.width(s.string()); -} - -/** closes the current word and draws it - * @param p painter - * @param d text direction - * @param x current x position, will be inc-/decremented correctly according - * to text direction - * @param y baseline of text - * @param widths list of widths; width of word is expected at position - * wordStart - * @param str string - * @param pos zero-indexed position within @p str upon which all other - * indices are based - * @param wordStart relative index pointing to the position where the word started, - * will be set to wordEnd after function - * @param wordEnd relative index pointing one position after the word ended - */ -inline void closeAndDrawWord(TQPainter *p, TQPainter::TextDirection d, - int &x, int y, const short widths[], const TQChar *str, int pos, - int &wordStart, int wordEnd) -{ - if (wordEnd <= wordStart) return; - - int width = widths[wordStart]; - if (d == TQPainter::RTL) - x -= width; - - TQConstString s(str + pos + wordStart, wordEnd - wordStart); - p->drawText(x, y, s.string(), -1, d); - - if (d != TQPainter::RTL) - x += width; - - wordStart = wordEnd; -} - -void Font::drawText( TQPainter *p, int x, int y, TQChar *str, int slen, int pos, int len, - int toAdd, TQPainter::TextDirection d, int from, int to, TQColor bg, int uy, int h, int deco ) const -{ - if (!str) return; - TQConstString cstr = TQConstString(str, slen); - TQString qstr = cstr.string(); - - // ### fixme for RTL - if ( !scFont && !letterSpacing && !wordSpacing && !toAdd && from==-1 ) { - // simply draw it - // Due to some unfounded cause TQPainter::drawText traverses the - // *whole* string when painting, not only the specified - // [pos, pos + len) segment. This makes painting *extremely* slow for - // long render texts (in the order of several megabytes). - // Hence, only hand over the piece of text of the actual inline text box - TQConstString cstr = TQConstString(str + pos, len); - p->drawText( x, y, cstr.string(), 0, len, d ); - } else { - if (from < 0) from = 0; - if (to < 0) to = len; - - int numSpaces = 0; - if ( toAdd ) { - for( int i = 0; i < len; ++i ) - if ( str[i+pos].category() == TQChar::Separator_Space ) - ++numSpaces; - } - - const int totWidth = width( str, slen, pos, len ); - if ( d == TQPainter::RTL ) { - x += totWidth + toAdd; - } - TQString upper = qstr; - TQFontMetrics sc_fm = fm; - if ( scFont ) { - // draw in small caps - upper = qstr.upper(); - sc_fm = TQFontMetrics( *scFont ); - } - - // ### sc could be optimized by only painting uppercase letters extra, - // and treat the rest WordWise, but I think it's not worth it. - // Somebody else may volunteer, and implement this ;-) (LS) - - // The mode determines whether the text is displayed character by - // character, word by word, or as a whole - enum { CharacterWise, WordWise, Whole } - mode = Whole; - if (!letterSpacing && !scFont && (wordSpacing || toAdd > 0)) - mode = WordWise; - else if (letterSpacing || scFont) - mode = CharacterWise; - - if (mode == Whole) { // most likely variant is treated extra - - if (to < 0) to = len; - const TQConstString cstr(str + pos, len); - const TQConstString segStr(str + pos + from, to - from); - const int preSegmentWidth = fm.width(cstr.string(), from); - const int segmentWidth = fm.width(segStr.string()); - const int eff_x = d == TQPainter::RTL ? x - preSegmentWidth - segmentWidth - : x + preSegmentWidth; - - // draw whole string segment, with optional background - if ( bg.isValid() ) - p->fillRect( eff_x, uy, segmentWidth, h, bg ); - p->drawText(eff_x, y, segStr.string(), -1, d); - if (deco) - drawDecoration(p, eff_x, uy, y - uy, segmentWidth - 1, h, deco); - return; - } - - // We are using two passes. In the first pass, the widths are collected, - // and stored. In the second, the actual characters are drawn. - - // For each letter in the text box, save the width of the character. - // When word-wise, only the first letter contains the width, but of the - // whole word. - short* const widthList = (short *)alloca(to*sizeof(short)); - - // First pass: gather widths - int preSegmentWidth = 0; - int segmentWidth = 0; - int lastWordBegin = 0; - bool onSegment = from == 0; - for( int i = 0; i < to; ++i ) { - if (i == from) { - // Also close words on visibility boundary - if (mode == WordWise) { - const int width = closeWordAndGetWidth(fm, str, pos, lastWordBegin, i); - - if (lastWordBegin < i) { - widthList[lastWordBegin] = (short)width; - lastWordBegin = i; - preSegmentWidth += width; - } - } - onSegment = true; - } - - const TQChar ch = str[pos+i]; - bool lowercase = (ch.category() == TQChar::Letter_Lowercase); - bool is_space = (ch.category() == TQChar::Separator_Space); - int chw = 0; - if ( letterSpacing ) - chw += letterSpacing; - if ( (wordSpacing || toAdd) && is_space ) { - if (mode == WordWise) { - const int width = closeWordAndGetWidth(fm, str, pos, lastWordBegin, i); - if (lastWordBegin < i) { - widthList[lastWordBegin] = (short)width; - lastWordBegin = i; - (onSegment ? segmentWidth : preSegmentWidth) += width; - } - ++lastWordBegin; // ignore this space - } - chw += wordSpacing; - if ( numSpaces ) { - const int a = toAdd/numSpaces; - chw += a; - toAdd -= a; - --numSpaces; - } - } - if (is_space || mode == CharacterWise) { - chw += lowercase ? sc_fm.charWidth( upper, pos+i ) : fm.charWidth( qstr, pos+i ); - widthList[i] = (short)chw; - - (onSegment ? segmentWidth : preSegmentWidth) += chw; - } - - } - - // close last word - Q_ASSERT(onSegment); - if (mode == WordWise) { - const int width = closeWordAndGetWidth(fm, str, pos, lastWordBegin, to); - segmentWidth += width; - widthList[lastWordBegin] = (short)width; - } - - if (d == TQPainter::RTL) x -= preSegmentWidth; - else x += preSegmentWidth; - - const int startx = d == TQPainter::RTL ? x-segmentWidth : x; - - // optionally draw background - if ( bg.isValid() ) - p->fillRect( startx, uy, segmentWidth, h, bg ); - - // second pass: do the actual drawing - lastWordBegin = from; - for( int i = from; i < to; ++i ) { - const TQChar ch = str[pos+i]; - bool lowercase = (ch.category() == TQChar::Letter_Lowercase); - bool is_space = ch.category() == TQChar::Separator_Space; - if ( is_space ) { - if (mode == WordWise) { - closeAndDrawWord(p, d, x, y, widthList, str, pos, lastWordBegin, i); - ++lastWordBegin; // jump over space - } - } - if (is_space || mode == CharacterWise) { - const int chw = widthList[i]; - if (d == TQPainter::RTL) - x -= chw; - - if ( scFont ) - p->setFont( lowercase ? *scFont : f ); - p->drawText( x, y, (lowercase ? upper : qstr), pos+i, 1, d ); - - if (d != TQPainter::RTL) - x += chw; - } - - } - - // don't forget to draw last word - if (mode == WordWise) { - closeAndDrawWord(p, d, x, y, widthList, str, pos, lastWordBegin, to); - } - - if (deco) - drawDecoration(p, startx, uy, y - uy, segmentWidth - 1, h, deco); - - if ( scFont ) - p->setFont( f ); - } -} - - -int Font::width( TQChar *chs, int, int pos, int len, int start, int end, int toAdd ) const -{ - const TQConstString cstr(chs+pos, len); - int w = 0; - - const TQString qstr = cstr.string(); - if ( scFont ) { - const TQString upper = qstr.upper(); - const TQChar *uc = qstr.unicode(); - const TQFontMetrics sc_fm( *scFont ); - for ( int i = 0; i < len; ++i ) { - if ( (uc+i)->category() == TQChar::Letter_Lowercase ) - w += sc_fm.charWidth( upper, i ); - else - w += fm.charWidth( qstr, i ); - } - } else { - // ### might be a little inaccurate - w = fm.width( qstr ); - } - - if ( letterSpacing ) - w += len*letterSpacing; - - if ( wordSpacing ) - // add amount - for( int i = 0; i < len; ++i ) { - if( chs[i+pos].category() == TQChar::Separator_Space ) - w += wordSpacing; - } - - if ( toAdd ) { - // first gather count of spaces - int numSpaces = 0; - for( int i = start; i != end; ++i ) - if ( chs[i].category() == TQChar::Separator_Space ) - ++numSpaces; - // distribute pixels evenly among spaces, but count only those within - // [pos, pos+len) - for ( int i = start; numSpaces && i != pos + len; i++ ) - if ( chs[i].category() == TQChar::Separator_Space ) { - const int a = toAdd/numSpaces; - if ( i >= pos ) w += a; - toAdd -= a; - --numSpaces; - } - } - - return w; -} - -int Font::width( TQChar *chs, int slen, int pos ) const -{ - int w; - if ( scFont && chs[pos].category() == TQChar::Letter_Lowercase ) { - TQString str( chs, slen ); - str[pos] = chs[pos].upper(); - w = TQFontMetrics( *scFont ).charWidth( str, pos ); - } else { - const TQConstString cstr( chs, slen ); - w = fm.charWidth( cstr.string(), pos ); - } - if ( letterSpacing ) - w += letterSpacing; - - if ( wordSpacing && (chs+pos)->category() == TQChar::Separator_Space ) - w += wordSpacing; - return w; -} - -/** Querying QFontDB whether something is scalable is expensive, so we cache. */ -struct Font::ScalKey -{ - TQString family; - int weight; - int italic; - - ScalKey(const TQFont& font) : - family(font.family()), weight(font.weight()), italic(font.italic()) - {} - - ScalKey() {} - - bool operator<(const ScalKey& other) const { - if (weight < other.weight) - return true; - if (weight > other.weight) - return false; - - if (italic < other.italic) - return true; - if (italic > other.italic) - return false; - - return family < other.family; - } - - bool operator==(const ScalKey& other) const { - return (weight == other.weight && - italic == other.italic && - family == other.family); - } -}; - -TQMap<Font::ScalKey, Font::ScalInfo>* Font::scalCache; -TQMap<Font::ScalKey, TQValueList<int> >* Font::scalSizesCache; - -bool Font::isFontScalable(TQFontDatabase& db, const TQFont& font) -{ - if (!scalCache) - scalCache = new TQMap<ScalKey, ScalInfo>; - - ScalKey key(font); - - ScalInfo &s = (*scalCache)[key]; - if (s == Unknown) { - s = db.isSmoothlyScalable(font.family(), db.styleString(font)) ? Yes : No; - - if (s == No) { - /* Cache size info */ - if (!scalSizesCache) - scalSizesCache = new TQMap<ScalKey, TQValueList<int> >; - (*scalSizesCache)[key] = db.smoothSizes(font.family(), db.styleString(font)); - } - } - - return (s == Yes); -} - - -void Font::update( TQPaintDeviceMetrics* devMetrics ) const -{ - f.setFamily( fontDef.family.isEmpty() ? KHTMLFactory::defaultHTMLSettings()->stdFontName() : fontDef.family ); - f.setItalic( fontDef.italic ); - f.setWeight( fontDef.weight ); - - TQFontDatabase db; - - int size = fontDef.size; - const int lDpiY = kMax(devMetrics->logicalDpiY(), 96); - - // ok, now some magic to get a nice unscaled font - // all other font properties should be set before this one!!!! - if( !isFontScalable(db, f) ) - { - const TQValueList<int>& pointSizes = (*scalSizesCache)[ScalKey(f)]; - // lets see if we find a nice looking font, which is not too far away - // from the requested one. - // kdDebug(6080) << "khtml::setFontSize family = " << f.family() << " size requested=" << size << endl; - - - float diff = 1; // ### 100% deviation - float bestSize = 0; - - TQValueList<int>::ConstIterator it = pointSizes.begin(); - const TQValueList<int>::ConstIterator itEnd = pointSizes.end(); - - for( ; it != itEnd; ++it ) - { - float newDiff = ((*it)*(lDpiY/72.) - float(size))/float(size); - //kdDebug( 6080 ) << "smooth font size: " << *it << " diff=" << newDiff << endl; - if(newDiff < 0) newDiff = -newDiff; - if(newDiff < diff) - { - diff = newDiff; - bestSize = *it; - } - } - //kdDebug( 6080 ) << "best smooth font size: " << bestSize << " diff=" << diff << endl; - if ( bestSize != 0 && diff < 0.2 ) // 20% deviation, otherwise we use a scaled font... - size = (int)((bestSize*lDpiY) / 72); - } - - // make sure we don't bust up X11 - // Also, Qt does not support sizing a TQFont to zero. - size = kMax(1, kMin(255, size)); - -// tqDebug("setting font to %s, italic=%d, weight=%d, size=%d", fontDef.family.latin1(), fontDef.italic, -// fontDef.weight, size ); - - - f.setPixelSize( size ); - - fm = TQFontMetrics( f ); - - // small caps - delete scFont; - scFont = 0; - - if ( fontDef.smallCaps ) { - scFont = new TQFont( f ); - scFont->setPixelSize( kMax(1, f.pixelSize()*7/10) ); - } -} - -void Font::drawDecoration(TQPainter *pt, int _tx, int _ty, int baseline, int width, int height, int deco) const -{ - Q_UNUSED(height); - // thick lines on small fonts look ugly - const int thickness = fm.height() > 20 ? fm.lineWidth() : 1; - const TQBrush brush = pt->pen().color(); - if (deco & UNDERLINE) { - int underlineOffset = ( fm.height() + baseline ) / 2; - if (underlineOffset <= baseline) underlineOffset = baseline+1; - - pt->fillRect(_tx, _ty + underlineOffset, width + 1, thickness, brush ); - } - if (deco & OVERLINE) { - pt->fillRect(_tx, _ty, width + 1, thickness, brush ); - } - if (deco & LINE_THROUGH) { - pt->fillRect(_tx, _ty + 2*baseline/3, width + 1, thickness, brush ); - } -} - diff --git a/khtml/rendering/font.h b/khtml/rendering/font.h deleted file mode 100644 index 714b03829..000000000 --- a/khtml/rendering/font.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.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. - * - */ - -#ifndef KHTMLFONT_H -#define KHTMLFONT_H - -#include <tqfont.h> -#include <tqfontmetrics.h> -#include <tqmap.h> -#include <tqpainter.h> - -class TQFontDatabase; -class TQPaintDeviceMetrics; - -namespace khtml -{ -class RenderStyle; -class CSSStyleSelector; - -class FontDef -{ -public: - FontDef() - : size( 0 ), italic( false ), smallCaps( false ), weight( 50 ) {} - bool operator == ( const FontDef &other ) const { - return ( family == other.family && - size == other.size && - italic == other.italic && - smallCaps == other.smallCaps && - weight == other.weight ); - } - - TQString family; - short int size; - bool italic : 1; - bool smallCaps : 1; - unsigned int weight : 8; -}; - - -class Font -{ - friend class RenderStyle; - friend class CSSStyleSelector; - -public: - Font() : fontDef(), f(), fm( f ), scFont( 0 ), letterSpacing( 0 ), wordSpacing( 0 ) {} - Font( const FontDef &fd ) - : fontDef( fd ), f(), fm( f ), scFont( 0 ), letterSpacing( 0 ), wordSpacing( 0 ) - {} - Font(const Font& o) - : fontDef(o.fontDef), f(o.f), fm(o.fm), scFont(o.scFont), letterSpacing(o.letterSpacing), wordSpacing(o.wordSpacing) { if (o.scFont) scFont = new TQFont(*o.scFont); } - ~Font() { delete scFont; } - - bool operator == ( const Font &other ) const { - return (fontDef == other.fontDef && - letterSpacing == other.letterSpacing && - wordSpacing == other.wordSpacing ); - } - - const FontDef& getFontDef() const { return fontDef; } - - void update( TQPaintDeviceMetrics *devMetrics ) const; - - /** - * Draws a piece from the given piece of text. - * @param p painter - * @param x x-coordinate to begin drawing, always denotes leftmost position - * @param y y-coordinate of baseline of text - * @param str string to draw a piece from - * @param slen total length of string - * @param pos zero-based offset of beginning of piece - * @param len length of piece - * @param width additional pixels to be distributed equally among all - * spaces - * @param d text direction - * @param from begin with this position relative to @p pos, -1 to start - * at @p pos - * @param to stop before this position relative to @p pos, -1 to use full - * length of piece - * @param bg if valid, fill the background of the drawn piece with this - * color - * @param uy y-coordinate of top position, used for background and text - * decoration painting - * @param h total height of line, only used for background and text - * decoration painting - * @param deco combined text decoration (see Decoration) - */ - void drawText( TQPainter *p, int x, int y, TQChar *str, int slen, int pos, int len, int width, - TQPainter::TextDirection d, int from=-1, int to=-1, TQColor bg=TQColor(), - int uy=-1, int h=-1, int deco=0 ) const; - - /** returns the width of the given string chunk in pixels. - * - * The method also considers various styles like text-align and font-variant - * @param str pointer to string - * @param slen total length of string - * @param pos zero-based position in string where to start measuring - * @param len count of characters up to which the width should be determined - * @param start starting position of inline text box within str, only - * used when toAdd is specified. - * @param end ending position of inline text box within str, only - * used when toAdd is specified. - * @param toAdd amount of pixels to distribute evenly among all spaces of - * str. Note that toAdd applies to all spaces within str, but only those - * within [pos, pos+len) are counted towards the width. - */ - int width( TQChar *str, int slen, int pos, int len, int start = 0, int end = 0, int toAdd = 0 ) const; - /** return the width of the given char in pixels. - * - * The method also considers various styles like text-align and font-variant - * @param str pointer to string - * @param slen total length of string - * @param pos zero-based position of char in string - */ - int width( TQChar *str, int slen, int pos) const; - - /** Text decoration constants. - * - * The enumeration constant values match those of ETextDecoration, but only - * a subset is supported. - */ - enum Decoration { UNDERLINE = 0x1, OVERLINE = 0x2, LINE_THROUGH= 0x4 }; - // Keep in sync with ETextDecoration - - /** draws text decoration - * @param p painter - * @param x x-coordinate - * @param y top y-coordinate of line box - * @param baseline baseline - * @param width length of decoration in pixels - * @param height height of line box - * @param deco decoration to be drawn (see Decoration). The enumeration - * constants may be combined. - */ - void drawDecoration(TQPainter *p, int x, int y, int baseline, int width, int height, int deco) const; - - /** returns letter spacing - */ - int getLetterSpacing() const { return letterSpacing; } - /** returns word spacing - */ - int getWordSpacing() const { return wordSpacing; } - -private: - mutable FontDef fontDef; - mutable TQFont f; - mutable TQFontMetrics fm; - mutable TQFont *scFont; - short letterSpacing; - short wordSpacing; - - struct ScalKey; - enum ScalInfo { - Unknown, - No, - Yes - }; - - static TQMap<ScalKey, ScalInfo>* scalCache; - static TQMap<ScalKey, TQValueList<int> >* scalSizesCache; - static bool isFontScalable(TQFontDatabase& db, const TQFont& font); -}; - -} // namespace - -#endif diff --git a/khtml/rendering/img-loading.png b/khtml/rendering/img-loading.png Binary files differdeleted file mode 100644 index ae5a9732f..000000000 --- a/khtml/rendering/img-loading.png +++ /dev/null diff --git a/khtml/rendering/loading_icon.cpp b/khtml/rendering/loading_icon.cpp deleted file mode 100644 index 218befcf8..000000000 --- a/khtml/rendering/loading_icon.cpp +++ /dev/null @@ -1,25 +0,0 @@ -static const unsigned char loading_icon_data[] = { -0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44, -0x52,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x10,0x08,0x04,0x00,0x00,0x00,0x8c, -0x9d,0x86,0xb1,0x00,0x00,0x00,0x04,0x67,0x41,0x4d,0x41,0x00,0x00,0xb1,0x8f, -0x0b,0xfc,0x61,0x05,0x00,0x00,0x00,0x02,0x62,0x4b,0x47,0x44,0x00,0xff,0x87, -0x8f,0xcc,0xbf,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x12, -0x00,0x00,0x0b,0x12,0x01,0xd2,0xdd,0x7e,0xfc,0x00,0x00,0x00,0x07,0x74,0x49, -0x4d,0x45,0x07,0xd4,0x0c,0x17,0x10,0x00,0x23,0xf3,0x04,0xa4,0xbc,0x00,0x00, -0x00,0xbf,0x49,0x44,0x41,0x54,0x78,0x9c,0x75,0xd1,0x31,0x4e,0x04,0x31,0x0c, -0x85,0xe1,0x2f,0xc9,0x1c,0x63,0xee,0x02,0x82,0x9a,0x23,0x70,0x01,0xba,0xad, -0xe8,0x98,0x0d,0x35,0xab,0xe9,0x10,0xf7,0x80,0x76,0xe0,0x32,0x7b,0x01,0x44, -0x9d,0x84,0x22,0xc3,0x32,0xd2,0x82,0x5d,0xd9,0xbf,0xf5,0xe4,0x67,0x07,0xd9, -0x59,0x4c,0xf2,0x04,0x91,0xf6,0x47,0x3e,0x64,0x18,0xe0,0x1d,0x51,0x15,0x05, -0x05,0xc1,0x5e,0xc8,0x79,0x1a,0xba,0x50,0x54,0x3d,0x49,0x76,0xa2,0xaa,0x61, -0x4f,0x8e,0x1d,0x05,0xb3,0x1b,0xc5,0xb5,0x2a,0x79,0x14,0x04,0xb9,0xcb,0x06, -0x45,0xf1,0x2a,0x21,0x2a,0x16,0x5c,0x09,0x1d,0x16,0xd1,0xbd,0x4b,0x2c,0xaa, -0xa4,0x48,0x4e,0x0b,0xf5,0x58,0x24,0xcd,0x2d,0x38,0x6a,0xdd,0x0a,0xd1,0x41, -0x41,0x01,0xcf,0xa7,0xf1,0x08,0xd5,0x68,0x16,0x11,0x70,0xe7,0x73,0x0b,0x13, -0x46,0x07,0x34,0x47,0x47,0x5f,0x2b,0x1c,0xa0,0x81,0xd1,0x6c,0x67,0xd9,0x9c, -0x71,0xe8,0xb2,0x2f,0x6b,0xf9,0xe6,0x43,0xd0,0xd4,0x5f,0x98,0x2c,0x48,0x9a, -0xba,0xb6,0x37,0x56,0x2e,0xce,0x1f,0xf3,0x03,0xc3,0x3f,0x88,0x6f,0xc1,0xe0, -0x3e,0x9e,0x60,0xe9,0x10,0xaa,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae, -0x42,0x60,0x82 -}; -static const unsigned int loading_icon_len = 318; diff --git a/khtml/rendering/render_applet.cpp b/khtml/rendering/render_applet.cpp deleted file mode 100644 index fce22f7c8..000000000 --- a/khtml/rendering/render_applet.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/** - * This file is part of the HTML widget for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.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 <config.h> -#include <klocale.h> - -#include <kdebug.h> - -#include "rendering/render_applet.h" -#include "rendering/render_canvas.h" -#include "xml/dom_docimpl.h" -#include "khtmlview.h" -#include "khtml_part.h" - -#include <tqlabel.h> - -#ifndef Q_WS_QWS // We don't have Java in Qt Embedded - -#include "java/kjavaappletwidget.h" -#include "misc/htmltags.h" -#include "html/html_objectimpl.h" - -using namespace khtml; -using namespace DOM; - -RenderApplet::RenderApplet(HTMLElementImpl *applet, const TQMap<TQString, TQString> &args ) - : RenderWidget(applet) -{ - // init RenderObject attributes - setInline(true); - - KJavaAppletContext *context = 0; - KHTMLView *_view = applet->getDocument()->view(); - if ( _view ) { - KHTMLPart *part = _view->part(); - context = part->createJavaContext(); - } - - if ( context ) { - //kdDebug(6100) << "RenderApplet::RenderApplet, setting TQWidget" << endl; - setQWidget( new KJavaAppletWidget(context, _view->viewport()) ); - processArguments(args); - } -} - -RenderApplet::~RenderApplet() -{ -} - -short RenderApplet::intrinsicWidth() const -{ - int rval = 300; - - if( m_widget ) - rval = ((KJavaAppletWidget*)(m_widget))->sizeHint().width(); - - return rval > 10 ? rval : 50; -} - -int RenderApplet::intrinsicHeight() const -{ - int rval = 150; - - if( m_widget ) - rval = m_widget->sizeHint().height(); - - return rval > 10 ? rval : 50; -} - -void RenderApplet::layout() -{ - //kdDebug(6100) << "RenderApplet::layout" << endl; - - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - calcWidth(); - calcHeight(); - - KJavaAppletWidget *tmp = static_cast<KJavaAppletWidget*>(m_widget); - if ( tmp ) { - NodeImpl *child = element()->firstChild(); - - while(child) { - - if(child->id() == ID_PARAM) { - HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>(child); - if(tmp->applet()) - tmp->applet()->setParameter( p->name(), p->value()); - } - child = child->nextSibling(); - } - //kdDebug(6100) << "setting applet widget to size: " << m_width << ", " << m_height << endl; - m_widget->resize(m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), - m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom()); - tmp->showApplet(); - } - - setNeedsLayout(false); -} - -void RenderApplet::processArguments(const TQMap<TQString, TQString> &args) -{ - KJavaAppletWidget *w = static_cast<KJavaAppletWidget*>(m_widget); - KJavaApplet* applet = w ? w->applet() : 0; - - if ( applet ) { - applet->setBaseURL( args[TQString::fromLatin1("baseURL") ] ); - applet->setAppletClass( args[TQString::fromLatin1("code") ] ); - - TQString str = args[TQString::fromLatin1("codeBase") ]; - if( !str.isEmpty() ) - applet->setCodeBase( str ); - - str = args[TQString::fromLatin1("name") ]; - if( !str.isNull() ) - applet->setAppletName( str ); - else - applet->setAppletName( args[TQString::fromLatin1("code") ] ); - - str = args[TQString::fromLatin1("archive") ]; - if( !str.isEmpty() ) - applet->setArchives( args[TQString::fromLatin1("archive") ] ); - } -} - -#endif diff --git a/khtml/rendering/render_applet.h b/khtml/rendering/render_applet.h deleted file mode 100644 index 184697a7c..000000000 --- a/khtml/rendering/render_applet.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the HTML widget for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.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. - * - */ -#ifndef render_applet_h -#define render_applet_h - -#include "rendering/render_replaced.h" -#include "html/html_objectimpl.h" - -#include <tqwidget.h> -#include <tqmap.h> - -class KHTMLView; - -namespace DOM { - class HTMLElementImpl; -} - -namespace khtml { - -class RenderApplet : public RenderWidget -{ -public: - RenderApplet(DOM::HTMLElementImpl* node, const TQMap<TQString, TQString> &args); - virtual ~RenderApplet(); - - virtual const char *renderName() const { return "RenderApplet"; } - - virtual void layout(); - virtual short intrinsicWidth() const; - virtual int intrinsicHeight() const; - virtual bool isApplet() const { return true; } - - DOM::HTMLElementImpl *element() const - { return static_cast<DOM::HTMLElementImpl*>(RenderObject::element()); } - -private: - void processArguments( const TQMap<TQString, TQString> &args ); -}; - -} -#endif diff --git a/khtml/rendering/render_arena.cpp b/khtml/rendering/render_arena.cpp deleted file mode 100644 index 99fbf4f4d..000000000 --- a/khtml/rendering/render_arena.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2002 Apple Computer, Inc. - * Copyright (C) 2003 Dirk Mueller (mueller@kde.org) - * - * Portions are Copyright (C) 1998 Netscape Communications Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Alternatively, the contents of this file may be used under the terms - * of either the Mozilla Public License Version 1.1, found at - * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public - * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html - * (the "GPL"), in which case the provisions of the MPL or the GPL are - * applicable instead of those above. If you wish to allow use of your - * version of this file only under the terms of one of those two - * licenses (the MPL or the GPL) and not to allow others to use your - * version of this file under the LGPL, indicate your decision by - * deletingthe provisions above and replace them with the notice and - * other provisions required by the MPL or the GPL, as the case may be. - * If you do not delete the provisions above, a recipient may use your - * version of this file under any of the LGPL, the MPL or the GPL. - */ - -#include "render_arena.h" - -#include <string.h> -#include <assert.h> - -using namespace khtml; - -namespace khtml { - -//#ifdef NDEBUG -#define KHTML_USE_ARENA_ALLOCATOR -//#endif - -typedef struct { - RenderArena *arena; - size_t size; -} RenderArenaDebugHeader; - -#ifdef VALGRIND_SUPPORT -Arena* findContainingArena(ArenaPool* pool, void* ptr) { - uword ptrBits = reinterpret_cast<uword>(ptr); - for (Arena* a = &pool->first; a; a = a->next) - if (ptrBits >= a->base && ptrBits < a->limit) - return a; - return 0; //Should not happen -} -#endif - -RenderArena::RenderArena(unsigned int arenaSize) -{ - // Initialize the arena pool - INIT_ARENA_POOL(&m_pool, "RenderArena", arenaSize); - - // Zero out the recyclers array - memset(m_recyclers, 0, sizeof(m_recyclers)); -} - -RenderArena::~RenderArena() -{ - // Free the arena in the pool and finish using it - FreeArenaPool(&m_pool); -} - -void* RenderArena::allocate(size_t size) -{ -#ifndef KHTML_USE_ARENA_ALLOCATOR - // Use standard malloc so that memory debugging tools work. - void *block = ::malloc(sizeof(RenderArenaDebugHeader) + size); - RenderArenaDebugHeader *header = (RenderArenaDebugHeader *)block; - header->arena = this; - header->size = size; - return header + 1; -#else - void* result = 0; - - // Ensure we have correct alignment for pointers. Important for Tru64 - size = KHTML_ROUNDUP(size, sizeof(void*)); - - // Check recyclers first - if (size < KHTML_MAX_RECYCLED_SIZE) { - const int index = size >> 2; - - result = m_recyclers[index]; - if (result) { -#ifdef VALGRIND_SUPPORT - VALGRIND_MEMPOOL_ALLOC(findContainingArena(&m_pool, result)->base, result, size); -#endif - // Need to move to the next object - void* next = *((void**)result); - m_recyclers[index] = next; - } - } - - if (!result) { - // Allocate a new chunk from the arena - ARENA_ALLOCATE(result, &m_pool, size); - } - - return result; -#endif -} - -void RenderArena::free(size_t size, void* ptr) -{ -#ifndef KHTML_USE_ARENA_ALLOCATOR - // Use standard free so that memory debugging tools work. - assert(this); - RenderArenaDebugHeader *header = (RenderArenaDebugHeader *)ptr - 1; - assert(header->size == size); - assert(header->arena == this); - ::free(header); -#else - -#ifdef VALGRIND_SUPPORT - VALGRIND_MEMPOOL_FREE(findContainingArena(&m_pool, ptr)->base, ptr); -#endif - - // Ensure we have correct alignment for pointers. Important for Tru64 - size = KHTML_ROUNDUP(size, sizeof(void*)); - - // See if it's a size that we recycle - if (size < KHTML_MAX_RECYCLED_SIZE) { - const int index = size >> 2; - void* currentTop = m_recyclers[index]; - m_recyclers[index] = ptr; - *((void**)ptr) = currentTop; - } -#endif -} - -} diff --git a/khtml/rendering/render_arena.h b/khtml/rendering/render_arena.h deleted file mode 100644 index 786cd208a..000000000 --- a/khtml/rendering/render_arena.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2002 Apple Computer, Inc. - * Copyright (C) 2003 Dirk Mueller (mueller@kde.org) - * - * Portions are Copyright (C) 1998 Netscape Communications Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Alternatively, the contents of this file may be used under the terms - * of either the Mozilla Public License Version 1.1, found at - * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public - * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html - * (the "GPL"), in which case the provisions of the MPL or the GPL are - * applicable instead of those above. If you wish to allow use of your - * version of this file only under the terms of one of those two - * licenses (the MPL or the GPL) and not to allow others to use your - * version of this file under the LGPL, indicate your decision by - * deletingthe provisions above and replace them with the notice and - * other provisions required by the MPL or the GPL, as the case may be. - * If you do not delete the provisions above, a recipient may use your - * version of this file under any of the LGPL, the MPL or the GPL. - */ - -#ifndef RENDERARENA_H -#define RENDERARENA_H - -#include "misc/arena.h" -#include "misc/shared.h" - -#include <stdlib.h> - -namespace khtml { - -#define KHTML_MAX_RECYCLED_SIZE 400 -#define KHTML_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) - -class RenderArena: public Shared<RenderArena> { -public: - RenderArena(unsigned int arenaSize = 4096); - ~RenderArena(); - - // Memory management functions - void* allocate(size_t size); - void free(size_t size, void* ptr); - -private: - // Underlying arena pool - ArenaPool m_pool; - - // The recycler array is sparse with the indices being multiples of 4, - // i.e., 0, 4, 8, 12, 16, 20, ... - void* m_recyclers[KHTML_MAX_RECYCLED_SIZE >> 2]; -}; - - -} // namespace - - -#endif - diff --git a/khtml/rendering/render_block.cpp b/khtml/rendering/render_block.cpp deleted file mode 100644 index ccbb6fad0..000000000 --- a/khtml/rendering/render_block.cpp +++ /dev/null @@ -1,3155 +0,0 @@ -/* - * This file is part of the render object implementation for KHTML. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003,2005 Apple Computer, Inc. - * (C) 2004 Germain Garand (germain@ebooksfrance.org) - * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * (C) 2006 Charles Samuels (charles@kde.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. - * - */ - -//#define DEBUG -//#define DEBUG_LAYOUT -//#define BOX_DEBUG -//#define FLOAT_DEBUG -//#define PAGE_DEBUG - -#include <kdebug.h> -#include "rendering/render_text.h" -#include "rendering/render_table.h" -#include "rendering/render_canvas.h" -#include "rendering/render_layer.h" -#include "rendering/render_block.h" - -#include "xml/dom_nodeimpl.h" -#include "xml/dom_docimpl.h" -#include "html/html_formimpl.h" -#include "misc/htmltags.h" - -#include "khtmlview.h" - -using namespace DOM; - -namespace khtml { - -// ------------------------------------------------------------------------------------------------------- - -// Our MarginInfo state used when laying out block children. -RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) -{ - // Whether or not we can collapse our own margins with our children. We don't do this - // if we had any border/padding (obviously), if we're the root or HTML elements, or if - // we're positioned, floating, a table cell. - m_canCollapseWithChildren = !block->isCanvas() && !block->isRoot() && !block->isPositioned() && - !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable(); - - m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) /*&& block->style()->marginTopCollapse() != MSEPARATE */; - - // If any height other than auto is specified in CSS, then we don't collapse our bottom - // margins with our children's margins. To do otherwise would be to risk odd visual - // effects when the children overflow out of the parent block and yet still collapse - // with it. We also don't collapse if we have any bottom border/padding. - m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) && - (block->style()->height().isVariable() && block->style()->height().value() == 0) /*&& block->style()->marginBottomCollapse() != MSEPARATE*/; - - m_quirkContainer = block->isTableCell() || block->isBody() /*|| block->style()->marginTopCollapse() == MDISCARD || - block->style()->marginBottomCollapse() == MDISCARD*/; - - m_atTopOfBlock = true; - m_atBottomOfBlock = false; - - m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0; - m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0; - - m_selfCollapsingBlockClearedFloat = false; - - m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false; -} - -// ------------------------------------------------------------------------------------------------------- - -RenderBlock::RenderBlock(DOM::NodeImpl* node) - : RenderFlow(node) -{ - m_childrenInline = true; - m_floatingObjects = 0; - m_positionedObjects = 0; - m_firstLine = false; - m_avoidPageBreak = false; - m_clearStatus = CNONE; - m_maxTopPosMargin = m_maxTopNegMargin = m_maxBottomPosMargin = m_maxBottomNegMargin = 0; - m_topMarginQuirk = m_bottomMarginQuirk = false; - m_overflowHeight = m_overflowWidth = 0; - m_overflowLeft = m_overflowTop = 0; -} - -RenderBlock::~RenderBlock() -{ - delete m_floatingObjects; - delete m_positionedObjects; -} - -void RenderBlock::setStyle(RenderStyle* _style) -{ - setReplaced(_style->isDisplayReplacedType()); - - RenderFlow::setStyle(_style); - - // ### we could save this call when the change only affected - // non inherited properties - RenderObject *child = firstChild(); - while (child != 0) - { - if (child->isAnonymousBlock()) - { - RenderStyle* newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(BLOCK); - child->setStyle(newStyle); - } - child = child->nextSibling(); - } - - if (attached()) { - // Update generated content and ::inside - updateReplacedContent(); - // Update pseudos for :before and :after - updatePseudoChildren(); - } - - // handled by close() during parsing - // ### remove close move upto updatePseudo - if (!document()->parsing()) { - updateFirstLetter(); - } -} - -// Attach handles initial setStyle that requires parent nodes -void RenderBlock::attach() -{ - RenderFlow::attach(); - - updateReplacedContent(); - updatePseudoChildren(); -} - -void RenderBlock::updateFirstLetter() -{ - // Only blocks with inline-children can generate a first-letter - if (!childrenInline() || !firstChild()) return; - - // Don't recurse - if (style()->styleType() == RenderStyle::FIRST_LETTER) return; - - // The first-letter style is inheritable. - RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LETTER); - RenderObject *o = this; - while (o && !pseudoStyle) { - // ### We should ignore empty preceding siblings - if (o->parent() && o->parent()->firstChild() == this) - o = o->parent(); - else - break; - pseudoStyle = o->style()->getPseudoStyle(RenderStyle::FIRST_LETTER); - }; - - // FIXME: Currently we don't delete first-letters, this is - // handled instead in NodeImpl::diff by issuing Detach on first-letter changes. - if (!pseudoStyle) { - return; - } - - // Drill into inlines looking for our first text child. - RenderObject* firstText = firstChild(); - while (firstText && firstText->needsLayout() && !firstText->isFloating() && !firstText->isRenderBlock() && !firstText->isReplaced() && !firstText->isText()) - // ### We should skip first children with only white-space and punctuation - firstText = firstText->firstChild(); - - if (firstText && firstText->isText() && !firstText->isBR()) { - RenderObject* firstLetterObject = 0; - // Find the old first-letter - if (firstText->parent()->style()->styleType() == RenderStyle::FIRST_LETTER) - firstLetterObject = firstText->parent(); - - // Force inline display (except for floating first-letters) - pseudoStyle->setDisplay( pseudoStyle->isFloating() ? BLOCK : INLINE); - pseudoStyle->setPosition( STATIC ); // CSS2 says first-letter can't be positioned. - - if (firstLetterObject != 0) { - firstLetterObject->setStyle( pseudoStyle ); - RenderStyle* newStyle = new RenderStyle(); - newStyle->inheritFrom( pseudoStyle ); - firstText->setStyle( newStyle ); - return; - } - - RenderText* textObj = static_cast<RenderText*>(firstText); - RenderObject* firstLetterContainer = firstText->parent(); - - firstLetterObject = RenderFlow::createFlow(node(), pseudoStyle, renderArena() ); - firstLetterObject->setIsAnonymous( true ); - firstLetterContainer->addChild(firstLetterObject, firstLetterContainer->firstChild()); - - // if this object is the result of a :begin, then the text may have not been - // generated yet if it is a counter - if (textObj->recalcMinMax()) - textObj->recalcMinMaxWidths(); - - // The original string is going to be either a generated content string or a DOM node's - // string. We want the original string before it got transformed in case first-letter has - // no text-transform or a different text-transform applied to it. - DOMStringImpl* oldText = textObj->originalString(); - if (!oldText) - oldText = textObj->string(); - // ### In theory a first-letter can stretch across multiple text objects, if they only contain - // punctuation and white-space - if(oldText->l >= 1) { - oldText->ref(); - // begin: we need skip leading whitespace so that RenderBlock::findNextLineBreak - // won't think we're continuing from a previous run - unsigned int begin = 0; // the position that first-letter begins - unsigned int length = 0; // the position that "the rest" begins - while ( length < oldText->l && (oldText->s+length)->isSpace() ) - length++; - begin = length; - while ( length < oldText->l && - ( (oldText->s+length)->isPunct()) || (oldText->s+length)->isSpace() ) - length++; - if ( length < oldText->l && - !( (oldText->s+length)->isSpace() || (oldText->s+length)->isPunct() )) - length++; - while ( length < oldText->l && (oldText->s+length)->isMark() ) - length++; - - // we need to generated a remainingText object even if no text is left - // because it holds the place and style for the old textObj - RenderTextFragment* remainingText = - new (renderArena()) RenderTextFragment(textObj->node(), oldText, length, oldText->l-length); - remainingText->setIsAnonymous( textObj->isAnonymous() ); - remainingText->setStyle(textObj->style()); - if (remainingText->element()) - remainingText->element()->setRenderer(remainingText); - - RenderObject* nextObj = textObj->nextSibling(); - textObj->detach(); - firstLetterContainer->addChild(remainingText, nextObj); - - RenderTextFragment* letter = - new (renderArena()) RenderTextFragment(remainingText->node(), oldText, begin, length-begin); - letter->setIsAnonymous( remainingText->isAnonymous() ); - RenderStyle* newStyle = new RenderStyle(); - newStyle->inheritFrom(pseudoStyle); - letter->setStyle(newStyle); - firstLetterObject->addChild(letter); - oldText->deref(); - } - firstLetterObject->close(); - } -} - -void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) -{ - // Make sure we don't append things after :after-generated content if we have it. - if ( !beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER ) - beforeChild = lastChild(); - - bool madeBoxesNonInline = false; - - // If the requested beforeChild is not one of our children, then this is most likely because - // there is an anonymous block box within this object that contains the beforeChild. So - // just insert the child into the anonymous block box instead of here. This may also be - // needed in cases of things like anonymous tables. - if (beforeChild && beforeChild->parent() != this) { - - KHTMLAssert(beforeChild->parent()); - - // In the special case where we are prepending a block-level element before - // something contained inside an anonymous block, we can just prepend it before - // the anonymous block. - if (!newChild->isInline() && beforeChild->parent()->isAnonymousBlock() && - beforeChild->parent()->parent() == this && - beforeChild->parent()->firstChild() == beforeChild) - return addChildToFlow(newChild, beforeChild->parent()); - - // Otherwise find our kid inside which the beforeChild is, and delegate to it. - // This may be many levels deep due to anonymous tables, table sections, etc. - RenderObject* responsible = beforeChild->parent(); - while (responsible->parent() != this) - responsible = responsible->parent(); - - return responsible->addChild(newChild,beforeChild); - } - - // prevent elements that haven't received a layout yet from getting painted by pushing - // them far above the top of the page - if (!newChild->isInline()) - newChild->setPos(newChild->xPos(), -500000); - - if (!newChild->isText() && newChild->style()->position() != STATIC) - setOverhangingContents(); - - // A block has to either have all of its children inline, or all of its children as blocks. - // So, if our children are currently inline and a block child has to be inserted, we move all our - // inline children into anonymous block boxes - if ( m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned() ) - { - // This is a block with inline content. Wrap the inline content in anonymous blocks. - makeChildrenNonInline(beforeChild); - madeBoxesNonInline = true; - - if (beforeChild && beforeChild->parent() != this) { - beforeChild = beforeChild->parent(); - KHTMLAssert(beforeChild->isAnonymousBlock()); - KHTMLAssert(beforeChild->parent() == this); - } - } - else if (!m_childrenInline && !newChild->isFloatingOrPositioned()) - { - // If we're inserting an inline child but all of our children are blocks, then we have to make sure - // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise - // a new one is created and inserted into our list of children in the appropriate position. - if (newChild->isInline()) { - if (beforeChild) { - if ( beforeChild->previousSibling() && beforeChild->previousSibling()->isAnonymousBlock() ) { - beforeChild->previousSibling()->addChild(newChild); - return; - } - } - else { - if ( m_last && m_last->isAnonymousBlock() ) { - m_last->addChild(newChild); - return; - } - } - - // no suitable existing anonymous box - create a new one - RenderBlock* newBox = createAnonymousBlock(); - RenderBox::addChild(newBox,beforeChild); - newBox->addChild(newChild); - - //the above may actually destroy newBox in case an anonymous - //table got created, and made the anonymous block redundant. - //so look up what to hide indirectly. - RenderObject* toHide = newChild; - while (toHide->parent() != this) - toHide = toHide->parent(); - - toHide->setPos(toHide->xPos(), -500000); - return; - } - else { - // We are adding another block child... if the current last child is an anonymous box - // then it needs to be closed. - // ### get rid of the closing thing altogether this will only work during initial parsing - if (lastChild() && lastChild()->isAnonymous()) { - lastChild()->close(); - } - } - } - - RenderBox::addChild(newChild,beforeChild); - // ### care about aligned stuff - - if ( madeBoxesNonInline ) - removeLeftoverAnonymousBoxes(); -} - -static void getInlineRun(RenderObject* start, RenderObject* stop, - RenderObject*& inlineRunStart, - RenderObject*& inlineRunEnd) -{ - // Beginning at |start| we find the largest contiguous run of inlines that - // we can. We denote the run with start and end points, |inlineRunStart| - // and |inlineRunEnd|. Note that these two values may be the same if - // we encounter only one inline. - // - // We skip any non-inlines we encounter as long as we haven't found any - // inlines yet. - // - // |stop| indicates a non-inclusive stop point. Regardless of whether |stop| - // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered - // a non-inline. - - RenderObject * curr = start; - bool sawInline; - do { - while (curr && !(curr->isInline() || curr->isFloatingOrPositioned())) - curr = curr->nextSibling(); - - inlineRunStart = inlineRunEnd = curr; - - if (!curr) - return; // No more inline children to be found. - - sawInline = curr->isInline(); - - curr = curr->nextSibling(); - while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != stop)) { - inlineRunEnd = curr; - if (curr->isInline()) - sawInline = true; - curr = curr->nextSibling(); - } - } while (!sawInline); - -} - -void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) -{ - // makeChildrenNonInline takes a block whose children are *all* inline and it - // makes sure that inline children are coalesced under anonymous - // blocks. If |insertionPoint| is defined, then it represents the insertion point for - // the new block child that is causing us to have to wrap all the inlines. This - // means that we cannot coalesce inlines before |insertionPoint| with inlines following - // |insertionPoint|, because the new child is going to be inserted in between the inlines, - // splitting them. - KHTMLAssert(isReplacedBlock() || !isInline()); - KHTMLAssert(!insertionPoint || insertionPoint->parent() == this); - - m_childrenInline = false; - - RenderObject *child = firstChild(); - - while (child) { - RenderObject *inlineRunStart, *inlineRunEnd; - getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd); - - if (!inlineRunStart) - break; - - child = inlineRunEnd->nextSibling(); - - RenderBlock* box = createAnonymousBlock(); - insertChildNode(box, inlineRunStart); - RenderObject* o = inlineRunStart; - while(o != inlineRunEnd) - { - RenderObject* no = o; - o = no->nextSibling(); - box->appendChildNode(removeChildNode(no)); - } - box->appendChildNode(removeChildNode(inlineRunEnd)); - box->close(); - box->setPos(box->xPos(), -500000); - } -} - -void RenderBlock::makePageBreakAvoidBlocks() -{ - KHTMLAssert(!childrenInline()); - KHTMLAssert(canvas()->pagedMode()); - - RenderObject *breakAfter = firstChild(); - RenderObject *breakBefore = breakAfter ? breakAfter->nextSibling() : 0; - - RenderBlock* pageRun = 0; - - // ### Should follow margin-collapsing rules, skipping self-collapsing blocks - // and exporting page-breaks from first/last child when collapsing with parent margin. - while (breakAfter) { - if (breakAfter->isRenderBlock() && !breakAfter->childrenInline()) - static_cast<RenderBlock*>(breakAfter)->makePageBreakAvoidBlocks(); - EPageBreak pbafter = breakAfter->style()->pageBreakAfter(); - EPageBreak pbbefore = breakBefore ? breakBefore->style()->pageBreakBefore() : PBALWAYS; - if ((pbafter == PBAVOID && pbbefore == PBAVOID) || - (pbafter == PBAVOID && pbbefore == PBAUTO) || - (pbafter == PBAUTO && pbbefore == PBAVOID)) - { - if (!pageRun) { - pageRun = createAnonymousBlock(); - pageRun->m_avoidPageBreak = true; - pageRun->setChildrenInline(false); - } - pageRun->appendChildNode(removeChildNode(breakAfter)); - } else - { - if (pageRun) { - pageRun->appendChildNode(removeChildNode(breakAfter)); - pageRun->close(); - insertChildNode(pageRun, breakBefore); - pageRun = 0; - } - } - breakAfter = breakBefore; - breakBefore = breakBefore ? breakBefore->nextSibling() : 0; - } - - // recurse into positioned block children as well. - if (m_positionedObjects) { - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - for ( ; it.current(); ++it ) { - if (it.current()->isRenderBlock() && !it.current()->childrenInline()) { - static_cast<RenderBlock*>(it.current())->makePageBreakAvoidBlocks(); - } - } - } - - // recurse into floating block children. - if (m_floatingObjects) { - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; it.current(); ++it ) { - if (it.current()->node->isRenderBlock() && !it.current()->node->childrenInline()) { - static_cast<RenderBlock*>(it.current()->node)->makePageBreakAvoidBlocks(); - } - } - } -} - -void RenderBlock::removeChild(RenderObject *oldChild) -{ - // If this child is a block, and if our previous and next siblings are - // both anonymous blocks with inline content, then we can go ahead and - // fold the inline content back together. - RenderObject* prev = oldChild->previousSibling(); - RenderObject* next = oldChild->nextSibling(); - bool mergedBlocks = false; - if (document()->renderer() && !isInline() && !oldChild->isInline() && !oldChild->continuation() && - prev && prev->isAnonymousBlock() && prev->childrenInline() && - next && next->isAnonymousBlock() && next->childrenInline()) { - // Take all the children out of the |next| block and put them in - // the |prev| block. - RenderObject* o = next->firstChild(); - while (o) { - RenderObject* no = o; - o = no->nextSibling(); - prev->appendChildNode(next->removeChildNode(no)); - no->setNeedsLayoutAndMinMaxRecalc(); - } - prev->setNeedsLayoutAndMinMaxRecalc(); - - // Nuke the now-empty block. - next->detach(); - - mergedBlocks = true; - } - - RenderFlow::removeChild(oldChild); - - if (mergedBlocks && prev && !prev->previousSibling() && !prev->nextSibling()) { - // The remerge has knocked us down to containing only a single anonymous - // box. We can go ahead and pull the content right back up into our - // box. - RenderObject* anonBlock = removeChildNode(prev); - m_childrenInline = true; - RenderObject* o = anonBlock->firstChild(); - while (o) { - RenderObject* no = o; - o = no->nextSibling(); - appendChildNode(anonBlock->removeChildNode(no)); - no->setNeedsLayoutAndMinMaxRecalc(); - } - - // Nuke the now-empty block. - anonBlock->detach(); - } -} - -bool RenderBlock::isSelfCollapsingBlock() const -{ - // We are not self-collapsing if we - // (a) have a non-zero height according to layout (an optimization to avoid wasting time) - // (b) are a table, - // (c) have border/padding, - // (d) have a min-height - if (m_height > 0 || - isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || - style()->minHeight().value() > 0) - return false; - - bool hasAutoHeight = style()->height().isVariable(); - if (style()->height().isPercent() && !style()->htmlHacks()) { - hasAutoHeight = true; - for (RenderBlock* cb = containingBlock(); !cb->isCanvas(); cb = cb->containingBlock()) { - if (cb->style()->height().isFixed() || cb->isTableCell()) - hasAutoHeight = false; - } - } - - // If the height is 0 or auto, then whether or not we are a self-collapsing block depends - // on whether we have content that is all self-collapsing or not. - if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().value() == 0)) { - // If the block has inline children, see if we generated any line boxes. If we have any - // line boxes, then we can't be self-collapsing, since we have content. - if (childrenInline()) - return !firstLineBox(); - - // Whether or not we collapse is dependent on whether all our normal flow children - // are also self-collapsing. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isFloatingOrPositioned()) - continue; - if (!child->isSelfCollapsingBlock()) - return false; - } - return true; - } - return false; -} - -void RenderBlock::layout() -{ - // Table cells call layoutBlock directly, so don't add any logic here. Put code into - // layoutBlock(). - layoutBlock(false); -} - -void RenderBlock::layoutBlock(bool relayoutChildren) -{ - if (isInline() && !isReplacedBlock()) { - setNeedsLayout(false); - return; - } - // kdDebug( 6040 ) << renderName() << " " << this << "::layoutBlock() start" << endl; - // TQTime t; - // t.start(); - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - if (canvas()->pagedMode()) relayoutChildren = true; - - if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) { - // All we have to is lay out our positioned objects. - layoutPositionedObjects(relayoutChildren); - if (hasOverflowClip()) - m_layer->checkScrollbarsAfterLayout(); - setNeedsLayout(false); - return; - } - - if (markedForRepaint()) { - repaintDuringLayout(); - setMarkedForRepaint(false); - } - - int oldWidth = m_width; - - calcWidth(); - m_overflowWidth = m_width; - m_overflowLeft = 0; - if (style()->direction() == LTR ) - { - int cw=0; - if (style()->textIndent().isPercent()) - cw = containingBlock()->contentWidth(); - m_overflowLeft = kMin(0, style()->textIndent().minWidth(cw)); - } - - if ( oldWidth != m_width ) - relayoutChildren = true; - - // kdDebug( 6040 ) << floatingObjects << "," << oldWidth << "," - // << m_width << ","<< needsLayout() << "," << isAnonymousBox() << "," - // << overhangingContents() << "," << isPositioned() << endl; - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(RenderBlock) " << this << " ::layout() width=" << m_width << ", needsLayout=" << needsLayout() << endl; - if(containingBlock() == static_cast<RenderObject *>(this)) - kdDebug( 6040 ) << renderName() << ": containingBlock == this" << endl; -#endif - - clearFloats(); - - int previousHeight = m_height; - m_height = 0; - m_overflowHeight = 0; - m_clearStatus = CNONE; - - // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track - // our current maximal positive and negative margins. These values are used when we - // are collapsed with adjacent blocks, so for example, if you have block A and B - // collapsing together, then you'd take the maximal positive margin from both A and B - // and subtract it from the maximal negative margin from both A and B to get the - // true collapsed margin. This algorithm is recursive, so when we finish layout() - // our block knows its current maximal positive/negative values. - // - // Start out by setting our margin values to our current margins. Table cells have - // no margins, so we don't fill in the values for table cells. - if (!isTableCell()) { - initMaxMarginValues(); - - m_topMarginQuirk = style()->marginTop().isQuirk(); - m_bottomMarginQuirk = style()->marginBottom().isQuirk(); - - if (element() && element()->id() == ID_FORM && static_cast<HTMLFormElementImpl*>(element())->isMalformed()) - // See if this form is malformed (i.e., unclosed). If so, don't give the form - // a bottom margin. - m_maxBottomPosMargin = m_maxBottomNegMargin = 0; - } - - if (scrollsOverflow() && m_layer) { - // For overflow:scroll blocks, ensure we have both scrollbars in place always. - if (style()->overflowX() == OSCROLL) - m_layer->showScrollbar( Qt::Horizontal, true ); - if (style()->overflowY() == OSCROLL) - m_layer->showScrollbar( Qt::Vertical, true ); - } - - setContainsPageBreak(false); - - if (childrenInline()) - layoutInlineChildren( relayoutChildren ); - else - layoutBlockChildren( relayoutChildren ); - - // Expand our intrinsic height to encompass floats. - int toAdd = borderBottom() + paddingBottom(); - if (m_layer && scrollsOverflowX() && style()->height().isVariable()) - toAdd += m_layer->horizontalScrollbarHeight(); - if ( hasOverhangingFloats() && (isFloatingOrPositioned() || flowAroundFloats()) ) - m_overflowHeight = m_height = floatBottom() + toAdd; - - int oldHeight = m_height; - calcHeight(); - if (oldHeight != m_height) { - m_overflowHeight -= toAdd; - if (m_layer && scrollsOverflowY()) { - // overflow-height only includes padding-bottom when it scrolls - m_overflowHeight += paddingBottom(); - } - // If the block got expanded in size, then increase our overflowheight to match. - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; - } - if (previousHeight != m_height) - relayoutChildren = true; - - if (isTableCell()) { - // Table cells need to grow to accommodate both overhanging floats and - // blocks that have overflowed content. - // Check for an overhanging float first. - // FIXME: This needs to look at the last flow, not the last child. - if (lastChild() && lastChild()->hasOverhangingFloats() && !lastChild()->hasOverflowClip()) { - KHTMLAssert(lastChild()->isRenderBlock()); - m_height = lastChild()->yPos() + static_cast<RenderBlock*>(lastChild())->floatBottom(); - m_height += borderBottom() + paddingBottom(); - } - - if (m_overflowHeight > m_height && !hasOverflowClip()) - m_height = m_overflowHeight + borderBottom() + paddingBottom(); - } - - if( hasOverhangingFloats() && ((isFloating() && style()->height().isVariable()) || isTableCell())) { - m_height = floatBottom(); - m_height += borderBottom() + paddingBottom(); - } - - if (canvas()->pagedMode()) { -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << " Page Bottom: " << pageTopAfter(0) << endl; - kdDebug(6040) << renderName() << " Bottom: " << m_height << endl; -#endif - bool needsPageBreak = false; - int xpage = crossesPageBreak(0, m_height); - if (xpage) { - needsPageBreak = true; -#ifdef PAGE_DEBUG - kdDebug( 6040 ) << renderName() << " crosses to page " << xpage << endl; -#endif - } - if (needsPageBreak && !containsPageBreak()) { - setNeedsPageClear(true); -#ifdef PAGE_DEBUG - kdDebug( 6040 ) << renderName() << " marked for page-clear" << endl; -#endif - } - } - - layoutPositionedObjects( relayoutChildren ); - - // Always ensure our overflow width/height are at least as large as our width/height. - m_overflowWidth = kMax(m_overflowWidth, (int)m_width); - m_overflowHeight = kMax(m_overflowHeight, m_height); - - // Update our scrollbars if we're overflow:auto/scroll now that we know if - // we overflow or not. - if (hasOverflowClip() && m_layer) - m_layer->checkScrollbarsAfterLayout(); - - setNeedsLayout(false); -} - -void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo) -{ - if (child->isBox() && child->hasStaticX()) { - if (style()->direction() == LTR) - static_cast<RenderBox*>(child)->setStaticX(borderLeft() + paddingLeft()); - else - static_cast<RenderBox*>(child)->setStaticX(borderRight() + paddingRight()); - } - - if (child->isBox() && child->hasStaticY()) { - int y = m_height; - if (!marginInfo.canCollapseWithTop()) { - child->calcVerticalMargins(); - int marginTop = child->marginTop(); - int collapsedTopPos = marginInfo.posMargin(); - int collapsedTopNeg = marginInfo.negMargin(); - if (marginTop > 0) { - if (marginTop > collapsedTopPos) - collapsedTopPos = marginTop; - } else { - if (-marginTop > collapsedTopNeg) - collapsedTopNeg = -marginTop; - } - y += (collapsedTopPos - collapsedTopNeg) - marginTop; - } - static_cast<RenderBox*>(child)->setStaticY(y); - } -} - -void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) -{ - // The float should be positioned taking into account the bottom margin - // of the previous flow. We add that margin into the height, get the - // float positioned properly, and then subtract the margin out of the - // height again. In the case of self-collapsing blocks, we always just - // use the top margins, since the self-collapsing block collapsed its - // own bottom margin into its top margin. - // - // Note also that the previous flow may collapse its margin into the top of - // our block. If this is the case, then we do not add the margin in to our - // height when computing the position of the float. This condition can be tested - // for by simply calling canCollapseWithTop. See - // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for - // an example of this scenario. - int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); - m_height += marginOffset; - positionNewFloats(); - m_height -= marginOffset; -} - -RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled) -{ - // Handle positioned children first. - RenderObject* next = handlePositionedChild(child, marginInfo, handled); - if (handled) return next; - - // Handle floating children next. - next = handleFloatingChild(child, marginInfo, handled); - if (handled) return next; - - // See if we have a compact element. If we do, then try to tuck the compact element into the margin space of the next block. - next = handleCompactChild(child, compactInfo, marginInfo, handled); - if (handled) return next; - - // Finally, see if we have a run-in element. - return handleRunInChild(child, handled); -} - -RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) -{ - if (child->isPositioned()) { - handled = true; - child->containingBlock()->insertPositionedObject(child); - adjustPositionedBlock(child, marginInfo); - return child->nextSibling(); - } - return 0; -} - -RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) -{ - if (child->isFloating()) { - handled = true; - insertFloatingObject(child); - adjustFloatingBlock(marginInfo); - return child->nextSibling(); - } - return 0; -} - -static inline bool isAnonymousWhitespace( RenderObject* o ) { - if (!o->isAnonymous()) - return false; - RenderObject *fc = o->firstChild(); - return fc && fc == o->lastChild() && fc->isText() && static_cast<RenderText *>(fc)->stringLength() == 1 && - static_cast<RenderText *>(fc)->text()[0].unicode() == ' '; -} - -RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, const MarginInfo& marginInfo, bool& handled) -{ - // FIXME: We only deal with one compact at a time. It is unclear what should be - // done if multiple contiguous compacts are encountered. For now we assume that - // compact A followed by another compact B should simply be treated as block A. - if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) { - // Get the next non-positioned/non-floating RenderBlock. - RenderObject* next = child->nextSibling(); - RenderObject* curr = next; - while (curr && (curr->isFloatingOrPositioned() || isAnonymousWhitespace(curr)) ) - curr = curr->nextSibling(); - if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) { - curr->calcWidth(); // So that horizontal margins are correct. - // Need to compute margins for the child as though it is a block. - child->style()->setDisplay(BLOCK); - child->calcWidth(); - child->style()->setDisplay(COMPACT); - - int childMargins = child->marginLeft() + child->marginRight(); - int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight(); - if (margin >= (childMargins + child->maxWidth())) { - // The compact will fit in the margin. - handled = true; - compactInfo.set(child, curr); - child->layoutIfNeeded(); - int off = marginInfo.margin(); - m_height += off + curr->marginTop() < child->marginTop() ? - child->marginTop() - curr->marginTop() -off: 0; - - child->setPos(0,0); // This position will be updated to reflect the compact's - // desired position and the line box for the compact will - // pick that position up. - return next; - } - } - } - return 0; -} - -void RenderBlock::adjustSizeForCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo) -{ - // if the compact is bigger than the block it was run into - // then "this" block should take the height of the compact - if (compactInfo.matches(child)) { - // We have a compact child to squeeze in. - RenderObject* compactChild = compactInfo.compact(); - if (compactChild->height() > child->height()) - m_height += compactChild->height() - child->height(); - } -} - -void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo) -{ - if (compactInfo.matches(child)) { - // We have a compact child to squeeze in. - RenderObject* compactChild = compactInfo.compact(); - int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft(); - if (style()->direction() == RTL) { - compactChild->calcWidth(); // have to do this because of the capped maxwidth - compactXPos = width() - borderRight() - paddingRight() - - compactChild->width() - compactChild->marginRight(); - } - - int compactYPos = child->yPos() + child->borderTop() + child->paddingTop() - - compactChild->paddingTop() - compactChild->borderTop(); - int adj = 0; - KHTMLAssert(child->isRenderBlock()); - InlineRunBox *b = static_cast<RenderBlock*>(child)->firstLineBox(); - InlineRunBox *c = static_cast<RenderBlock*>(compactChild)->firstLineBox(); - if (b && c) { - // adjust our vertical position - int vpos = compactChild->getVerticalPosition( true, child ); - if (vpos == PositionBottom) - adj = b->height() > c->height() ? (b->height() + b->yPos() - c->height() - c->yPos()) : 0; - else if (vpos == PositionTop) - adj = b->yPos() - c->yPos(); - else - adj = vpos; - compactYPos += adj; - } - Length newLineHeight( kMax(compactChild->lineHeight(true)+adj, (int)child->lineHeight(true)), khtml::Fixed); - child->style()->setLineHeight( newLineHeight ); - child->setNeedsLayout( true, false ); - child->layout(); - - compactChild->setPos(compactXPos, compactYPos); // Set the x position. - compactInfo.clear(); - } -} - -RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled) -{ - // See if we have a run-in element with inline children. If the - // children aren't inline, then just treat the run-in as a normal - // block. - if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) { - // Get the next non-positioned/non-floating RenderBlock. - RenderObject* curr = child->nextSibling(); - while (curr && (curr->isFloatingOrPositioned() || isAnonymousWhitespace(curr)) ) - curr = curr->nextSibling(); - if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) { - // The block acts like an inline, so just null out its - // position. - handled = true; - child->setInline(true); - child->setPos(0,0); - - // Remove the child. - RenderObject* next = child->nextSibling(); - removeChildNode(child); - - // Now insert the child under |curr|. - curr->insertChildNode(child, curr->firstChild()); - return next; - } - } - return 0; -} - -void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate) -{ - // Get our max pos and neg top margins. - int posTop = child->maxTopMargin(true); - int negTop = child->maxTopMargin(false); - - // For self-collapsing blocks, collapse our bottom margins into our - // top to get new posTop and negTop values. - if (child->isSelfCollapsingBlock()) { - posTop = kMax(posTop, (int)child->maxBottomMargin(true)); - negTop = kMax(negTop, (int)child->maxBottomMargin(false)); - } - - // See if the top margin is quirky. We only care if this child has - // margins that will collapse with us. - bool topQuirk = child->isTopMarginQuirk() /*|| style()->marginTopCollapse() == MDISCARD*/; - - if (marginInfo.canCollapseWithTop()) { - // This child is collapsing with the top of the - // block. If it has larger margin values, then we need to update - // our own maximal values. - if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) { - m_maxTopPosMargin = kMax(posTop, (int)m_maxTopPosMargin); - m_maxTopNegMargin = kMax(negTop, (int)m_maxTopNegMargin); - } - - // The minute any of the margins involved isn't a quirk, don't - // collapse it away, even if the margin is smaller (www.webreference.com - // has an example of this, a <dt> with 0.8em author-specified inside - // a <dl> inside a <td>. - if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) { - m_topMarginQuirk = false; - marginInfo.setDeterminedTopQuirk(true); - } - - if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0) - // We have no top margin and our top child has a quirky margin. - // We will pick up this quirky margin and pass it through. - // This deals with the <td><div><p> case. - // Don't do this for a block that split two inlines though. You do - // still apply margins in this case. - m_topMarginQuirk = true; - } - - if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) - marginInfo.setTopQuirk(topQuirk); - - int ypos = m_height; - if (child->isSelfCollapsingBlock()) { - // This child has no height. We need to compute our - // position before we collapse the child's margins together, - // so that we can get an accurate position for the zero-height block. - int collapsedTopPos = kMax(marginInfo.posMargin(), (int)child->maxTopMargin(true)); - int collapsedTopNeg = kMax(marginInfo.negMargin(), (int)child->maxTopMargin(false)); - marginInfo.setMargin(collapsedTopPos, collapsedTopNeg); - - // Now collapse the child's margins together, which means examining our - // bottom margin values as well. - marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true)); - marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false)); - - if (!marginInfo.canCollapseWithTop()) - // We need to make sure that the position of the self-collapsing block - // is correct, since it could have overflowing content - // that needs to be positioned correctly (e.g., a block that - // had a specified height of 0 but that actually had subcontent). - ypos = m_height + collapsedTopPos - collapsedTopNeg; - } - else { -#ifdef APPLE_CHANGES - if (child->style()->marginTopCollapse() == MSEPARATE) { - m_height += marginInfo.margin() + child->marginTop(); - ypos = m_height; - } - else -#endif - if (!marginInfo.atTopOfBlock() || - (!marginInfo.canCollapseTopWithChildren() - && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { - // We're collapsing with a previous sibling's margins and not - // with the top of the block. - m_height += kMax(marginInfo.posMargin(), posTop) - kMax(marginInfo.negMargin(), negTop); - ypos = m_height; - } - - marginInfo.setPosMargin(child->maxBottomMargin(true)); - marginInfo.setNegMargin(child->maxBottomMargin(false)); - - if (marginInfo.margin()) - marginInfo.setBottomQuirk(child->isBottomMarginQuirk() /*|| style()->marginBottomCollapse() == MDISCARD*/); - - marginInfo.setSelfCollapsingBlockClearedFloat(false); - } - - child->setPos(child->xPos(), ypos); - if (ypos != yPosEstimate) { - if (child->style()->width().isPercent() && child->usesLineWidth()) - // The child's width is a percentage of the line width. - // When the child shifts to clear an item, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true); - - if (!child->flowAroundFloats() && child->hasFloats()) - child->markAllDescendantsWithFloatsForLayout(); - - // Our guess was wrong. Make the child lay itself out again. - child->layoutIfNeeded(); - } -} - -void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin) -{ - int heightIncrease = getClearDelta(child); - if (heightIncrease) { - // The child needs to be lowered. Move the child so that it just clears the float. - child->setPos(child->xPos(), child->yPos() + heightIncrease); - - // Increase our height by the amount we had to clear. - bool selfCollapsing = child->isSelfCollapsingBlock(); - if (!selfCollapsing) - m_height += heightIncrease; - else { - // For self-collapsing blocks that clear, they may end up collapsing - // into the bottom of the parent block. We simulate this behavior by - // setting our positive margin value to compensate for the clear. - marginInfo.setPosMargin(kMax(0, child->yPos() - m_height)); - marginInfo.setNegMargin(0); - marginInfo.setSelfCollapsingBlockClearedFloat(true); - } - - if (marginInfo.canCollapseWithTop()) { - // We can no longer collapse with the top of the block since a clear - // occurred. The empty blocks collapse into the cleared block. - // FIXME: This isn't quite correct. Need clarification for what to do - // if the height the cleared block is offset by is smaller than the - // margins involved. - m_maxTopPosMargin = oldTopPosMargin; - m_maxTopNegMargin = oldTopNegMargin; - marginInfo.setAtTopOfBlock(false); - } - - // If our value of clear caused us to be repositioned vertically to be - // underneath a float, we might have to do another layout to take into account - // the extra space we now have available. - if (!selfCollapsing && !child->style()->width().isFixed() && child->usesLineWidth()) - // The child's width is a percentage of the line width. - // When the child shifts to clear an item, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true); - if (!child->flowAroundFloats() && child->hasFloats()) - child->markAllDescendantsWithFloatsForLayout(); - child->layoutIfNeeded(); - } -} - -bool RenderBlock::canClear(RenderObject *child, PageBreakLevel level) -{ - KHTMLAssert(child->parent() && child->parent() == this); - KHTMLAssert(canvas()->pagedMode()); - - // Positioned elements cannot be moved. Only normal flow and floating. - if (child->isPositioned() || child->isRelPositioned()) return false; - - switch(level) { - case PageBreakNormal: - // check page-break-inside: avoid - if (!style()->pageBreakInside()) - // we cannot, but can our parent? - if(!parent()->canClear(this, level)) return false; - case PageBreakHarder: - // check page-break-after/before: avoid - if (m_avoidPageBreak) - // we cannot, but can our parent? - if(!parent()->canClear(this, level)) return false; - case PageBreakForced: - // child is larger than page-height and is forced to break - if(child->height() > canvas()->pageHeight()) return false; - return true; - } - assert(false); - return false; -} - -void RenderBlock::clearPageBreak(RenderObject* child, int pageBottom) -{ - KHTMLAssert(child->parent() && child->parent() == this); - KHTMLAssert(canvas()->pagedMode()); - - if (child->yPos() >= pageBottom) return; - - int heightIncrease = 0; - - heightIncrease = pageBottom - child->yPos(); - - // ### should never happen, canClear should have been called to detect it. - if (child->height() > canvas()->pageHeight()) { - kdDebug(6040) << "### child is too large to clear: " << child->height() << " > " << canvas()->pageHeight() << endl; - return; - } - - // The child needs to be lowered. Move the child so that it just clears the break. - child->setPos(child->xPos(), pageBottom); - -#ifdef PAGE_DEBUG - kdDebug(6040) << "Cleared block " << heightIncrease << "px" << endl; -#endif - - // Increase our height by the amount we had to clear. - m_height += heightIncrease; - - // We might have to do another layout to take into account - // the extra space we now have available. - if (!child->style()->width().isFixed() && child->usesLineWidth()) - // The child's width is a percentage of the line width. - // When the child shifts to clear a page-break, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true); - if (!child->flowAroundFloats() && child->hasFloats()) - child->markAllDescendantsWithFloatsForLayout(); - if (child->containsPageBreak()) - child->setNeedsLayout(true); - child->layoutIfNeeded(); - - child->setAfterPageBreak(true); -} - -int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo) -{ - // FIXME: We need to eliminate the estimation of vertical position, because - // when it's wrong we sometimes trigger a pathological relayout if there are - // intruding floats. - int yPosEstimate = m_height; - if (!marginInfo.canCollapseWithTop()) { - int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); - yPosEstimate += kMax(marginInfo.margin(), childMarginTop); - } - return yPosEstimate; -} - -void RenderBlock::determineHorizontalPosition(RenderObject* child) -{ - if (style()->direction() == LTR) { - int xPos = borderLeft() + paddingLeft(); - - // Add in our left margin. - int chPos = xPos + child->marginLeft(); - - // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need - // to shift over as necessary to dodge any floats that might get in the way. - if (child->flowAroundFloats()) { - int leftOff = leftOffset(m_height); - if (style()->textAlign() != KHTML_CENTER && !child->style()->marginLeft().isVariable()) { - if (child->marginLeft() < 0) - leftOff += child->marginLeft(); - chPos = kMax(chPos, leftOff); // Let the float sit in the child's margin if it can fit. - } - else if (leftOff != xPos) { - // The object is shifting right. The object might be centered, so we need to - // recalculate our horizontal margins. Note that the containing block content - // width computation will take into account the delta between |leftOff| and |xPos| - // so that we can just pass the content width in directly to the |calcHorizontalMargins| - // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); - chPos = leftOff + child->marginLeft(); - } - } - - child->setPos(chPos, child->yPos()); - } else { - int xPos = m_width - borderRight() - paddingRight(); - if (m_layer && scrollsOverflowY()) - xPos -= m_layer->verticalScrollbarWidth(); - int chPos = xPos - (child->width() + child->marginRight()); - if (child->flowAroundFloats()) { - int rightOff = rightOffset(m_height); - if (style()->textAlign() != KHTML_CENTER && !child->style()->marginRight().isVariable()) { - if (child->marginRight() < 0) - rightOff -= child->marginRight(); - chPos = kMin(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit. - } else if (rightOff != xPos) { - // The object is shifting left. The object might be centered, so we need to - // recalculate our horizontal margins. Note that the containing block content - // width computation will take into account the delta between |rightOff| and |xPos| - // so that we can just pass the content width in directly to the |calcHorizontalMargins| - // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); - chPos = rightOff - child->marginRight() - child->width(); - } - } - child->setPos(chPos, child->yPos()); - } -} - -void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) -{ - if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) { - // Update our max pos/neg bottom margins, since we collapsed our bottom margins - // with our children. - m_maxBottomPosMargin = kMax((int)m_maxBottomPosMargin, marginInfo.posMargin()); - m_maxBottomNegMargin = kMax((int)m_maxBottomNegMargin, marginInfo.negMargin()); - - if (!marginInfo.bottomQuirk()) - m_bottomMarginQuirk = false; - - if (marginInfo.bottomQuirk() && marginBottom() == 0) - // We have no bottom margin and our last child has a quirky margin. - // We will pick up this quirky margin and pass it through. - // This deals with the <td><div><p> case. - m_bottomMarginQuirk = true; - } -} - -void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo) -{ - // If our last flow was a self-collapsing block that cleared a float, then we don't - // collapse it with the bottom of the block. - if (!marginInfo.selfCollapsingBlockClearedFloat()) - marginInfo.setAtBottomOfBlock(true); - - // If we can't collapse with children then go ahead and add in the bottom margin. - if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() - && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) - m_height += marginInfo.margin(); - - // Now add in our bottom border/padding. - m_height += bottom; - - // Negative margins can cause our height to shrink below our minimal height (border/padding). - // If this happens, ensure that the computed height is increased to the minimal height. - m_height = kMax(m_height, top + bottom); - - // Always make sure our overflow height is at least our height. - m_overflowHeight = kMax(m_height, m_overflowHeight); - - // Update our bottom collapsed margin info. - setCollapsedBottomMargin(marginInfo); -} - -void RenderBlock::layoutBlockChildren( bool relayoutChildren ) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << " layoutBlockChildren( " << this <<" ), relayoutChildren="<< relayoutChildren << endl; -#endif - - int top = borderTop() + paddingTop(); - int bottom = borderBottom() + paddingBottom(); - if (m_layer && scrollsOverflowX() && style()->height().isVariable()) - bottom += m_layer->horizontalScrollbarHeight(); - - m_height = m_overflowHeight = top; - - // The margin struct caches all our current margin collapsing state. - // The compact struct caches state when we encounter compacts. - MarginInfo marginInfo(this, top, bottom); - CompactInfo compactInfo; - - // Fieldsets need to find their legend and position it inside the border of the object. - // The legend then gets skipped during normal layout. - RenderObject* legend = layoutLegend(relayoutChildren); - - PageBreakInfo pageBreakInfo(pageTopAfter(0)); - - RenderObject* child = firstChild(); - while( child != 0 ) - { - if (legend == child) { - child = child->nextSibling(); - continue; // Skip the legend, since it has already been positioned up in the fieldset's border. - } - - int oldTopPosMargin = m_maxTopPosMargin; - int oldTopNegMargin = m_maxTopNegMargin; - - // make sure we relayout children if we need it. - if (!child->isPositioned() && (relayoutChildren || - (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) || - (child->isRenderBlock() && child->style()->height().isPercent()) || - (child->isBody() && child->style()->htmlHacks()))) - { - child->setChildNeedsLayout(true); - } - - // Handle the four types of special elements first. These include positioned content, floating content, compacts and - // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. - bool handled = false; - RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled); - if (handled) { child = next; continue; } - - // The child is a normal flow object. Compute its vertical margins now. - child->calcVerticalMargins(); - -#ifdef APPLE_CHANGES /* margin-*-collapse not merged yet */ - // Do not allow a collapse if the margin top collapse style is set to SEPARATE. - if (child->style()->marginTopCollapse() == MSEPARATE) { - marginInfo.setAtTopOfBlock(false); - marginInfo.clearMargin(); - } -#endif - - // Try to guess our correct y position. In most cases this guess will - // be correct. Only if we're wrong (when we compute the real y position) - // will we have to potentially relayout. - int yPosEstimate = estimateVerticalPosition(child, marginInfo); - - // If an element might be affected by the presence of floats, then always mark it for - // layout. - if ( !child->flowAroundFloats() || child->usesLineWidth() ) { - int fb = floatBottom(); - if (fb > m_height || fb > yPosEstimate) - child->setChildNeedsLayout(true); - } - - // Go ahead and position the child as though it didn't collapse with the top. - child->setPos(child->xPos(), yPosEstimate); - child->layoutIfNeeded(); - - // Now determine the correct ypos based on examination of collapsing margin - // values. - collapseMargins(child, marginInfo, yPosEstimate); - - // Now check for clear. - clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin); - - // We are no longer at the top of the block if we encounter a non-empty child. - // This has to be done after checking for clear, so that margins can be reset if a clear occurred. - if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock()) - marginInfo.setAtTopOfBlock(false); - - // Now place the child in the correct horizontal position - determineHorizontalPosition(child); - - adjustSizeForCompactIfNeeded(child, compactInfo); - // Update our height now that the child has been placed in the correct position. - m_height += child->height(); - -#ifdef APPLE_CHANGES - if (child->style()->marginBottomCollapse() == MSEPARATE) { - m_height += child->marginBottom(); - marginInfo.clearMargin(); - } -#endif - - // Check for page-breaks - if (canvas()->pagedMode()) - clearChildOfPageBreaks(child, pageBreakInfo, marginInfo); - - if (child->hasOverhangingFloats() && !child->flowAroundFloats()) { - // need to add the child's floats to our floating objects list, but not in the case where - // overflow is auto/scroll - addOverHangingFloats( static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), true ); - } - - // See if this child has made our overflow need to grow. - int effX = child->effectiveXPos(); - int effY = child->effectiveYPos(); - m_overflowWidth = kMax(effX + child->effectiveWidth(), m_overflowWidth); - m_overflowLeft = kMin(effX, m_overflowLeft); - m_overflowHeight = kMax(effY + child->effectiveHeight(), m_overflowHeight); - m_overflowTop = kMin(effY, m_overflowTop); - - // Insert our compact into the block margin if we have one. - insertCompactIfNeeded(child, compactInfo); - - child = child->nextSibling(); - } - - // The last child had forced page-break-after - if (pageBreakInfo.forcePageBreak()) - m_height = pageBreakInfo.pageBottom(); - - // Now do the handling of the bottom of the block, adding in our bottom border/padding and - // determining the correct collapsed bottom margin information. - handleBottomOfBlock(top, bottom, marginInfo); - - setNeedsLayout(false); -} - -void RenderBlock::clearChildOfPageBreaks(RenderObject *child, PageBreakInfo &pageBreakInfo, MarginInfo &marginInfo) -{ - (void)marginInfo; - int childTop = child->yPos(); - int childBottom = child->yPos()+child->height(); -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << " ChildTop: " << childTop << " ChildBottom: " << childBottom << endl; -#endif - - bool forcePageBreak = pageBreakInfo.forcePageBreak() || child->style()->pageBreakBefore() == PBALWAYS; -#ifdef PAGE_DEBUG - if (forcePageBreak) - kdDebug(6040) << renderName() << "Forced break required" << endl; -#endif - - int xpage = crossesPageBreak(childTop, childBottom); - if (xpage || forcePageBreak) - { - if (!forcePageBreak && child->containsPageBreak() && !child->needsPageClear()) { -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << " Child contains page-break to page " << xpage << endl; -#endif - // ### Actually this assumes floating children are breaking/clearing - // nicely as well. - setContainsPageBreak(true); - } - else { - bool doBreak = true; - // don't break before the first child or when page-break-inside is avoid - if (!forcePageBreak && (!style()->pageBreakInside() || m_avoidPageBreak || child == firstChild())) { - if (parent()->canClear(this, (m_avoidPageBreak) ? PageBreakHarder : PageBreakNormal )) { -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << "Avoid page-break inside" << endl; -#endif - child->setNeedsPageClear(false); - setNeedsPageClear(true); - doBreak = false; - } -#ifdef PAGE_DEBUG - else - kdDebug(6040) << renderName() << "Ignoring page-break avoid" << endl; -#endif - } - if (doBreak) { -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << " Clearing child of page-break" << endl; - kdDebug(6040) << renderName() << " child top of page " << xpage << endl; -#endif - clearPageBreak(child, pageBreakInfo.pageBottom()); - child->setNeedsPageClear(false); - setContainsPageBreak(true); - } - } - pageBreakInfo.setPageBottom(pageBreakInfo.pageBottom() + canvas()->pageHeight()); - } - else - if (child->yPos() >= pageBreakInfo.pageBottom()) { - bool doBreak = true; -#ifdef PAGE_DEBUG - kdDebug(6040) << "Page-break between children" << endl; -#endif - if (!style()->pageBreakInside() || m_avoidPageBreak) { - if(parent()->canClear(this, (m_avoidPageBreak) ? PageBreakHarder : PageBreakNormal )) { -#ifdef PAGE_DEBUG - kdDebug(6040) << "Avoid page-break inside" << endl; -#endif - child->setNeedsPageClear(false); - setNeedsPageClear(true); - doBreak = false; - } -#ifdef PAGE_DEBUG - else - kdDebug(6040) << "Ignoring page-break avoid" << endl; -#endif - } - if (doBreak) { - // Break between children - setContainsPageBreak(true); - // ### Should collapse top-margin with page-margin - } - pageBreakInfo.setPageBottom(pageBreakInfo.pageBottom() + canvas()->pageHeight()); - } - - // Do we need a forced page-break before next child? - pageBreakInfo.setForcePageBreak(false); - if (child->style()->pageBreakAfter() == PBALWAYS) - pageBreakInfo.setForcePageBreak(true); -} - -void RenderBlock::layoutPositionedObjects(bool relayoutChildren) -{ - if (m_positionedObjects) { - //kdDebug( 6040 ) << renderName() << " " << this << "::layoutPositionedObjects() start" << endl; - RenderObject* r; - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - for ( ; (r = it.current()); ++it ) { - //kdDebug(6040) << " have a positioned object" << endl; - if (r->markedForRepaint()) { - r->repaintDuringLayout(); - r->setMarkedForRepaint(false); - } - if ( relayoutChildren || r->style()->position() == FIXED || - ((r->hasStaticY()||r->hasStaticX()) && r->parent() != this && r->parent()->isBlockFlow()) ) { - r->setChildNeedsLayout(true); - r->dirtyFormattingContext(false); - } - r->layoutIfNeeded(); - } - } -} - -void RenderBlock::paint(PaintInfo& pI, int _tx, int _ty) -{ - _tx += m_x; - _ty += m_y; - - // check if we need to do anything at all... - if (!isRoot() && !isInlineFlow() && !overhangingContents() && !isRelPositioned() && !isPositioned() ) - { - int h = m_overflowHeight; - int yPos = _ty; - if (m_floatingObjects && floatBottom() > h) - h = floatBottom(); - - yPos += overflowTop(); - - int os = maximalOutlineSize(pI.phase); - if( (yPos > pI.r.bottom() + os) || (_ty + h <= pI.r.y() - os)) - return; - } - - paintObject(pI, _tx, _ty); -} - -void RenderBlock::paintObject(PaintInfo& pI, int _tx, int _ty, bool shouldPaintOutline) -{ -#ifdef DEBUG_LAYOUT - //kdDebug( 6040 ) << renderName() << "(RenderBlock) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl; -#endif - - // If we're a repositioned run-in, don't paint background/borders. - bool inlineFlow = isInlineFlow(); - - // 1. paint background, borders etc - if (!inlineFlow && - (pI.phase == PaintActionElementBackground || pI.phase == PaintActionChildBackground ) && - shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) - paintBoxDecorations(pI, _tx, _ty); - - if ( pI.phase == PaintActionElementBackground ) - return; - if ( pI.phase == PaintActionChildBackgrounds ) - pI.phase = PaintActionChildBackground; - - // 2. paint contents - int scrolledX = _tx; - int scrolledY = _ty; - if (hasOverflowClip() && m_layer) - m_layer->subtractScrollOffset(scrolledX, scrolledY); - - if (childrenInline()) - paintLines(pI, scrolledX, scrolledY); - else { - for(RenderObject *child = firstChild(); child; child = child->nextSibling()) - if(!child->layer() && !child->isFloating()) - child->paint(pI, scrolledX, scrolledY); - } - - // 3. paint floats. - if (!inlineFlow && (pI.phase == PaintActionFloat || pI.phase == PaintActionSelection)) - paintFloats(pI, scrolledX, scrolledY, pI.phase == PaintActionSelection); - - // 4. paint outline. - if (shouldPaintOutline && !inlineFlow && pI.phase == PaintActionOutline && - style()->outlineWidth() && style()->visibility() == VISIBLE) - paintOutline(pI.p, _tx, _ty, width(), height(), style()); - -#ifdef BOX_DEBUG - if ( style() && style()->visibility() == VISIBLE ) { - if(isAnonymous()) - outlineBox(pI.p, _tx, _ty, "green"); - if(isFloating()) - outlineBox(pI.p, _tx, _ty, "yellow"); - else - outlineBox(pI.p, _tx, _ty); - } -#endif -} - -void RenderBlock::paintFloats(PaintInfo& pI, int _tx, int _ty, bool paintSelection) -{ - if (!m_floatingObjects) - return; - - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it) { - // Only paint the object if our noPaint flag isn't set. - if (r->node->isFloating() && !r->noPaint && !r->node->layer()) { - PaintAction oldphase = pI.phase; - if (paintSelection) { - pI.phase = PaintActionSelection; - r->node->paint(pI, _tx + r->left - r->node->xPos() + r->node->marginLeft(), - _ty + r->startY - r->node->yPos() + r->node->marginTop()); - } - else { - pI.phase = PaintActionElementBackground; - r->node->paint(pI, - _tx + r->left - r->node->xPos() + r->node->marginLeft(), - _ty + r->startY - r->node->yPos() + r->node->marginTop()); - pI.phase = PaintActionChildBackgrounds; - r->node->paint(pI, - _tx + r->left - r->node->xPos() + r->node->marginLeft(), - _ty + r->startY - r->node->yPos() + r->node->marginTop()); - pI.phase = PaintActionFloat; - r->node->paint(pI, - _tx + r->left - r->node->xPos() + r->node->marginLeft(), - _ty + r->startY - r->node->yPos() + r->node->marginTop()); - pI.phase = PaintActionForeground; - r->node->paint(pI, - _tx + r->left - r->node->xPos() + r->node->marginLeft(), - _ty + r->startY - r->node->yPos() + r->node->marginTop()); - pI.phase = PaintActionOutline; - r->node->paint(pI, - _tx + r->left - r->node->xPos() + r->node->marginLeft(), - _ty + r->startY - r->node->yPos() + r->node->marginTop()); - } - pI.phase = oldphase; - } - } -} - -void RenderBlock::insertPositionedObject(RenderObject *o) -{ - // Create the list of special objects if we don't aleady have one - if (!m_positionedObjects) { - m_positionedObjects = new TQPtrList<RenderObject>; - m_positionedObjects->setAutoDelete(false); - } - else { - // Don't insert the object again if it's already in the list - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - RenderObject* f; - while ( (f = it.current()) ) { - if (f == o) return; - ++it; - } - } - - // Create the special object entry & append it to the list - setOverhangingContents(); - m_positionedObjects->append(o); -} - -void RenderBlock::removePositionedObject(RenderObject *o) -{ - if (m_positionedObjects) { - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - while (it.current()) { - if (it.current() == o) - m_positionedObjects->removeRef(it.current()); - ++it; - } - if (m_positionedObjects->isEmpty()) { - delete m_positionedObjects; - m_positionedObjects = 0; - } - } -} - -void RenderBlock::insertFloatingObject(RenderObject *o) -{ - // Create the list of special objects if we don't aleady have one - if (!m_floatingObjects) { - m_floatingObjects = new TQPtrList<FloatingObject>; - m_floatingObjects->setAutoDelete(true); - } - else { - // Don't insert the object again if it's already in the list - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - FloatingObject* f; - while ( (f = it.current()) ) { - if (f->node == o) return; - ++it; - } - } - - // Create the special object entry & append it to the list - - FloatingObject *newObj; - if (o->isFloating()) { - // floating object - o->layoutIfNeeded(); - - if(o->style()->floating() & FLEFT) - newObj = new FloatingObject(FloatingObject::FloatLeft); - else - newObj = new FloatingObject(FloatingObject::FloatRight); - - newObj->startY = -500000; - newObj->endY = -500000; - newObj->width = o->width() + o->marginLeft() + o->marginRight(); - } - else { - // We should never get here, as insertFloatingObject() should only ever be called with floating - // objects. - KHTMLAssert(false); - newObj = 0; // keep gcc's uninitialized variable warnings happy - } - - newObj->node = o; - - m_floatingObjects->append(newObj); -} - -void RenderBlock::removeFloatingObject(RenderObject *o) -{ - if (m_floatingObjects) { - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - while (it.current()) { - if (it.current()->node == o) - m_floatingObjects->removeRef(it.current()); - ++it; - } - } -} - -void RenderBlock::positionNewFloats() -{ - if(!m_floatingObjects) return; - FloatingObject *f = m_floatingObjects->getLast(); - if(!f || f->startY != -500000) return; - FloatingObject *lastFloat; - while(1) - { - lastFloat = m_floatingObjects->prev(); - if (!lastFloat || lastFloat->startY != -500000) { - m_floatingObjects->next(); - break; - } - f = lastFloat; - } - - int y = m_height; - - - // the float can not start above the y position of the last positioned float. - if(lastFloat && lastFloat->startY > y) - y = lastFloat->startY; - - while(f) - { - //skip elements copied from elsewhere and positioned elements - if (f->node->containingBlock()!=this) - { - f = m_floatingObjects->next(); - continue; - } - - RenderObject *o = f->node; - int _height = o->height() + o->marginTop() + o->marginBottom(); - - // floats avoid page-breaks - if(canvas()->pagedMode()) - { - int top = y; - int bottom = y + o->height(); - if (crossesPageBreak(top, bottom) && o->height() < canvas()->pageHeight() ) { - int newY = pageTopAfter(top); -#ifdef PAGE_DEBUG - kdDebug(6040) << renderName() << " clearing float " << newY - y << "px" << endl; -#endif - y = newY; - } - } - - int ro = rightOffset(); // Constant part of right offset. - int lo = leftOffset(); // Constant part of left offset. - int fwidth = f->width; // The width we look for. - //kdDebug( 6040 ) << " Object width: " << fwidth << " available width: " << ro - lo << endl; - - // in quirk mode, floated auto-width tables try to fit within remaining linewidth - bool ftQuirk = o->isTable() && style()->htmlHacks() && o->style()->width().isVariable(); - if (ftQuirk) - fwidth = kMin( o->minWidth()+o->marginLeft()+o->marginRight(), fwidth ); - - if (ro - lo < fwidth) - fwidth = ro - lo; // Never look for more than what will be available. - - if ( o->style()->clear() & CLEFT ) - y = kMax( leftBottom(), y ); - if ( o->style()->clear() & CRIGHT ) - y = kMax( rightBottom(), y ); - - bool canClearLine; - if (o->style()->floating() & FLEFT) - { - int heightRemainingLeft = 1; - int heightRemainingRight = 1; - int fx = leftRelOffset(y,lo, false, &heightRemainingLeft, &canClearLine); - if (canClearLine) - { - while (rightRelOffset(y,ro, false, &heightRemainingRight)-fx < fwidth) - { - y += kMin( heightRemainingLeft, heightRemainingRight ); - fx = leftRelOffset(y,lo, false, &heightRemainingLeft); - } - } - if (ftQuirk && (rightRelOffset(y,ro, false)-fx < f->width)) { - o->setPos( o->xPos(), y + o->marginTop() ); - o->setChildNeedsLayout(true, false); - o->layoutIfNeeded(); - _height = o->height() + o->marginTop() + o->marginBottom(); - f->width = o->width() + o->marginLeft() + o->marginRight(); - } - f->left = fx; - //kdDebug( 6040 ) << "positioning left aligned float at (" << fx + o->marginLeft() << "/" << y + o->marginTop() << ") fx=" << fx << endl; - o->setPos(fx + o->marginLeft(), y + o->marginTop()); - } - else - { - int heightRemainingLeft = 1; - int heightRemainingRight = 1; - int fx = rightRelOffset(y,ro, false, &heightRemainingRight, &canClearLine); - if (canClearLine) - { - while (fx - leftRelOffset(y,lo, false, &heightRemainingLeft) < fwidth) - { - y += kMin(heightRemainingLeft, heightRemainingRight); - fx = rightRelOffset(y,ro, false, &heightRemainingRight); - } - } - if (ftQuirk && (fx - leftRelOffset(y,lo, false) < f->width)) { - o->setPos( o->xPos(), y + o->marginTop() ); - o->setChildNeedsLayout(true, false); - o->layoutIfNeeded(); - _height = o->height() + o->marginTop() + o->marginBottom(); - f->width = o->width() + o->marginLeft() + o->marginRight(); - } - f->left = fx - f->width; - //kdDebug( 6040 ) << "positioning right aligned float at (" << fx - o->marginRight() - o->width() << "/" << y + o->marginTop() << ")" << endl; - o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop()); - } - - if ( m_layer && hasOverflowClip()) { - if (o->xPos()+o->width() > m_overflowWidth) - m_overflowWidth = o->xPos()+o->width(); - else - if (o->xPos() < m_overflowLeft) - m_overflowLeft = o->xPos(); - } - - f->startY = y; - f->endY = f->startY + _height; - - - //kdDebug( 6040 ) << "floatingObject x/y= (" << f->left << "/" << f->startY << "-" << f->width << "/" << f->endY - f->startY << ")" << endl; - - f = m_floatingObjects->next(); - } -} - -void RenderBlock::newLine() -{ - positionNewFloats(); - // set y position - int newY = 0; - switch(m_clearStatus) - { - case CLEFT: - newY = leftBottom(); - break; - case CRIGHT: - newY = rightBottom(); - break; - case CBOTH: - newY = floatBottom(); - default: - break; - } - if(m_height < newY) - { - // kdDebug( 6040 ) << "adjusting y position" << endl; - m_height = newY; - } - m_clearStatus = CNONE; -} - -int -RenderBlock::leftOffset() const -{ - return borderLeft()+paddingLeft(); -} - -int -RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int *heightRemaining, bool *canClearLine ) const -{ - int left = fixedOffset; - if (canClearLine) *canClearLine = true; - - if (m_floatingObjects) { - if ( heightRemaining ) *heightRemaining = 1; - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - { - //kdDebug( 6040 ) <<(void *)this << " left: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " " << endl; - if (r->startY <= y && r->endY > y && - r->type == FloatingObject::FloatLeft && - r->left + r->width > left) { - left = r->left + r->width; - if ( heightRemaining ) *heightRemaining = r->endY - y; - if ( canClearLine ) *canClearLine = (r->node->style()->floating() != FLEFT_ALIGN); - } - } - } - - if (applyTextIndent && m_firstLine && style()->direction() == LTR ) { - int cw=0; - if (style()->textIndent().isPercent()) - cw = containingBlock()->contentWidth(); - left += style()->textIndent().minWidth(cw); - } - - //kdDebug( 6040 ) << "leftOffset(" << y << ") = " << left << endl; - return left; -} - -int -RenderBlock::rightOffset() const -{ - int right = m_width - borderRight() - paddingRight(); - if (m_layer && scrollsOverflowY()) - right -= m_layer->verticalScrollbarWidth(); - return right; -} - -int -RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int *heightRemaining, bool *canClearLine ) const -{ - int right = fixedOffset; - if (canClearLine) *canClearLine = true; - - if (m_floatingObjects) { - if (heightRemaining) *heightRemaining = 1; - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - { - //kdDebug( 6040 ) << "right: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " " << endl; - if (r->startY <= y && r->endY > y && - r->type == FloatingObject::FloatRight && - r->left < right) { - right = r->left; - if ( heightRemaining ) *heightRemaining = r->endY - y; - if ( canClearLine ) *canClearLine = (r->node->style()->floating() != FRIGHT_ALIGN); - } - } - } - - if (applyTextIndent && m_firstLine && style()->direction() == RTL ) { - int cw=0; - if (style()->textIndent().isPercent()) - cw = containingBlock()->contentWidth(); - right -= style()->textIndent().minWidth(cw); - } - - //kdDebug( 6040 ) << "rightOffset(" << y << ") = " << right << endl; - return right; -} - -unsigned short -RenderBlock::lineWidth(int y, bool *canClearLine) const -{ - //kdDebug( 6040 ) << "lineWidth(" << y << ")=" << rightOffset(y) - leftOffset(y) << endl; - int result; - if (canClearLine) { - bool rightCanClearLine; - bool leftCanClearLine; - result = rightOffset(y, &rightCanClearLine) - leftOffset(y, &leftCanClearLine); - *canClearLine = rightCanClearLine && leftCanClearLine; - } else - result = rightOffset(y) - leftOffset(y); - return (result < 0) ? 0 : result; -} - -int -RenderBlock::nearestFloatBottom(int height) const -{ - if (!m_floatingObjects) return 0; - int bottom = 0; - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->endY>height && (r->endY<bottom || bottom==0)) - bottom=r->endY; - return kMax(bottom, height); -} - -int RenderBlock::floatBottom() const -{ - if (!m_floatingObjects) return 0; - int bottom=0; - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->endY>bottom) - bottom=r->endY; - return bottom; -} - -int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return bottom; - if (includeSelf && m_overflowHeight > bottom) - bottom = m_overflowHeight; - - if (m_floatingObjects) { - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) { - if (!r->noPaint) { - int lp = r->startY + r->node->marginTop() + r->node->lowestPosition(false); - bottom = kMax(bottom, lp); - } - } - } - bottom = kMax(bottom, lowestAbsolutePosition()); - - if (!includeSelf && lastLineBox()) { - int lp = lastLineBox()->yPos() + lastLineBox()->height(); - bottom = kMax(bottom, lp); - } - - return bottom; -} - -int RenderBlock::lowestAbsolutePosition() const -{ - if (!m_positionedObjects) - return 0; - - // Fixed positioned objects do not scroll and thus should not constitute - // part of the lowest position. - int bottom = 0; - RenderObject* r; - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - for ( ; (r = it.current()); ++it ) { - if (r->style()->position() == FIXED) - continue; - int lp = r->yPos() + r->lowestPosition(false); - bottom = kMax(bottom, lp); - } - return bottom; -} - -int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return right; - if (includeSelf && m_overflowWidth > right) - right = m_overflowWidth; - - if (m_floatingObjects) { - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) { - if (!r->noPaint) { - int rp = r->left + r->node->marginLeft() + r->node->rightmostPosition(false); - right = kMax(right, rp); - } - } - } - right = kMax(right, rightmostAbsolutePosition()); - - if (!includeSelf && firstLineBox()) { - for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { - int rp = currBox->xPos() + currBox->width(); - right = kMax(right, rp); - } - } - - return right; -} - -int RenderBlock::rightmostAbsolutePosition() const -{ - if (!m_positionedObjects) - return 0; - int right = 0; - RenderObject* r; - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - for ( ; (r = it.current()); ++it ) { - if (r->style()->position() == FIXED) - continue; - int rp = r->xPos() + r->rightmostPosition(false); - right = kMax(right, rp); - } - return right; -} - -int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return left; - - if (includeSelf && m_overflowLeft < left) - left = m_overflowLeft; - - if (m_floatingObjects) { - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) { - if (!r->noPaint) { - int lp = r->left + r->node->marginLeft() + r->node->leftmostPosition(false); - left = kMin(left, lp); - } - } - } - left = kMin(left, leftmostAbsolutePosition()); - - if (!includeSelf && firstLineBox()) { - for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) - left = kMin(left, (int)currBox->xPos()); - } - - return left; -} - -int RenderBlock::leftmostAbsolutePosition() const -{ - if (!m_positionedObjects) - return 0; - int left = 0; - RenderObject* r; - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - for ( ; (r = it.current()); ++it ) { - if (r->style()->position() == FIXED) - continue; - int lp = r->xPos() + r->leftmostPosition(false); - left = kMin(left, lp); - } - return left; -} - -int RenderBlock::highestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int top = RenderFlow::highestPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return top; - - if (includeSelf && m_overflowTop < top) - top = m_overflowTop; - - if (m_floatingObjects) { - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) { - if (!r->noPaint) { - int hp = r->startY + r->node->marginTop() + r->node->highestPosition(false); - top = kMin(top, hp); - } - } - } - top = kMin(top, highestAbsolutePosition()); - - if (!includeSelf && firstLineBox()) { - top = kMin(top, (int)firstLineBox()->yPos()); - } - - return top; -} - -int RenderBlock::highestAbsolutePosition() const -{ - if (!m_positionedObjects) - return 0; - int top = 0; - RenderObject* r; - TQPtrListIterator<RenderObject> it(*m_positionedObjects); - for ( ; (r = it.current()); ++it ) { - if (r->style()->position() == FIXED) - continue; - int hp = r->yPos() + r->highestPosition(false); - hp = kMin(top, hp); - } - return top; -} - -int -RenderBlock::leftBottom() -{ - if (!m_floatingObjects) return 0; - int bottom=0; - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->endY>bottom && r->type == FloatingObject::FloatLeft) - bottom=r->endY; - - return bottom; -} - -int -RenderBlock::rightBottom() -{ - if (!m_floatingObjects) return 0; - int bottom=0; - FloatingObject* r; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->endY>bottom && r->type == FloatingObject::FloatRight) - bottom=r->endY; - - return bottom; -} - -void -RenderBlock::clearFloats() -{ - if (m_floatingObjects) - m_floatingObjects->clear(); - - // we are done if the element defines a new block formatting context - if (flowAroundFloats() || isRoot() || isCanvas() || isFloatingOrPositioned() || isTableCell()) return; - - RenderObject *prev = previousSibling(); - - // find the element to copy the floats from - // pass non-flows - // pass fAF's - bool parentHasFloats = false; - while (prev) { - if (!prev->isRenderBlock() || prev->isFloatingOrPositioned() || prev->flowAroundFloats()) { - if ( prev->isFloating() && parent()->isRenderBlock() ) { - parentHasFloats = true; - } - prev = prev->previousSibling(); - } else - break; - } - - int offset = m_y; - if (parentHasFloats) - { - addOverHangingFloats( static_cast<RenderBlock *>( parent() ), - parent()->borderLeft() + parent()->paddingLeft(), offset, false ); - } - - int xoffset = 0; - if (prev) { - if(prev->isTableCell()) return; - offset -= prev->yPos(); - } else { - prev = parent(); - if(!prev) return; - xoffset += prev->borderLeft() + prev->paddingLeft(); - } - //kdDebug() << "RenderBlock::clearFloats found previous "<< (void *)this << " prev=" << (void *)prev<< endl; - - // add overhanging special objects from the previous RenderBlock - if(!prev->isRenderBlock()) return; - RenderBlock * flow = static_cast<RenderBlock *>(prev); - if(!flow->m_floatingObjects) return; - if(flow->floatBottom() > offset) - addOverHangingFloats( flow, xoffset, offset, false ); -} - -void RenderBlock::addOverHangingFloats( RenderBlock *flow, int xoff, int offset, bool child ) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << (void *)this << ": adding overhanging floats xoff=" << xoff << " offset=" << offset << " child=" << child << endl; -#endif - - // Prevent floats from being added to the canvas by the root element, e.g., <html>. - if ( !flow->m_floatingObjects || (child && flow->isRoot()) ) - return; - - // if I am clear of my floats, don't add them - // the CSS spec also mentions that child floats - // are not cleared. - if (!child && style()->clear() == CBOTH) - { - return; - } - - TQPtrListIterator<FloatingObject> it(*flow->m_floatingObjects); - FloatingObject *r; - for ( ; (r = it.current()); ++it ) { - - if (!child && r->type == FloatingObject::FloatLeft && style()->clear() == CLEFT ) - continue; - if (!child && r->type == FloatingObject::FloatRight && style()->clear() == CRIGHT ) - continue; - - if ( ( !child && r->endY > offset ) || - ( child && flow->yPos() + r->endY > height() ) ) { - if (child && !r->crossedLayer) { - if (flow->enclosingLayer() == enclosingLayer()) { - // Set noPaint to true only if we didn't cross layers. - r->noPaint = true; - } else { - r->crossedLayer = true; - } - } - - FloatingObject* f = 0; - // don't insert it twice! - if (m_floatingObjects) { - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - while ( (f = it.current()) ) { - if (f->node == r->node) break; - ++it; - } - } - if ( !f ) { - FloatingObject *floatingObj = new FloatingObject(r->type); - floatingObj->startY = r->startY - offset; - floatingObj->endY = r->endY - offset; - floatingObj->left = r->left - xoff; - // Applying the child's margin makes no sense in the case where the child was passed in. - // since his own margin was added already through the subtraction of the |xoff| variable - // above. |xoff| will equal -flow->marginLeft() in this case, so it's already been taken - // into account. Only apply this code if |child| is false, since otherwise the left margin - // will get applied twice. -dwh - if (!child && flow != parent()) - floatingObj->left += flow->marginLeft(); - if ( !child ) { - floatingObj->left -= marginLeft(); - floatingObj->noPaint = true; - } - else { - floatingObj->noPaint = (r->crossedLayer || !r->noPaint); - floatingObj->crossedLayer = r->crossedLayer; - } - - floatingObj->width = r->width; - floatingObj->node = r->node; - if (!m_floatingObjects) { - m_floatingObjects = new TQPtrList<FloatingObject>; - m_floatingObjects->setAutoDelete(true); - } - m_floatingObjects->append(floatingObj); -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "addOverHangingFloats x/y= (" << floatingObj->left << "/" << floatingObj->startY << "-" << floatingObj->width << "/" << floatingObj->endY - floatingObj->startY << ")" << endl; -#endif - } - } - } -} - -bool RenderBlock::containsFloat(RenderObject* o) const -{ - if (m_floatingObjects) { - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - while (it.current()) { - if (it.current()->node == o) - return true; - ++it; - } - } - return false; -} - -void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove) -{ - dirtyFormattingContext(false); - setChildNeedsLayout(true); - - if (floatToRemove) - removeFloatingObject(floatToRemove); - - // Iterate over our children and mark them as needed. - if (!childrenInline()) { - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (isBlockFlow() && !child->isFloatingOrPositioned() && - ((floatToRemove ? child->containsFloat(floatToRemove) : child->hasFloats()) || child->usesLineWidth())) - child->markAllDescendantsWithFloatsForLayout(floatToRemove); - } - } -} - -int RenderBlock::getClearDelta(RenderObject *child) -{ - if (!hasFloats()) - return 0; - - //kdDebug( 6040 ) << "getClearDelta on child " << child << " oldheight=" << m_height << endl; - bool clearSet = child->style()->clear() != CNONE; - int bottom = 0; - switch(child->style()->clear()) - { - case CNONE: - break; - case CLEFT: - bottom = leftBottom(); - break; - case CRIGHT: - bottom = rightBottom(); - break; - case CBOTH: - bottom = floatBottom(); - break; - } - - // We also clear floats if we are too big to sit on the same line as a float, and happen to flow around floats. - // FIXME: Note that the remaining space checks aren't quite accurate, since you should be able to clear only some floats (the minimum # needed - // to fit) and not all (we should be using nearestFloatBottom and looping). - - int result = clearSet ? kMax(0, bottom - child->yPos()) : 0; - if (!result && child->flowAroundFloats() && !style()->width().isVariable()) { - bool canClearLine; - int lw = lineWidth(child->yPos(), &canClearLine); - if (((child->style()->width().isPercent() && child->width() > lw) || - (child->style()->width().isFixed() && child->minWidth() > lw)) && - child->minWidth() <= contentWidth() && canClearLine) - result = kMax(0, floatBottom() - child->yPos()); - } - return result; -} - -bool RenderBlock::isPointInScrollbar(int _x, int _y, int _tx, int _ty) -{ - if (!scrollsOverflow() || !m_layer) - return false; - - if (m_layer->verticalScrollbarWidth()) { - TQRect vertRect(_tx + width() - borderRight() - m_layer->verticalScrollbarWidth(), - _ty + borderTop() - borderTopExtra(), - m_layer->verticalScrollbarWidth(), - height() + borderTopExtra() + borderBottomExtra()-borderTop()-borderBottom()); - if (vertRect.contains(_x, _y)) { -#ifdef APPLE_CHANGES - RenderLayer::gScrollBar = m_layer->verticalScrollbar(); -#endif - return true; - } - } - - if (m_layer->horizontalScrollbarHeight()) { - TQRect horizRect(_tx + borderLeft(), - _ty + height() + borderTop() + borderBottomExtra() - borderBottom() - m_layer->horizontalScrollbarHeight(), - width()-borderLeft()-borderRight(), - m_layer->horizontalScrollbarHeight()); - if (horizRect.contains(_x, _y)) { -#ifdef APPLE_CHANGES - RenderLayer::gScrollBar = m_layer->horizontalScrollbar(); -#endif - return true; - } - } - - return false; -} - -bool RenderBlock::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inBox) -{ - bool inScrollbar = isPointInScrollbar(_x, _y, _tx+xPos(), _ty+yPos()); - if (inScrollbar && hitTestAction != HitTestChildrenOnly) - inBox = true; - - if (hitTestAction != HitTestSelfOnly && m_floatingObjects && !inScrollbar) { - int stx = _tx + xPos(); - int sty = _ty + yPos(); - if (hasOverflowClip() && m_layer) - m_layer->subtractScrollOffset(stx, sty); - FloatingObject* o; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - for (it.toLast(); (o = it.current()); --it) - if (!o->noPaint && !o->node->layer()) - inBox |= o->node->nodeAtPoint(info, _x, _y, - stx+o->left + o->node->marginLeft() - o->node->xPos(), - sty+o->startY + o->node->marginTop() - o->node->yPos(), HitTestAll ) ; - } - - inBox |= RenderFlow::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox); - return inBox; -} - -void RenderBlock::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(RenderBlock)::calcMinMaxWidth() this=" << this << endl; -#endif - - m_minWidth = 0; - m_maxWidth = 0; - - bool noWrap = !style()->autoWrap(); - if (childrenInline()) - calcInlineMinMaxWidth(); - else - calcBlockMinMaxWidth(); - - if(m_maxWidth < m_minWidth) m_maxWidth = m_minWidth; - - if (noWrap && childrenInline()) { - m_minWidth = m_maxWidth; - - // A horizontal marquee with inline children has no minimum width. - if (style()->overflowX() == OMARQUEE && m_layer && m_layer->marquee() && - m_layer->marquee()->isHorizontal() && !m_layer->marquee()->isUnfurlMarquee()) - m_minWidth = 0; - } - - if (isTableCell()) { - Length w = static_cast<RenderTableCell*>(this)->styleOrColWidth(); - if (w.isFixed() && w.value() > 0) - m_maxWidth = kMax((int)m_minWidth, calcContentWidth(w.value())); - } else if (style()->width().isFixed() && style()->width().value() > 0) - m_minWidth = m_maxWidth = calcContentWidth(style()->width().value()); - - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxWidth = kMax(m_maxWidth, (int)calcContentWidth(style()->minWidth().value())); - m_minWidth = kMax(m_minWidth, (short)calcContentWidth(style()->minWidth().value())); - } - - if (style()->maxWidth().isFixed() && style()->maxWidth().value() != UNDEFINED) { - m_maxWidth = kMin(m_maxWidth, (int)calcContentWidth(style()->maxWidth().value())); - m_minWidth = kMin(m_minWidth, (short)calcContentWidth(style()->maxWidth().value())); - } - - int toAdd = 0; - toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight(); - - m_minWidth += toAdd; - m_maxWidth += toAdd; - - setMinMaxKnown(); - - //kdDebug( 6040 ) << "Text::calcMinMaxWidth(" << this << "): min = " << m_minWidth << " max = " << m_maxWidth << endl; - // ### compare with min/max width set in style sheet... -} - -// bidi.cpp defines the following functions too. -// Maybe these should not be static, after all... - -#ifndef KDE_USE_FINAL - -static int getBPMWidth(int childValue, Length cssUnit) -{ - if (!cssUnit.isVariable()) - return (cssUnit.isFixed() ? cssUnit.value() : childValue); - return 0; -} - -static int getBorderPaddingMargin(RenderObject* child, bool endOfInline) -{ - RenderStyle* cstyle = child->style(); - int result = 0; - bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline; - result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()), - (leftSide ? cstyle->marginLeft() : - cstyle->marginRight())); - result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()), - (leftSide ? cstyle->paddingLeft() : - cstyle->paddingRight())); - result += leftSide ? child->borderLeft() : child->borderRight(); - return result; -} -#endif - -static void stripTrailingSpace(bool preserveWS, - int& inlineMax, int& inlineMin, - RenderObject* trailingSpaceChild) -{ - if (!preserveWS && trailingSpaceChild && trailingSpaceChild->isText()) { - // Collapse away the trailing space at the end of a block. - RenderText* t = static_cast<RenderText *>(trailingSpaceChild); - const Font *f = t->htmlFont( false ); - TQChar space[1]; space[0] = ' '; - int spaceWidth = f->width(space, 1, 0); - inlineMax -= spaceWidth; - if (inlineMin > inlineMax) - inlineMin = inlineMax; - } -} - -void RenderBlock::calcInlineMinMaxWidth() -{ - int inlineMax=0; - int inlineMin=0; - - int cw = containingBlock()->contentWidth(); - int floatMaxWidth = 0; - - // If we are at the start of a line, we want to ignore all white-space. - // Also strip spaces if we previously had text that ended in a trailing space. - bool stripFrontSpaces = true; - - bool isTcQuirk = isTableCell() && style()->htmlHacks() && style()->width().isVariable(); - - RenderObject* trailingSpaceChild = 0; - - bool autoWrap, oldAutoWrap; - autoWrap = oldAutoWrap = style()->autoWrap(); - - InlineMinMaxIterator childIterator(this, this); - bool addedTextIndent = false; // Only gets added in once. - RenderObject* prevFloat = 0; - while (RenderObject* child = childIterator.next()) - { - autoWrap = child->style()->autoWrap(); - - if( !child->isBR() ) - { - // Step One: determine whether or not we need to go ahead and - // terminate our current line. Each discrete chunk can become - // the new min-width, if it is the widest chunk seen so far, and - // it can also become the max-width. - - // Children fall into three categories: - // (1) An inline flow object. These objects always have a min/max of 0, - // and are included in the iteration solely so that their margins can - // be added in. - // - // (2) An inline non-text non-flow object, e.g., an inline replaced element. - // These objects can always be on a line by themselves, so in this situation - // we need to go ahead and break the current line, and then add in our own - // margins and min/max width on its own line, and then terminate the line. - // - // (3) A text object. Text runs can have breakable characters at the start, - // the middle or the end. They may also lose whitespace off the front if - // we're already ignoring whitespace. In order to compute accurate min-width - // information, we need three pieces of information. - // (a) the min-width of the first non-breakable run. Should be 0 if the text string - // starts with whitespace. - // (b) the min-width of the last non-breakable run. Should be 0 if the text string - // ends with whitespace. - // (c) the min/max width of the string (trimmed for whitespace). - // - // If the text string starts with whitespace, then we need to go ahead and - // terminate our current line (unless we're already in a whitespace stripping - // mode. - // - // If the text string has a breakable character in the middle, but didn't start - // with whitespace, then we add the width of the first non-breakable run and - // then end the current line. We then need to use the intermediate min/max width - // values (if any of them are larger than our current min/max). We then look at - // the width of the last non-breakable run and use that to start a new line - // (unless we end in whitespace). - RenderStyle* cstyle = child->style(); - short childMin = 0; - short childMax = 0; - - if (!child->isText()) { - // Case (1) and (2). Inline replaced and inline flow elements. - if (child->isInlineFlow()) { - // Add in padding/border/margin from the appropriate side of - // the element. - int bpm = getBorderPaddingMargin(child, childIterator.endOfInline); - childMin += bpm; - childMax += bpm; - - inlineMin += childMin; - inlineMax += childMax; - } - else { - // Inline replaced elements add in their margins to their min/max values. - int margins = 0; - LengthType type = cstyle->marginLeft().type(); - if ( type != Variable ) - margins += (type == Fixed ? cstyle->marginLeft().value() : child->marginLeft()); - type = cstyle->marginRight().type(); - if ( type != Variable ) - margins += (type == Fixed ? cstyle->marginRight().value() : child->marginRight()); - childMin += margins; - childMax += margins; - } - } - - if (!child->isRenderInline() && !child->isText()) { - - bool qBreak = isTcQuirk && !child->isFloatingOrPositioned(); - // Case (2). Inline replaced elements and floats. - // Go ahead and terminate the current line as far as - // minwidth is concerned. - childMin += child->minWidth(); - childMax += child->maxWidth(); - - if (!qBreak && (autoWrap || oldAutoWrap)) { - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - inlineMin = 0; - } - - // Check our "clear" setting. If we're supposed to clear the previous float, then - // go ahead and terminate maxwidth as well. - if (child->isFloating()) { - if (prevFloat && - ((inlineMax + childMax > floatMaxWidth) || - ((prevFloat->style()->floating() & FLEFT) && (child->style()->clear() & CLEFT)) || - ((prevFloat->style()->floating() & FRIGHT) && (child->style()->clear() & CRIGHT)))) { - m_maxWidth = kMax(inlineMax, (int)m_maxWidth); - inlineMax = 0; - } - prevFloat = child; - if (!floatMaxWidth) - floatMaxWidth = availableWidth(); - } - - // Add in text-indent. This is added in only once. - int ti = 0; - if ( !addedTextIndent ) { - addedTextIndent = true; - ti = style()->textIndent().minWidth( cw ); - childMin+=ti; - childMax+=ti; - } - - // Add our width to the max. - inlineMax += childMax; - - if (!autoWrap||qBreak) - inlineMin += childMin; - else { - // Now check our line. - inlineMin = childMin; - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - - // Now start a new line. - inlineMin = 0; - } - - // We are no longer stripping whitespace at the start of - // a line. - if (!child->isFloating()) { - stripFrontSpaces = false; - trailingSpaceChild = 0; - } - } - else if (child->isText()) - { - // Case (3). Text. - RenderText* t = static_cast<RenderText *>(child); - - // Determine if we have a breakable character. Pass in - // whether or not we should ignore any spaces at the front - // of the string. If those are going to be stripped out, - // then they shouldn't be considered in the breakable char - // check. - bool hasBreakableChar, hasBreak; - short beginMin, endMin; - bool beginWS, endWS; - short beginMax, endMax; - t->trimmedMinMaxWidth(beginMin, beginWS, endMin, endWS, hasBreakableChar, - hasBreak, beginMax, endMax, - childMin, childMax, stripFrontSpaces); - - // This text object is insignificant and will not be rendered. Just - // continue. - if (!hasBreak && childMax == 0) continue; - - if (stripFrontSpaces) - trailingSpaceChild = child; - else - trailingSpaceChild = 0; - - // Add in text-indent. This is added in only once. - int ti = 0; - if (!addedTextIndent) { - addedTextIndent = true; - ti = style()->textIndent().minWidth(cw); - childMin+=ti; beginMin += ti; - childMax+=ti; beginMax += ti; - } - - // If we have no breakable characters at all, - // then this is the easy case. We add ourselves to the current - // min and max and continue. - if (!hasBreakableChar) { - inlineMin += childMin; - } - else { - // We have a breakable character. Now we need to know if - // we start and end with whitespace. - if (beginWS) { - // Go ahead and end the current line. - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - } - else { - inlineMin += beginMin; - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - childMin -= ti; - } - - inlineMin = childMin; - - if (endWS) { - // We end in whitespace, which means we can go ahead - // and end our current line. - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - inlineMin = 0; - } - else { - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - inlineMin = endMin; - } - } - - if (hasBreak) { - inlineMax += beginMax; - if (m_maxWidth < inlineMax) m_maxWidth = inlineMax; - if (m_maxWidth < childMax) m_maxWidth = childMax; - inlineMax = endMax; - } - else - inlineMax += childMax; - } - } - else - { - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - if(m_maxWidth < inlineMax) m_maxWidth = inlineMax; - inlineMin = inlineMax = 0; - stripFrontSpaces = true; - trailingSpaceChild = 0; - } - - oldAutoWrap = autoWrap; - } - - stripTrailingSpace(style()->preserveWS(), inlineMax, inlineMin, trailingSpaceChild); - - if(m_minWidth < inlineMin) m_minWidth = inlineMin; - if(m_maxWidth < inlineMax) m_maxWidth = inlineMax; - // kdDebug( 6040 ) << "m_minWidth=" << m_minWidth - // << " m_maxWidth=" << m_maxWidth << endl; -} - -// Use a very large value (in effect infinite). -#define BLOCK_MAX_WIDTH 15000 - -void RenderBlock::calcBlockMinMaxWidth() -{ - bool nowrap = !style()->autoWrap(); - - RenderObject *child = firstChild(); - RenderObject* prevFloat = 0; - int floatWidths = 0; - int floatMaxWidth = 0; - - while(child != 0) - { - // positioned children don't affect the minmaxwidth - if (child->isPositioned()) { - child = child->nextSibling(); - continue; - } - - if (prevFloat && (!child->isFloating() || - ((prevFloat->style()->floating() & FLEFT) && (child->style()->clear() & CLEFT)) || - ((prevFloat->style()->floating() & FRIGHT) && (child->style()->clear() & CRIGHT)))) { - m_maxWidth = kMax(floatWidths, m_maxWidth); - floatWidths = 0; - } - - Length ml = child->style()->marginLeft(); - Length mr = child->style()->marginRight(); - - // Call calcWidth on the child to ensure that our margins are - // up to date. This method can be called before the child has actually - // calculated its margins (which are computed inside calcWidth). - if (ml.isPercent() || mr.isPercent()) - calcWidth(); - - // A margin basically has three types: fixed, percentage, and auto (variable). - // Auto margins simply become 0 when computing min/max width. - // Fixed margins can be added in as is. - // Percentage margins are computed as a percentage of the width we calculated in - // the calcWidth call above. In this case we use the actual cached margin values on - // the RenderObject itself. - int margin = 0; - if (ml.isFixed()) - margin += ml.value(); - else if (ml.isPercent()) - margin += child->marginLeft(); - - if (mr.isFixed()) - margin += mr.value(); - else if (mr.isPercent()) - margin += child->marginRight(); - - if (margin < 0) margin = 0; - - int w = child->minWidth() + margin; - if(m_minWidth < w) m_minWidth = w; - // IE ignores tables for calculation of nowrap. Makes some sense. - if ( nowrap && !child->isTable() && m_maxWidth < w ) - m_maxWidth = w; - - w = child->maxWidth() + margin; - - if(m_maxWidth < w) m_maxWidth = w; - - if (child->isFloating()) { - if (prevFloat && (floatWidths + w > floatMaxWidth)) { - m_maxWidth = kMax(floatWidths, m_maxWidth); - floatWidths = w; - } else - floatWidths += w; - } else if (m_maxWidth < w) - m_maxWidth = w; - - // A very specific WinIE quirk. - // Example: - /* - <div style="position:absolute; width:100px; top:50px;"> - <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green"> - <table style="width:100%"><tr><td></table> - </div> - </div> - */ - // In the above example, the inner absolute positioned block should have a computed width - // of 100px because of the table. - // We can achieve this effect by making the maxwidth of blocks that contain tables - // with percentage widths be infinite (as long as they are not inside a table cell). - if (style()->htmlHacks() && child->style()->width().isPercent() && - !isTableCell() && child->isTable() && m_maxWidth < BLOCK_MAX_WIDTH) { - RenderBlock* cb = containingBlock(); - while (!cb->isCanvas() && !cb->isTableCell()) - cb = cb->containingBlock(); - if (!cb->isTableCell()) - m_maxWidth = BLOCK_MAX_WIDTH; - } - if (child->isFloating()) { - prevFloat = child; - if (!floatMaxWidth) - floatMaxWidth = availableWidth(); - } - child = child->nextSibling(); - } - m_maxWidth = kMax(floatWidths, m_maxWidth); -} - -void RenderBlock::close() -{ - if (lastChild() && lastChild()->isAnonymousBlock()) - lastChild()->close(); - updateFirstLetter(); - RenderFlow::close(); -} - -int RenderBlock::getBaselineOfFirstLineBox() -{ - if (m_firstLineBox) - return m_firstLineBox->yPos() + m_firstLineBox->baseline(); - - if (isInline()) - return -1; // We're inline and had no line box, so we have no baseline we can return. - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - int result = curr->getBaselineOfFirstLineBox(); - if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. - } - - return -1; -} - -InlineFlowBox* RenderBlock::getFirstLineBox() -{ - if (m_firstLineBox) - return m_firstLineBox; - - if (isInline()) - return 0; // We're inline and had no line box, so we have no baseline we can return. - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - InlineFlowBox* result = curr->getFirstLineBox(); - if (result) - return result; - } - - return 0; -} - -bool RenderBlock::inRootBlockContext() const -{ - if (isTableCell() || isFloatingOrPositioned() || hasOverflowClip()) - return false; - - if (isRoot() || isCanvas()) - return true; - - return containingBlock()->inRootBlockContext(); -} - -const char *RenderBlock::renderName() const -{ - if (isFloating()) - return "RenderBlock (floating)"; - if (isPositioned()) - return "RenderBlock (positioned)"; - if (isAnonymousBlock() && m_avoidPageBreak) - return "RenderBlock (avoidPageBreak)"; - if (isAnonymousBlock()) - return "RenderBlock (anonymous)"; - else if (isAnonymous()) - return "RenderBlock (generated)"; - if (isRelPositioned()) - return "RenderBlock (relative positioned)"; - if (style() && style()->display() == COMPACT) - return "RenderBlock (compact)"; - if (style() && style()->display() == RUN_IN) - return "RenderBlock (run-in)"; - return "RenderBlock"; -} - -#ifdef ENABLE_DUMP -void RenderBlock::printTree(int indent) const -{ - RenderFlow::printTree(indent); - - if (m_floatingObjects) - { - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - FloatingObject *r; - for ( ; (r = it.current()); ++it ) - { - TQString s; - s.fill(' ', indent); - kdDebug() << s << renderName() << ": " << - (r->type == FloatingObject::FloatLeft ? "FloatLeft" : "FloatRight" ) << - "[" << r->node->renderName() << ": " << (void*)r->node << "] (" << r->startY << " - " << r->endY << ")" << "width: " << r->width << - endl; - } - } -} - -void RenderBlock::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderFlow::dump(stream,ind); - - if (m_childrenInline) { stream << " childrenInline"; } - // FIXME: currently only print pre to not mess up regression - if (style()->preserveWS()) { stream << " pre"; } - if (m_firstLine) { stream << " firstLine"; } - - if (m_floatingObjects && !m_floatingObjects->isEmpty()) - { - stream << " special("; - TQPtrListIterator<FloatingObject> it(*m_floatingObjects); - FloatingObject *r; - bool first = true; - for ( ; (r = it.current()); ++it ) - { - if (!first) - stream << ","; - stream << r->node->renderName(); - first = false; - } - stream << ")"; - } - - // ### EClear m_clearStatus -} -#endif - -#undef DEBUG -#undef DEBUG_LAYOUT -#undef BOX_DEBUG - -} // namespace khtml - diff --git a/khtml/rendering/render_block.h b/khtml/rendering/render_block.h deleted file mode 100644 index 2b0e49398..000000000 --- a/khtml/rendering/render_block.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - * This file is part of the render object implementation for KHTML. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef RENDER_BLOCK_H -#define RENDER_BLOCK_H - -#include <tqptrlist.h> - -#include "render_flow.h" - -namespace khtml { - -class RenderBlock : public RenderFlow -{ -public: - RenderBlock(DOM::NodeImpl* node); - virtual ~RenderBlock(); - - virtual const char *renderName() const; - - virtual bool isRenderBlock() const { return true; } - virtual bool isBlockFlow() const { return !isInline() && !isTable(); } - virtual bool isInlineFlow() const { return isInline() && !isReplaced(); } - virtual bool isInlineBlockOrInlineTable() const { return isInline() && isReplaced(); } - - virtual bool childrenInline() const { return m_childrenInline; } - virtual void setChildrenInline(bool b) { m_childrenInline = b; } - void makeChildrenNonInline(RenderObject* insertionPoint = 0); - - void makePageBreakAvoidBlocks(); - - // The height (and width) of a block when you include overflow spillage out of the bottom - // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside - // it would have an overflow height of borderTop() + paddingTop() + 100px. - virtual int overflowHeight() const { return m_overflowHeight; } - virtual int overflowWidth() const { return m_overflowWidth; } - virtual int overflowLeft() const { return m_overflowLeft; } - virtual int overflowTop() const { return m_overflowTop; } - virtual void setOverflowHeight(int h) { m_overflowHeight = h; } - virtual void setOverflowWidth(int w) { m_overflowWidth = w; } - virtual void setOverflowLeft(int l) { m_overflowLeft = l; } - virtual void setOverflowTop(int t) { m_overflowTop = t; } - - virtual bool isSelfCollapsingBlock() const; - virtual bool isTopMarginQuirk() const { return m_topMarginQuirk; } - virtual bool isBottomMarginQuirk() const { return m_bottomMarginQuirk; } - - virtual short maxTopMargin(bool positive) const { - if (positive) - return m_maxTopPosMargin; - else - return m_maxTopNegMargin; - } - virtual short maxBottomMargin(bool positive) const { - if (positive) - return m_maxBottomPosMargin; - else - return m_maxBottomNegMargin; - } - - void initMaxMarginValues() { - if (m_marginTop >= 0) - m_maxTopPosMargin = m_marginTop; - else - m_maxTopNegMargin = -m_marginTop; - if (m_marginBottom >= 0) - m_maxBottomPosMargin = m_marginBottom; - else - m_maxBottomNegMargin = -m_marginBottom; - } - - virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild); - virtual void removeChild(RenderObject *oldChild); - - virtual void setStyle(RenderStyle* _style); - virtual void attach(); - void updateFirstLetter(); - - virtual void layout(); - void layoutBlock( bool relayoutChildren ); - void layoutBlockChildren( bool relayoutChildren ); - void layoutInlineChildren( bool relayoutChildren, int breakBeforeLine = 0); - - void layoutPositionedObjects( bool relayoutChildren ); - void insertPositionedObject(RenderObject *o); - void removePositionedObject(RenderObject *o); - - // Called to lay out the legend for a fieldset. - virtual RenderObject* layoutLegend(bool /*relayoutChildren*/) { return 0; }; - - // the implementation of the following functions is in bidi.cpp - void bidiReorderLine(const BidiIterator &start, const BidiIterator &end, BidiState &bidi ); - BidiIterator findNextLineBreak(BidiIterator &start, BidiState &info ); - InlineFlowBox* constructLine(const BidiIterator& start, const BidiIterator& end); - InlineFlowBox* createLineBoxes(RenderObject* obj); - void computeHorizontalPositionsForLine(InlineFlowBox* lineBox, BidiState &bidi); - void computeVerticalPositionsForLine(InlineFlowBox* lineBox); - bool clearLineOfPageBreaks(InlineFlowBox* lineBox); - void checkLinesForOverflow(); - void deleteEllipsisLineBoxes(); - void checkLinesForTextOverflow(); - // end bidi.cpp functions - - virtual void paint(PaintInfo& i, int tx, int ty); - void paintObject(PaintInfo& i, int tx, int ty, bool paintOutline = true); - void paintFloats(PaintInfo& i, int _tx, int _ty, bool paintSelection = false); - - void insertFloatingObject(RenderObject *o); - void removeFloatingObject(RenderObject *o); - - // called from lineWidth, to position the floats added in the last line. - void positionNewFloats(); - void clearFloats(); - int getClearDelta(RenderObject *child); - virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0); - - // FIXME: containsFloats() should not return true if the floating objects list - // is empty. However, layoutInlineChildren() relies on the current behavior. - // http://bugzilla.opendarwin.org/show_bug.cgi?id=7395#c3 - virtual bool hasFloats() const { return m_floatingObjects!=0; } - virtual bool containsFloat(RenderObject* o) const; - - virtual bool hasOverhangingFloats() const { return floatBottom() > m_height; } - void addOverHangingFloats( RenderBlock *block, int xoffset, int yoffset, bool child ); - - int nearestFloatBottom(int height) const; - int floatBottom() const; - inline int leftBottom(); - inline int rightBottom(); - - virtual unsigned short lineWidth(int y, bool *canClearLine = 0) const; - virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int highestPosition(bool includeOverflowInterior, bool includeSelf) const; - int lowestAbsolutePosition() const; - int leftmostAbsolutePosition() const; - int rightmostAbsolutePosition() const; - int highestAbsolutePosition() const; - - int rightOffset() const; - int rightRelOffset(int y, int fixedOffset, bool applyTextIndent=true, int *heightRemaining = 0, bool *canClearLine = 0) const; - int rightOffset(int y, bool *canClearLine = 0) const { return rightRelOffset(y, rightOffset(), true, 0, canClearLine); } - - int leftOffset() const; - int leftRelOffset(int y, int fixedOffset, bool applyTextIndent=true, int *heightRemaining = 0, bool *canClearLine = 0) const; - int leftOffset(int y, bool *canClearLine = 0) const { return leftRelOffset(y, leftOffset(), true, 0, canClearLine); } - - virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int _tx, int _ty, HitTestAction hitTestAction = HitTestAll, bool inside=false); - - bool isPointInScrollbar(int x, int y, int tx, int ty); - - virtual void calcMinMaxWidth(); - void calcInlineMinMaxWidth(); - void calcBlockMinMaxWidth(); - - virtual void close(); - - virtual int getBaselineOfFirstLineBox(); - virtual InlineFlowBox* getFirstLineBox(); - - RootInlineBox* firstRootBox() { return static_cast<RootInlineBox*>(m_firstLineBox); } - RootInlineBox* lastRootBox() { return static_cast<RootInlineBox*>(m_lastLineBox); } - - bool inRootBlockContext() const; - -#ifdef ENABLE_DUMP - virtual void printTree(int indent=0) const; - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - -protected: - void newLine(); - -protected: - struct FloatingObject { - enum Type { - FloatLeft, - FloatRight - }; - - FloatingObject(Type _type) { - node = 0; - startY = 0; - endY = 0; - type = _type; - left = 0; - width = 0; - noPaint = false; - crossedLayer = false; - - } - RenderObject* node; - int startY; - int endY; - short left; - short width; - Type type : 1; // left or right aligned - bool noPaint : 1; - bool crossedLayer : 1; // lock noPaint flag - }; - - // The following helper functions and structs are used by layoutBlockChildren. - class CompactInfo { - // A compact child that needs to be collapsed into the margin of the following block. - RenderObject* m_compact; - - // The block with the open margin that the compact child is going to place itself within. - RenderObject* m_block; - bool m_treatAsBlock : 1; - - public: - RenderObject* compact() const { return m_compact; } - RenderObject* block() const { return m_block; } - void setTreatAsBlock(bool b) { m_treatAsBlock = b; } - bool treatAsBlock() const { return m_treatAsBlock; } - bool matches(RenderObject* child) const { return m_compact && m_block == child; } - - void clear() { set(0, 0); } - void set(RenderObject* c, RenderObject* b) { m_compact = c; m_block = b; } - - CompactInfo() { clear(); } - }; - - class MarginInfo { - // Collapsing flags for whether we can collapse our margins with our children's margins. - bool m_canCollapseWithChildren : 1; - bool m_canCollapseTopWithChildren : 1; - bool m_canCollapseBottomWithChildren : 1; - - // Whether or not we are a quirky container, i.e., do we collapse away top and bottom - // margins in our container. Table cells and the body are the common examples. We - // also have a custom style property for Safari RSS to deal with TypePad blog articles. - bool m_quirkContainer : 1; - - // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block. - // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will - // always be collapsing with one another. This variable can remain set to true through multiple iterations - // as long as we keep encountering self-collapsing blocks. - bool m_atTopOfBlock : 1; - - // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block. - bool m_atBottomOfBlock : 1; - - // If our last normal flow child was a self-collapsing block that cleared a float, - // we track it in this variable. - bool m_selfCollapsingBlockClearedFloat : 1; - - // These variables are used to detect quirky margins that we need to collapse away (in table cells - // and in the body element). - bool m_topQuirk : 1; - bool m_bottomQuirk : 1; - bool m_determinedTopQuirk : 1; - - // These flags track the previous maximal positive and negative margins. - int m_posMargin; - int m_negMargin; - - public: - MarginInfo(RenderBlock* b, int top, int bottom); - - void setAtTopOfBlock(bool b) { m_atTopOfBlock = b; } - void setAtBottomOfBlock(bool b) { m_atBottomOfBlock = b; } - void clearMargin() { m_posMargin = m_negMargin = 0; } - void setSelfCollapsingBlockClearedFloat(bool b) { m_selfCollapsingBlockClearedFloat = b; } - void setTopQuirk(bool b) { m_topQuirk = b; } - void setBottomQuirk(bool b) { m_bottomQuirk = b; } - void setDeterminedTopQuirk(bool b) { m_determinedTopQuirk = b; } - void setPosMargin(int p) { m_posMargin = p; } - void setNegMargin(int n) { m_negMargin = n; } - void setPosMarginIfLarger(int p) { if (p > m_posMargin) m_posMargin = p; } - void setNegMarginIfLarger(int n) { if (n > m_negMargin) m_negMargin = n; } - - void setMargin(int p, int n) { m_posMargin = p; m_negMargin = n; } - - bool atTopOfBlock() const { return m_atTopOfBlock; } - bool canCollapseWithTop() const { return m_atTopOfBlock && m_canCollapseTopWithChildren; } - bool canCollapseWithBottom() const { return m_atBottomOfBlock && m_canCollapseBottomWithChildren; } - bool canCollapseTopWithChildren() const { return m_canCollapseTopWithChildren; } - bool canCollapseBottomWithChildren() const { return m_canCollapseBottomWithChildren; } - bool selfCollapsingBlockClearedFloat() const { return m_selfCollapsingBlockClearedFloat; } - bool quirkContainer() const { return m_quirkContainer; } - bool determinedTopQuirk() const { return m_determinedTopQuirk; } - bool topQuirk() const { return m_topQuirk; } - bool bottomQuirk() const { return m_bottomQuirk; } - int posMargin() const { return m_posMargin; } - int negMargin() const { return m_negMargin; } - int margin() const { return m_posMargin - m_negMargin; } - }; - - class PageBreakInfo { - int m_pageBottom; // Next calculated page-break - bool m_forcePageBreak : 1; // Must break before next block - // ### to do better "page-break-after/before: avoid" this struct - // should keep a pagebreakAvoid block and gather children in it - public: - PageBreakInfo(int pageBottom) : m_pageBottom(pageBottom), m_forcePageBreak(false) {}; - bool forcePageBreak() { return m_forcePageBreak; } - void setForcePageBreak(bool b) { m_forcePageBreak = b; } - int pageBottom() { return m_pageBottom; }; - void setPageBottom(int bottom) { m_pageBottom = bottom; } - }; - - virtual bool canClear(RenderObject *child, PageBreakLevel level); - void clearPageBreak(RenderObject* child, int pageBottom); - - void adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo); - void adjustFloatingBlock(const MarginInfo& marginInfo); - RenderObject* handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled); - RenderObject* handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled); - RenderObject* handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled); - RenderObject* handleCompactChild(RenderObject* child, CompactInfo& compactInfo, const MarginInfo& marginInfo, bool& handled); - RenderObject* handleRunInChild(RenderObject* child, bool& handled); - void collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate); - void clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin); - void adjustSizeForCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo); - void insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo); - int estimateVerticalPosition(RenderObject* child, const MarginInfo& info); - void determineHorizontalPosition(RenderObject* child); - void handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo); - void setCollapsedBottomMargin(const MarginInfo& marginInfo); - void clearChildOfPageBreaks(RenderObject* child, PageBreakInfo &pageBreakInfo, MarginInfo &marginInfo); - // End helper functions and structs used by layoutBlockChildren. - -protected: - // How much content overflows out of our block vertically or horizontally (all we support - // for now is spillage out of the bottom and the right, which are the common cases). - int m_overflowHeight; - int m_overflowWidth; - - // Left and top overflow. - int m_overflowTop; - int m_overflowLeft; - -private: - TQPtrList<FloatingObject>* m_floatingObjects; - TQPtrList<RenderObject>* m_positionedObjects; - - bool m_childrenInline : 1; - bool m_firstLine : 1; // used in inline layouting - EClear m_clearStatus : 2; // used during layuting of paragraphs - bool m_avoidPageBreak : 1; // anonymous avoid page-break block - bool m_topMarginQuirk : 1; - bool m_bottomMarginQuirk : 1; - - short m_maxTopPosMargin; - short m_maxTopNegMargin; - short m_maxBottomPosMargin; - short m_maxBottomNegMargin; - -}; - -} // namespace - -#endif // RENDER_BLOCK_H - diff --git a/khtml/rendering/render_body.cpp b/khtml/rendering/render_body.cpp deleted file mode 100644 index 541c9676d..000000000 --- a/khtml/rendering/render_body.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.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 "rendering/render_body.h" -#include "rendering/render_canvas.h" -#include "html/html_baseimpl.h" -#include "xml/dom_docimpl.h" -#include "khtmlview.h" - -#include <kglobal.h> -#include <kdebug.h> - -using namespace khtml; -using namespace DOM; - -RenderBody::RenderBody(HTMLBodyElementImpl* element) - : RenderBlock(element) -{ - scrollbarsStyled = false; -} - -RenderBody::~RenderBody() -{ -} - -void RenderBody::setStyle(RenderStyle* style) -{ -// tqDebug("RenderBody::setStyle()"); - // ignore position: fixed on body - if (style->htmlHacks() && style->position() == FIXED) - style->setPosition(STATIC); - - RenderBlock::setStyle(style); - document()->setTextColor( style->color() ); - scrollbarsStyled = false; -} - -void RenderBody::paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty) -{ - //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl; - TQColor bgColor; - const BackgroundLayer *bgLayer = 0; - - if( parent()->style()->hasBackground() ) { - // the root element already has a non-transparent background of its own - // so we must fork our own. (CSS2.1 - 14.2 §4) - bgColor = style()->backgroundColor(); - bgLayer = style()->backgroundLayers(); - } - - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - _ty -= borderTopExtra(); - - int my = kMax(_ty, paintInfo.r.y()); - int end = kMin( paintInfo.r.y()+paintInfo.r.height(), _ty + h ); - int mh = end - my; - - paintBackgrounds(paintInfo.p, bgColor, bgLayer, my, mh, _tx, _ty, w, h); - - if(style()->hasBorder()) - paintBorder( paintInfo.p, _tx, _ty, w, h, style() ); - -} - -void RenderBody::repaint(Priority p) -{ - RenderObject *cb = containingBlock(); - if(cb) - cb->repaint(p); -} - -void RenderBody::layout() -{ - // in quirk mode, we'll need to have our margins determined - // for percentage height calculations - if (style()->htmlHacks()) - calcHeight(); - RenderBlock::layout(); - - if (!scrollbarsStyled) - { - RenderCanvas* canvas = this->canvas(); - if (canvas->view()) - { - canvas->view()->horizontalScrollBar()->setPalette(style()->palette()); - canvas->view()->verticalScrollBar()->setPalette(style()->palette()); - } - scrollbarsStyled=true; - } -} - -int RenderBody::availableHeight() const -{ - int h = RenderBlock::availableHeight(); - - if( style()->marginTop().isFixed() ) - h -= style()->marginTop().value(); - if( style()->marginBottom().isFixed() ) - h -= style()->marginBottom().value(); - - return kMax(0, h); -} diff --git a/khtml/rendering/render_body.h b/khtml/rendering/render_body.h deleted file mode 100644 index 7951f73e1..000000000 --- a/khtml/rendering/render_body.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.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. - * - */ -#ifndef RENDER_BODY -#define RENDER_BODY - -#include "rendering/render_block.h" - -namespace DOM -{ - class HTMLBodyElementImpl; -} - -namespace khtml { - -class RenderBody : public RenderBlock -{ -public: - RenderBody(DOM::HTMLBodyElementImpl* node); - virtual ~RenderBody(); - - virtual bool isBody() const { return true; } - - virtual const char *renderName() const { return "RenderBody"; } - virtual void repaint(Priority p=NormalPriority); - - virtual void layout(); - virtual void setStyle(RenderStyle* style); - - virtual int availableHeight() const; - -protected: - virtual void paintBoxDecorations(PaintInfo&, int _tx, int _ty); - bool scrollbarsStyled; -}; - -} // end namespace -#endif diff --git a/khtml/rendering/render_box.cpp b/khtml/rendering/render_box.cpp deleted file mode 100644 index 7400752ac..000000000 --- a/khtml/rendering/render_box.cpp +++ /dev/null @@ -1,2325 +0,0 @@ -/** - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Apple Computer, Inc. - * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * - * 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. - * - */ -// ------------------------------------------------------------------------- -//#define DEBUG_LAYOUT -//#define CLIP_DEBUG - - -#include <tqpainter.h> - -#include "misc/loader.h" -#include "rendering/render_replaced.h" -#include "rendering/render_canvas.h" -#include "rendering/render_table.h" -#include "rendering/render_inline.h" -#include "rendering/render_block.h" -#include "rendering/render_line.h" -#include "rendering/render_layer.h" -#include "misc/htmlhashes.h" -#include "xml/dom_nodeimpl.h" -#include "xml/dom_docimpl.h" -#include "html/html_elementimpl.h" - -#include <khtmlview.h> -#include <kdebug.h> -#include <kglobal.h> -#include <assert.h> - - -using namespace DOM; -using namespace khtml; - -#define TABLECELLMARGIN -0x4000 - -RenderBox::RenderBox(DOM::NodeImpl* node) - : RenderContainer(node) -{ - m_minWidth = -1; - m_maxWidth = -1; - m_width = m_height = 0; - m_x = 0; - m_y = 0; - m_marginTop = 0; - m_marginBottom = 0; - m_marginLeft = 0; - m_marginRight = 0; - m_staticX = 0; - m_staticY = 0; - - m_placeHolderBox = 0; - m_layer = 0; -} - -RenderBlock* RenderBox::createAnonymousBlock() -{ - RenderStyle *newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(BLOCK); - - RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous*/); - newBox->setStyle(newStyle); - return newBox; -} - -void RenderBox::restructureParentFlow() { - if (!parent() || parent()->childrenInline() == isInline()) - return; - // We have gone from not affecting the inline status of the parent flow to suddenly - // having an impact. See if there is a mismatch between the parent flow's - // childrenInline() state and our state. - if (!isInline()) { - if (parent()->isRenderInline()) { - // We have to split the parent flow. - RenderInline* parentInline = static_cast<RenderInline*>(parent()); - RenderBlock* newBox = parentInline->createAnonymousBlock(); - - RenderFlow* oldContinuation = parent()->continuation(); - parentInline->setContinuation(newBox); - - RenderObject* beforeChild = nextSibling(); - parent()->removeChildNode(this); - parentInline->splitFlow(beforeChild, newBox, this, oldContinuation); - } - else if (parent()->isRenderBlock()) - static_cast<RenderBlock*>(parent())->makeChildrenNonInline(); - } - else { - // An anonymous block must be made to wrap this inline. - RenderBlock* box = createAnonymousBlock(); - parent()->insertChildNode(box, this); - box->appendChildNode(parent()->removeChildNode(this)); - } -} - -static inline bool overflowAppliesTo(RenderObject* o) -{ - // css 2.1-11.1.1 - // 1) overflow only applies to non-replaced block-level elements, table cells, and inline-block elements - if (o->isRenderBlock() || o->isTableRow() || o->isTableSection()) - // 2) overflow on root applies to the viewport (cf. KHTMLView::layout) - if (!o->isRoot()) - // 3) overflow on body may apply to the viewport... - if (!o->isBody() - // ...but only for HTML documents... - || !o->document()->isHTMLDocument() - // ...and only when the root has a visible overflow - || !o->document()->documentElement()->renderer() - || !o->document()->documentElement()->renderer()->style() - || o->document()->documentElement()->renderer()->style()->hidesOverflow()) - return true; - - return false; -} - -void RenderBox::setStyle(RenderStyle *_style) -{ - bool affectsParent = style() && isFloatingOrPositioned() && - (!_style->isFloating() && _style->position() != ABSOLUTE && _style->position() != FIXED) && - parent() && (parent()->isBlockFlow() || parent()->isInlineFlow()); - - RenderContainer::setStyle(_style); - - // The root always paints its background/border. - if (isRoot()) - setShouldPaintBackgroundOrBorder(true); - - switch(_style->display()) - { - case INLINE: - case INLINE_BLOCK: - case INLINE_TABLE: - setInline(true); - break; - case RUN_IN: - if (isInline() && parent() && parent()->childrenInline()) - break; - default: - setInline(false); - } - - switch(_style->position()) - { - case ABSOLUTE: - case FIXED: - setPositioned(true); - break; - default: - setPositioned(false); - if( !isTableCell() && _style->isFloating() ) - setFloating(true); - - if( _style->position() == RELATIVE ) - setRelPositioned(true); - } - - if (overflowAppliesTo(this) && _style->hidesOverflow()) - setHasOverflowClip(); - - if (requiresLayer()) { - if (!m_layer) { - m_layer = new (renderArena()) RenderLayer(this); - m_layer->insertOnlyThisLayer(); - if (parent() && containingBlock()) - m_layer->updateLayerPosition(); - } - } - else if (m_layer && !isCanvas()) { - m_layer->removeOnlyThisLayer(); - m_layer = 0; - } - - if (m_layer) - m_layer->styleChanged(); - - if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintActionOutline)) - static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize()); - if (affectsParent) - restructureParentFlow(); -} - -RenderBox::~RenderBox() -{ - //kdDebug( 6040 ) << "Element destructor: this=" << nodeName().string() << endl; -} - -void RenderBox::detach() -{ - RenderLayer* layer = m_layer; - RenderArena* arena = renderArena(); - - RenderContainer::detach(); - - if (layer) - layer->detach(arena); -} - -InlineBox* RenderBox::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/) -{ - if (m_placeHolderBox) - m_placeHolderBox->detach(renderArena()); - return (m_placeHolderBox = new (renderArena()) InlineBox(this)); -} - -void RenderBox::deleteInlineBoxes(RenderArena* arena) -{ - if (m_placeHolderBox) { - m_placeHolderBox->detach( arena ? arena : renderArena() ); - m_placeHolderBox = 0; - } -} - -short RenderBox::contentWidth() const -{ - short w = m_width - style()->borderLeftWidth() - style()->borderRightWidth(); - w -= paddingLeft() + paddingRight(); - - if (m_layer && scrollsOverflowY()) - w -= m_layer->verticalScrollbarWidth(); - - //kdDebug( 6040 ) << "RenderBox::contentWidth(2) = " << w << endl; - return w; -} - -int RenderBox::contentHeight() const -{ - int h = m_height - style()->borderTopWidth() - style()->borderBottomWidth(); - h -= paddingTop() + paddingBottom(); - - if (m_layer && scrollsOverflowX()) - h -= m_layer->horizontalScrollbarHeight(); - - return h; -} - -void RenderBox::setPos( int xPos, int yPos ) -{ - m_x = xPos; m_y = yPos; -} - -short RenderBox::width() const -{ - return m_width; -} - -int RenderBox::height() const -{ - return m_height; -} - -void RenderBox::setWidth( int width ) -{ - m_width = width; -} - -void RenderBox::setHeight( int height ) -{ - m_height = height; -} - -int RenderBox::calcBoxHeight(int h) const -{ - if (style()->boxSizing() == CONTENT_BOX) - h += borderTop() + borderBottom() + paddingTop() + paddingBottom(); - - return h; -} - -int RenderBox::calcBoxWidth(int w) const -{ - if (style()->boxSizing() == CONTENT_BOX) - w += borderLeft() + borderRight() + paddingLeft() + paddingRight(); - - return w; -} - -int RenderBox::calcContentHeight(int h) const -{ - if (style()->boxSizing() == BORDER_BOX) - h -= borderTop() + borderBottom() + paddingTop() + paddingBottom(); - - return kMax(0, h); -} - -int RenderBox::calcContentWidth(int w) const -{ - if (style()->boxSizing() == BORDER_BOX) - w -= borderLeft() + borderRight() + paddingLeft() + paddingRight(); - - return kMax(0, w); -} - -// --------------------- painting stuff ------------------------------- - -void RenderBox::paint(PaintInfo& i, int _tx, int _ty) -{ - _tx += m_x; - _ty += m_y; - - if (hasOverflowClip() && m_layer) - m_layer->subtractScrollOffset(_tx, _ty); - - // default implementation. Just pass things through to the children - for(RenderObject* child = firstChild(); child; child = child->nextSibling()) - child->paint(i, _tx, _ty); -} - -void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty) -{ - //kdDebug( 6040 ) << renderName() << "::paintRootBoxDecorations()" << _tx << "/" << _ty << endl; - const BackgroundLayer* bgLayer = style()->backgroundLayers(); - TQColor bgColor = style()->backgroundColor(); - if (document()->isHTMLDocument() && !style()->hasBackground()) { - // Locate the <body> element using the DOM. This is easier than trying - // to crawl around a render tree with potential :before/:after content and - // anonymous blocks created by inline <body> tags etc. We can locate the <body> - // render object very easily via the DOM. - HTMLElementImpl* body = document()->body(); - RenderObject* bodyObject = (body && body->id() == ID_BODY) ? body->renderer() : 0; - - if (bodyObject) { - bgLayer = bodyObject->style()->backgroundLayers(); - bgColor = bodyObject->style()->backgroundColor(); - } - } - - if( !bgColor.isValid() && canvas()->view()) - bgColor = canvas()->view()->palette().active().color(TQColorGroup::Base); - - int w = width(); - int h = height(); - - // kdDebug(0) << "width = " << w <<endl; - - int rw, rh; - if (canvas()->view()) { - rw = canvas()->view()->contentsWidth(); - rh = canvas()->view()->contentsHeight(); - } else { - rw = canvas()->docWidth(); - rh = canvas()->docHeight(); - } - - // kdDebug(0) << "rw = " << rw <<endl; - - int bx = _tx - marginLeft(); - int by = _ty - marginTop(); - int bw = QMAX(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw); - int bh = QMAX(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh); - - // CSS2 14.2: - // " The background of the box generated by the root element covers the entire canvas." - // hence, paint the background even in the margin areas (unlike for every other element!) - // I just love these little inconsistencies .. :-( (Dirk) - int my = kMax(by, paintInfo.r.y()); - - paintBackgrounds(paintInfo.p, bgColor, bgLayer, my, paintInfo.r.height(), bx, by, bw, bh); - - if(style()->hasBorder()) - paintBorder( paintInfo.p, _tx, _ty, w, h, style() ); -} - -void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty) -{ - //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl; - - if(isRoot()) - return paintRootBoxDecorations(paintInfo, _tx, _ty); - - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - _ty -= borderTopExtra(); - - int my = kMax(_ty,paintInfo.r.y()); - int end = kMin( paintInfo.r.y() + paintInfo.r.height(), _ty + h ); - int mh = end - my; - - // The <body> only paints its background if the root element has defined a background - // independent of the body. Go through the DOM to get to the root element's render object, - // since the root could be inline and wrapped in an anonymous block. - - if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground()) - paintBackgrounds(paintInfo.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h); - - if(style()->hasBorder()) { - paintBorder(paintInfo.p, _tx, _ty, w, h, style()); - } -} - -void RenderBox::paintBackgrounds(TQPainter *p, const TQColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height) - { - if (!bgLayer) return; - paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height); - paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height); -} - -void RenderBox::paintBackground(TQPainter *p, const TQColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height) -{ - paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height, - borderLeft(), borderRight(), paddingLeft(), paddingRight()); -} - -static void calculateBackgroundSize(const BackgroundLayer* bgLayer, int& scaledWidth, int& scaledHeight) -{ - CachedImage* bg = bgLayer->backgroundImage(); - - if (bgLayer->isBackgroundSizeSet()) { - Length bgWidth = bgLayer->backgroundSize().width; - Length bgHeight = bgLayer->backgroundSize().height; - - if (bgWidth.isPercent()) - scaledWidth = scaledWidth * bgWidth.value() / 100; - else if (bgWidth.isFixed()) - scaledWidth = bgWidth.value(); - else if (bgWidth.isVariable()) { - // If the width is auto and the height is not, we have to use the appropriate - // scale to maintain our aspect ratio. - if (bgHeight.isPercent()) { - int scaledH = scaledHeight * bgHeight.value() / 100; - scaledWidth = bg->pixmap_size().width() * scaledH / bg->pixmap_size().height(); - } else if (bgHeight.isFixed()) - scaledWidth = bg->pixmap_size().width() * bgHeight.value() / bg->pixmap_size().height(); - } - - if (bgHeight.isPercent()) - scaledHeight = scaledHeight * bgHeight.value() / 100; - else if (bgHeight.isFixed()) - scaledHeight = bgHeight.value(); - else if (bgHeight.isVariable()) { - // If the height is auto and the width is not, we have to use the appropriate - // scale to maintain our aspect ratio. - if (bgWidth.isPercent()) - scaledHeight = bg->pixmap_size().height() * scaledWidth / bg->pixmap_size().width(); - else if (bgWidth.isFixed()) - scaledHeight = bg->pixmap_size().height() * bgWidth.value() / bg->pixmap_size().width(); - else if (bgWidth.isVariable()) { - // If both width and height are auto, we just want to use the image's - // intrinsic size. - scaledWidth = bg->pixmap_size().width(); - scaledHeight = bg->pixmap_size().height(); - } - } - } else { - scaledWidth = bg->pixmap_size().width(); - scaledHeight = bg->pixmap_size().height(); - } -} - -void RenderBox::paintBackgroundExtended(TQPainter *p, const TQColor &c, const BackgroundLayer* bgLayer, int clipy, int cliph, - int _tx, int _ty, int w, int h, - int bleft, int bright, int pleft, int pright) -{ - if ( cliph < 0 ) - return; - - if (bgLayer->backgroundClip() != BGBORDER) { - // Clip to the padding or content boxes as necessary. - bool includePadding = bgLayer->backgroundClip() == BGCONTENT; - int x = _tx + bleft + (includePadding ? pleft : 0); - int y = _ty + borderTop() + (includePadding ? paddingTop() : 0); - int width = w - bleft - bright - (includePadding ? pleft + pright : 0); - int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0); - p->save(); - p->setClipRect(TQRect(x, y, width, height), TQPainter::CoordPainter); - } - - CachedImage* bg = bgLayer->backgroundImage(); - bool shouldPaintBackgroundImage = bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage(); - TQColor bgColor = c; - - // Paint the color first underneath all images. - if (!bgLayer->next() && bgColor.isValid() && tqAlpha(bgColor.rgb()) > 0) - p->fillRect(_tx, clipy, w, cliph, bgColor); - - // no progressive loading of the background image - if (shouldPaintBackgroundImage) { - int sx = 0; - int sy = 0; - int cw,ch; - int cx,cy; - int scaledImageWidth, scaledImageHeight; - - // CSS2 chapter 14.2.1 - - if (bgLayer->backgroundAttachment()) { - //scroll - int hpab = 0, vpab = 0, left = 0, top = 0; // Init to 0 for background-origin of 'border' - if (bgLayer->backgroundOrigin() != BGBORDER) { - hpab += bleft + bright; - vpab += borderTop() + borderBottom(); - left += bleft; - top += borderTop(); - if (bgLayer->backgroundOrigin() == BGCONTENT) { - hpab += pleft + pright; - vpab += paddingTop() + paddingBottom(); - left += pleft; - top += paddingTop(); - } - } - - int pw = w - hpab; - int ph = h - vpab; - scaledImageWidth = pw; - scaledImageHeight = ph; - calculateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight); - - EBackgroundRepeat bgr = bgLayer->backgroundRepeat(); - if (bgr == NO_REPEAT || bgr == REPEAT_Y) { - cw = scaledImageWidth; - int xPosition = bgLayer->backgroundXPosition().minWidth(pw-scaledImageWidth); - if ( xPosition >= 0 ) { - cx = _tx + xPosition; - cw = kMin(scaledImageWidth, pw - xPosition); - } - else { - cx = _tx; - if (scaledImageWidth > 0) { - sx = -xPosition; - cw = kMin(scaledImageWidth+xPosition, pw); - } - } - cx += left; - } else { - // repeat over x - cw = w; - cx = _tx; - if (scaledImageWidth > 0) { - int xPosition = bgLayer->backgroundXPosition().minWidth(pw-scaledImageWidth); - sx = scaledImageWidth - (xPosition % scaledImageWidth); - sx -= left % scaledImageWidth; - } - } - if (bgr == NO_REPEAT || bgr == REPEAT_X) { - ch = scaledImageHeight; - int yPosition = bgLayer->backgroundYPosition().minWidth(ph - scaledImageHeight); - if ( yPosition >= 0 ) { - cy = _ty + yPosition; - ch = kMin(ch, ph - yPosition); - } - else { - cy = _ty; - if (scaledImageHeight > 0) { - sy = -yPosition; - ch = kMin(scaledImageHeight+yPosition, ph); - } - } - - cy += top; - } else { - // repeat over y - ch = h; - cy = _ty; - if (scaledImageHeight > 0) { - int yPosition = bgLayer->backgroundYPosition().minWidth(ph - scaledImageHeight); - sy = scaledImageHeight - (yPosition % scaledImageHeight); - sy -= top % scaledImageHeight; - } - } - if (layer()) - layer()->scrollOffset(sx, sy); - } - else - { - //fixed - TQRect vr = viewRect(); - int pw = vr.width(); - int ph = vr.height(); - scaledImageWidth = pw; - scaledImageHeight = ph; - calculateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight); - EBackgroundRepeat bgr = bgLayer->backgroundRepeat(); - - int xPosition = bgLayer->backgroundXPosition().minWidth(pw-scaledImageWidth); - if (bgr == NO_REPEAT || bgr == REPEAT_Y) { - cw = kMin(scaledImageWidth, pw - xPosition); - cx = vr.x() + xPosition; - } else { - cw = pw; - cx = vr.x(); - if (scaledImageWidth > 0) - sx = scaledImageWidth - xPosition % scaledImageWidth; - } - - int yPosition = bgLayer->backgroundYPosition().minWidth(ph-scaledImageHeight); - if (bgr == NO_REPEAT || bgr == REPEAT_X) { - ch = kMin(scaledImageHeight, ph - yPosition); - cy = vr.y() + yPosition; - } else { - ch = ph; - cy = vr.y(); - if (scaledImageHeight > 0) - sy = scaledImageHeight - yPosition % scaledImageHeight; - } - - TQRect fix(cx, cy, cw, ch); - TQRect ele(_tx, _ty, w, h); - TQRect b = fix.intersect(ele); - - //kdDebug() <<" ele is " << ele << " b is " << b << " fix is " << fix << endl; - sx+=b.x()-cx; - sy+=b.y()-cy; - cx=b.x();cy=b.y();cw=b.width();ch=b.height(); - } - // restrict painting to repaint-clip - if (cy < clipy) { - ch -= (clipy - cy); - sy += (clipy - cy); - cy = clipy; - } - ch = kMin(ch, cliph); - -// kdDebug() << " clipy, cliph: " << clipy << ", " << cliph << endl; -// kdDebug() << " drawTiledPixmap(" << cx << ", " << cy << ", " << cw << ", " << ch << ", " << sx << ", " << sy << ")" << endl; - if (cw>0 && ch>0) - p->drawTiledPixmap(cx, cy, cw, ch, bg->tiled_pixmap(c, scaledImageWidth, scaledImageHeight), sx, sy); - - } - - if (bgLayer->backgroundClip() != BGBORDER) - p->restore(); // Undo the background clip - -} - -void RenderBox::outlineBox(TQPainter *p, int _tx, int _ty, const char *color) -{ - p->setPen(TQPen(TQColor(color), 1, Qt::DotLine)); - p->setBrush( Qt::NoBrush ); - p->drawRect(_tx, _ty, m_width, m_height); -} - -TQRect RenderBox::getOverflowClipRect(int tx, int ty) -{ - // XXX When overflow-clip (CSS3) is implemented, we'll obtain the property - // here. - int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight(); - int clipx = tx+bl; - int clipy = ty+bt; - int clipw = m_width-bl-br; - int cliph = m_height-bt-bb+borderTopExtra()+borderBottomExtra(); - - // Substract out scrollbars if we have them. - if (m_layer) { - clipw -= m_layer->verticalScrollbarWidth(); - cliph -= m_layer->horizontalScrollbarHeight(); - } - - return TQRect(clipx,clipy,clipw,cliph); -} - -TQRect RenderBox::getClipRect(int tx, int ty) -{ - int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight(); - // ### what about paddings? - int clipw = m_width-bl-br; - int cliph = m_height-bt-bb; - - bool rtl = (style()->direction() == RTL); - - int clipleft = 0; - int clipright = clipw; - int cliptop = 0; - int clipbottom = cliph; - - if ( style()->hasClip() && style()->position() == ABSOLUTE ) { - // the only case we use the clip property according to CSS 2.1 - if (!style()->clipLeft().isVariable()) { - int c = style()->clipLeft().width(clipw); - if ( rtl ) - clipleft = clipw - c; - else - clipleft = c; - } - if (!style()->clipRight().isVariable()) { - int w = style()->clipRight().width(clipw); - if ( rtl ) { - clipright = clipw - w; - } else { - clipright = w; - } - } - if (!style()->clipTop().isVariable()) - cliptop = style()->clipTop().width(cliph); - if (!style()->clipBottom().isVariable()) - clipbottom = style()->clipBottom().width(cliph); - } - int clipx = tx + clipleft; - int clipy = ty + cliptop; - clipw = clipright-clipleft; - cliph = clipbottom-cliptop; - - //kdDebug( 6040 ) << "setting clip("<<clipx<<","<<clipy<<","<<clipw<<","<<cliph<<")"<<endl; - - return TQRect(clipx,clipy,clipw,cliph); -} - -void RenderBox::close() -{ - setNeedsLayoutAndMinMaxRecalc(); -} - -short RenderBox::containingBlockWidth() const -{ - if (isCanvas() && canvas()->view()) - { - if (canvas()->pagedMode()) - return canvas()->width(); - else - return canvas()->view()->visibleWidth(); - } - - RenderBlock* cb = containingBlock(); - if (isRenderBlock() && cb->isTable() && static_cast<RenderTable*>(cb)->caption() == this) { - //captions are not affected by table border or padding - return cb->width(); - } - if (usesLineWidth()) - return cb->lineWidth(m_y); - else - return cb->contentWidth(); -} - -bool RenderBox::absolutePosition(int &_xPos, int &_yPos, bool f) const -{ - if ( style()->position() == FIXED ) - f = true; - RenderObject *o = container(); - if( o && o->absolutePosition(_xPos, _yPos, f)) - { - if ( o->layer() ) { - if (o->hasOverflowClip()) - o->layer()->subtractScrollOffset( _xPos, _yPos ); - if (isPositioned()) - o->layer()->checkInlineRelOffset(this, _xPos, _yPos); - } - - if(!isInline() || isReplaced()) { - _xPos += xPos(), - _yPos += yPos(); - } - - if(isRelPositioned()) - relativePositionOffset(_xPos, _yPos); - return true; - } - else - { - _xPos = 0; - _yPos = 0; - return false; - } -} - -void RenderBox::position(InlineBox* box, int /*from*/, int /*len*/, bool /*reverse*/) -{ - if (isPositioned()) { - // Cache the x position only if we were an INLINE type originally. - bool wasInline = style()->isOriginalDisplayInlineType(); - - if (wasInline && hasStaticX()) { - // The value is cached in the xPos of the box. We only need this value if - // our object was inline originally, since otherwise it would have ended up underneath - // the inlines. - m_staticX = box->xPos(); - } - else if (!wasInline && hasStaticY()) { - // Our object was a block originally, so we make our normal flow position be - // just below the line box (as though all the inlines that came before us got - // wrapped in an anonymous block, which is what would have happened had we been - // in flow). This value was cached in the yPos() of the box. - m_staticY = box->yPos(); - } - } - else if (isReplaced()) - setPos( box->xPos(), box->yPos() ); -} - -void RenderBox::repaint(Priority prior) -{ - int ow = style() ? style()->outlineSize() : 0; - if( isInline() && !isReplaced() ) - { - RenderObject* p = parent(); - Q_ASSERT(p); - while( p->isInline() && !p->isReplaced() ) - p = p->parent(); - int xoff = p->hasOverflowClip() ? 0 : p->overflowLeft(); - int yoff = p->hasOverflowClip() ? 0 : p->overflowTop(); - p->repaintRectangle( -ow + xoff, -ow + yoff, p->effectiveWidth()+ow*2, p->effectiveHeight()+ow*2, prior); - } - else - { - int xoff = hasOverflowClip() ? 0 : overflowLeft(); - int yoff = hasOverflowClip() ? 0 : overflowTop(); - repaintRectangle( -ow + xoff, -ow + yoff, effectiveWidth()+ow*2, effectiveHeight()+ow*2, prior); - } -} - -void RenderBox::repaintRectangle(int x, int y, int w, int h, Priority p, bool f) -{ - x += m_x; - y += m_y; - - // Apply the relative position offset when invalidating a rectangle. The layer - // is translated, but the render box isn't, so we need to do this to get the - // right dirty rect. Since this is called from RenderObject::setStyle, the relative position - // flag on the RenderObject has been cleared, so use the one on the style(). - if (style()->position() == RELATIVE && m_layer) - relativePositionOffset(x,y); - - if (style()->position() == FIXED) f=true; - - // kdDebug( 6040 ) << "RenderBox(" <<this << ", " << renderName() << ")::repaintRectangle (" << x << "/" << y << ") (" << w << "/" << h << ")" << endl; - RenderObject *o = container(); - if( o ) { - if (o->layer()) { - if (o->style()->hidesOverflow() && o->layer() && !o->isInlineFlow()) - o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden. - if (style()->position() == ABSOLUTE) - o->layer()->checkInlineRelOffset(this,x,y); - } - o->repaintRectangle(x, y, w, h, p, f); - } -} - -void RenderBox::relativePositionOffset(int &tx, int &ty) const -{ - if(!style()->left().isVariable()) - tx += style()->left().width(containingBlockWidth()); - else if(!style()->right().isVariable()) - tx -= style()->right().width(containingBlockWidth()); - if(!style()->top().isVariable()) - { - if (!style()->top().isPercent() - || containingBlock()->style()->height().isFixed()) - ty += style()->top().width(containingBlockHeight()); - } - else if(!style()->bottom().isVariable()) - { - if (!style()->bottom().isPercent() - || containingBlock()->style()->height().isFixed()) - ty -= style()->bottom().width(containingBlockHeight()); - } -} - -void RenderBox::calcWidth() -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "RenderBox("<<renderName()<<")::calcWidth()" << endl; -#endif - if (isPositioned()) - { - calcAbsoluteHorizontal(); - } - else - { - bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable(); - Length w; - if (treatAsReplaced) - w = Length( calcReplacedWidth(), Fixed ); - else - w = style()->width(); - - Length ml = style()->marginLeft(); - Length mr = style()->marginRight(); - - int cw = containingBlockWidth(); - if (cw<0) cw = 0; - - m_marginLeft = 0; - m_marginRight = 0; - - if (isInline() && !isInlineBlockOrInlineTable()) - { - // just calculate margins - m_marginLeft = ml.minWidth(cw); - m_marginRight = mr.minWidth(cw); - if (treatAsReplaced) - { - m_width = calcBoxWidth(w.width(cw)); - m_width = KMAX(m_width, m_minWidth); - } - - return; - } - else - { - LengthType widthType, minWidthType, maxWidthType; - if (treatAsReplaced) { - m_width = calcBoxWidth(w.width(cw)); - widthType = w.type(); - } else { - m_width = calcWidthUsing(Width, cw, widthType); - int minW = calcWidthUsing(MinWidth, cw, minWidthType); - int maxW = style()->maxWidth().value() == UNDEFINED ? - m_width : calcWidthUsing(MaxWidth, cw, maxWidthType); - - if (m_width > maxW) { - m_width = maxW; - widthType = maxWidthType; - } - if (m_width < minW) { - m_width = minW; - widthType = minWidthType; - } - } - - if (widthType == Variable) { - // kdDebug( 6040 ) << "variable" << endl; - m_marginLeft = ml.minWidth(cw); - m_marginRight = mr.minWidth(cw); - } - else - { -// kdDebug( 6040 ) << "non-variable " << w.type << ","<< w.value << endl; - calcHorizontalMargins(ml,mr,cw); - } - } - - if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline()) - { - if (containingBlock()->style()->direction()==LTR) - m_marginRight = cw - m_width - m_marginLeft; - else - m_marginLeft = cw - m_width - m_marginRight; - } - } - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "RenderBox::calcWidth(): m_width=" << m_width << " containingBlockWidth()=" << containingBlockWidth() << endl; - kdDebug( 6040 ) << "m_marginLeft=" << m_marginLeft << " m_marginRight=" << m_marginRight << endl; -#endif -} - -int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType) -{ - int width = m_width; - Length w; - if (widthType == Width) - w = style()->width(); - else if (widthType == MinWidth) - w = style()->minWidth(); - else - w = style()->maxWidth(); - - lengthType = w.type(); - - if (lengthType == Variable) { - int marginLeft = style()->marginLeft().minWidth(cw); - int marginRight = style()->marginRight().minWidth(cw); - if (cw) width = cw - marginLeft - marginRight; - - // size to max width? - if (sizesToMaxWidth()) { - width = KMAX(width, (int)m_minWidth); - width = KMIN(width, (int)m_maxWidth); - } - } - else - { - width = calcBoxWidth(w.width(cw)); - } - - return width; -} - -void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw) -{ - if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased. - { - m_marginLeft = ml.minWidth(cw); - m_marginRight = mr.minWidth(cw); - } - else - { - if ( (ml.isVariable() && mr.isVariable() && m_width<cw) || - (!ml.isVariable() && !mr.isVariable() && - containingBlock()->style()->textAlign() == KHTML_CENTER) ) - { - m_marginLeft = (cw - m_width)/2; - if (m_marginLeft<0) m_marginLeft=0; - m_marginRight = cw - m_width - m_marginLeft; - } - else if ( (mr.isVariable() && m_width<cw) || - (!ml.isVariable() && containingBlock()->style()->direction() == RTL && - containingBlock()->style()->textAlign() == KHTML_LEFT)) - { - m_marginLeft = ml.width(cw); - m_marginRight = cw - m_width - m_marginLeft; - } - else if ( (ml.isVariable() && m_width<cw) || - (!mr.isVariable() && containingBlock()->style()->direction() == LTR && - containingBlock()->style()->textAlign() == KHTML_RIGHT)) - { - m_marginRight = mr.width(cw); - m_marginLeft = cw - m_width - m_marginRight; - } - else - { - // this makes auto margins 0 if we failed a m_width<cw test above (css2.1, 10.3.3) - m_marginLeft = ml.minWidth(cw); - m_marginRight = mr.minWidth(cw); - } - } -} - -void RenderBox::calcHeight() -{ - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "RenderBox::calcHeight()" << endl; -#endif - - //cell height is managed by table, inline elements do not have a height property. - if ( isTableCell() || (isInline() && !isReplaced()) ) - return; - - if (isPositioned()) - calcAbsoluteVertical(); - else - { - calcVerticalMargins(); - - // For tables, calculate margins only - if (isTable()) - return; - - Length h; - bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable(); - bool checkMinMaxHeight = false; - - if ( treatAsReplaced ) - h = Length( calcReplacedHeight(), Fixed ); - else { - h = style()->height(); - checkMinMaxHeight = true; - } - - int height; - if (checkMinMaxHeight) { - height = calcHeightUsing(style()->height()); - if (height == -1) - height = m_height; - int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset. - int maxH = style()->maxHeight().value() == UNDEFINED ? height : calcHeightUsing(style()->maxHeight()); - if (maxH == -1) - maxH = height; - height = kMin(maxH, height); - height = kMax(minH, height); - } - else { - // The only times we don't check min/max height are when a fixed length has - // been given as an override. Just use that. - height = calcBoxHeight(h.value()); - } - - if (height<m_height && !overhangingContents() && !hasOverflowClip()) - setOverhangingContents(); - - m_height = height; - } - - // Unfurling marquees override with the furled height. - if (style()->overflowX() == OMARQUEE && m_layer && m_layer->marquee() && - m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) { - m_layer->marquee()->setEnd(m_height); - m_height = kMin(m_height, m_layer->marquee()->unfurlPos()); - } - -} - -int RenderBox::calcHeightUsing(const Length& h) -{ - int height = -1; - if (!h.isVariable()) { - if (h.isFixed()) - height = h.value(); - else if (h.isPercent()) - height = calcPercentageHeight(h); - if (height != -1) { - height = calcBoxHeight(height); - return height; - } - } - return height; -} - -int RenderBox::calcImplicitHeight() const { - assert(hasImplicitHeight()); - - RenderBlock* cb = containingBlock(); - // padding-box height - int ch = cb->height() - cb->borderTop() + cb->borderBottom(); - int top = style()->top().width(ch); - int bottom = style()->bottom().width(ch); - - return ch - top - bottom; -} - -int RenderBox::calcPercentageHeight(const Length& height, bool treatAsReplaced) const -{ - int result = -1; - RenderBlock* cb = containingBlock(); - // In quirk mode, table cells violate what the CSS spec says to do with heights. - if (cb->isTableCell() && style()->htmlHacks()) { - result = static_cast<RenderTableCell*>(cb)->cellPercentageHeight(); - } - - // Otherwise we only use our percentage height if our containing block had a specified - // height. - else if (cb->style()->height().isFixed()) - result = cb->calcContentHeight(cb->style()->height().value()); - else if (cb->style()->height().isPercent()) { - // We need to recur and compute the percentage height for our containing block. - result = cb->calcPercentageHeight(cb->style()->height(), treatAsReplaced); - if (result != -1) - result = cb->calcContentHeight(result); - } - else if (cb->isCanvas()) { - if (!canvas()->pagedMode()) - result = static_cast<RenderCanvas*>(cb)->viewportHeight(); - else - result = static_cast<RenderCanvas*>(cb)->height(); - result -= cb->style()->borderTopWidth() - cb->style()->borderBottomWidth(); - result -= cb->paddingTop() + cb->paddingBottom(); - } - else if (cb->isBody() && style()->htmlHacks() && - cb->style()->height().isVariable() && !cb->isFloatingOrPositioned()) { - int margins = cb->collapsedMarginTop() + cb->collapsedMarginBottom(); - int visHeight = canvas()->viewportHeight(); - RenderObject* p = cb->parent(); - result = visHeight - (margins + p->marginTop() + p->marginBottom() + - p->borderTop() + p->borderBottom() + - p->paddingTop() + p->paddingBottom()); - } - else if (cb->isRoot() && style()->htmlHacks() && cb->style()->height().isVariable()) { - int visHeight = canvas()->viewportHeight(); - result = visHeight - (marginTop() + marginBottom() + - borderTop() + borderBottom() + - paddingTop() + paddingBottom()); - } - else if (cb->isAnonymousBlock() || treatAsReplaced && style()->htmlHacks()) { - // IE quirk. - result = cb->calcPercentageHeight(cb->style()->height(), treatAsReplaced); - } - else if (cb->hasImplicitHeight()) { - result = cb->calcImplicitHeight(); - } - - if (result != -1) { - result = height.width(result); - if (cb->isTableCell() && style()->boxSizing() != BORDER_BOX) { - result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom()); - result = kMax(0, result); - } - } - return result; -} - -short RenderBox::calcReplacedWidth() const -{ - int width = calcReplacedWidthUsing(Width); - int minW = calcReplacedWidthUsing(MinWidth); - int maxW = style()->maxWidth().value() == UNDEFINED ? width : calcReplacedWidthUsing(MaxWidth); - - if (width > maxW) - width = maxW; - - if (width < minW) - width = minW; - - return width; -} - -int RenderBox::calcReplacedWidthUsing(WidthType widthType) const -{ - Length w; - if (widthType == Width) - w = style()->width(); - else if (widthType == MinWidth) - w = style()->minWidth(); - else - w = style()->maxWidth(); - - switch (w.type()) { - case Fixed: - return w.value(); - case Percent: - { - const int cw = containingBlockWidth(); - if (cw > 0) { - int result = w.minWidth(cw); - return result; - } - } - // fall through - default: - return intrinsicWidth(); - } -} - -int RenderBox::calcReplacedHeight() const -{ - int height = calcReplacedHeightUsing(Height); - int minH = calcReplacedHeightUsing(MinHeight); - int maxH = style()->maxHeight().value() == UNDEFINED ? height : calcReplacedHeightUsing(MaxHeight); - - if (height > maxH) - height = maxH; - - if (height < minH) - height = minH; - - return height; -} - -int RenderBox::calcReplacedHeightUsing(HeightType heightType) const -{ - Length h; - if (heightType == Height) - h = style()->height(); - else if (heightType == MinHeight) - h = style()->minHeight(); - else - h = style()->maxHeight(); - switch( h.type() ) { - case Fixed: - return h.value(); - case Percent: - { - int th = calcPercentageHeight(h, true); - if (th != -1) - return th; - // fall through - } - default: - return intrinsicHeight(); - }; -} - -int RenderBox::availableHeight() const -{ - return availableHeightUsing(style()->height()); -} - -int RenderBox::availableHeightUsing(const Length& h) const -{ - if (h.isFixed()) - return calcContentHeight(h.value()); - - if (isCanvas()) - if (static_cast<const RenderCanvas*>(this)->pagedMode()) - return static_cast<const RenderCanvas*>(this)->pageHeight(); - else - return static_cast<const RenderCanvas*>(this)->viewportHeight(); - - // We need to stop here, since we don't want to increase the height of the table - // artificially. We're going to rely on this cell getting expanded to some new - // height, and then when we lay out again we'll use the calculation below. - if (isTableCell() && (h.isVariable() || h.isPercent())) { - const RenderTableCell* tableCell = static_cast<const RenderTableCell*>(this); - return tableCell->cellPercentageHeight() - - (borderTop()+borderBottom()+paddingTop()+paddingBottom()); - } - - if (h.isPercent()) - return calcContentHeight(h.width(containingBlock()->availableHeight())); - - // Check for implicit height - if (hasImplicitHeight()) - return calcImplicitHeight(); - - return containingBlock()->availableHeight(); -} - -int RenderBox::availableWidth() const -{ - return availableWidthUsing(style()->width()); -} - -int RenderBox::availableWidthUsing(const Length& w) const -{ - if (w.isFixed()) - return calcContentWidth(w.value()); - - if (isCanvas()) - return static_cast<const RenderCanvas*>(this)->viewportWidth(); - - if (w.isPercent()) - return calcContentWidth(w.width(containingBlock()->availableWidth())); - - return containingBlock()->availableWidth(); -} - -void RenderBox::calcVerticalMargins() -{ - if( isTableCell() ) { - // table margins are basically infinite - m_marginTop = TABLECELLMARGIN; - m_marginBottom = TABLECELLMARGIN; - return; - } - - Length tm = style()->marginTop(); - Length bm = style()->marginBottom(); - - // margins are calculated with respect to the _width_ of - // the containing block (8.3) - int cw = containingBlock()->contentWidth(); - - m_marginTop = tm.minWidth(cw); - m_marginBottom = bm.minWidth(cw); -} - -void RenderBox::setStaticX(short staticX) -{ - m_staticX = staticX; -} - -void RenderBox::setStaticY(int staticY) -{ - m_staticY = staticY; -} - -void RenderBox::calcAbsoluteHorizontal() -{ - if (isReplaced()) { - calcAbsoluteHorizontalReplaced(); - return; - } - - // QUESTIONS - // FIXME 1: Which RenderObject's 'direction' property should used: the - // containing block (cb) as the spec seems to imply, the parent (parent()) as - // was previously done in calculating the static distances, or ourself, which - // was also previously done for deciding what to override when you had - // over-constrained margins? Also note that the container block is used - // in similar situations in other parts of the RenderBox class (see calcWidth() - // and calcHorizontalMargins()). For now we are using the parent for quirks - // mode and the containing block for strict mode. - - // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater - // than or less than the computed m_width. Be careful of box-sizing and - // percentage issues. - - // The following is based off of the W3C Working Draft from April 11, 2006 of - // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements" - // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width> - // (block-style-comments in this function and in calcAbsoluteHorizontalValues() - // correspond to text from the spec) - - - // We don't use containingBlock(), since we may be positioned by an enclosing - // relative positioned inline. - const RenderObject* containerBlock = container(); - - // FIXME: This is incorrect for cases where the container block is a relatively - // positioned inline. - const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight(); - - // To match WinIE, in quirks mode use the parent's 'direction' property - // instead of the the container block's. - EDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction(); - - const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight(); - const Length marginLeft = style()->marginLeft(); - const Length marginRight = style()->marginRight(); - Length left = style()->left(); - Length right = style()->right(); - - /*---------------------------------------------------------------------------*\ - * For the purposes of this section and the next, the term "static position" - * (of an element) refers, roughly, to the position an element would have had - * in the normal flow. More precisely: - * - * * The static position for 'left' is the distance from the left edge of the - * containing block to the left margin edge of a hypothetical box that would - * have been the first box of the element if its 'position' property had - * been 'static' and 'float' had been 'none'. The value is negative if the - * hypothetical box is to the left of the containing block. - * * The static position for 'right' is the distance from the right edge of the - * containing block to the right margin edge of the same hypothetical box as - * above. The value is positive if the hypothetical box is to the left of the - * containing block's edge. - * - * But rather than actually calculating the dimensions of that hypothetical box, - * user agents are free to make a guess at its probable position. - * - * For the purposes of calculating the static position, the containing block of - * fixed positioned elements is the initial containing block instead of the - * viewport, and all scrollable boxes should be assumed to be scrolled to their - * origin. - \*---------------------------------------------------------------------------*/ - - // Calculate the static distance if needed. - if (left.isVariable() && right.isVariable()) { - if (containerDirection == LTR) { - // 'm_staticX' should already have been set through layout of the parent. - int staticPosition = m_staticX - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) - staticPosition += po->xPos(); - left = Length(staticPosition, Fixed); - } else { - RenderObject* po = parent(); - // 'm_staticX' should already have been set through layout of the parent. - int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width(); - for (; po && po != containerBlock; po = po->parent()) - staticPosition -= po->xPos(); - right = Length(staticPosition, Fixed); - } - } - - // Calculate constraint equation values for 'width' case. - calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - m_width, m_marginLeft, m_marginRight, m_x); - // Calculate constraint equation values for 'max-width' case.calcContentWidth(width.width(containerWidth)); - if (style()->maxWidth().value() != UNDEFINED) { - short maxWidth; - short maxMarginLeft; - short maxMarginRight; - short maxXPos; - - calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - maxWidth, maxMarginLeft, maxMarginRight, maxXPos); - - if (m_width > maxWidth) { - m_width = maxWidth; - m_marginLeft = maxMarginLeft; - m_marginRight = maxMarginRight; - m_x = maxXPos; - } - } - - // Calculate constraint equation values for 'min-width' case. - if (style()->minWidth().value()) { - short minWidth; - short minMarginLeft; - short minMarginRight; - short minXPos; - - calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - minWidth, minMarginLeft, minMarginRight, minXPos); - - if (m_width < minWidth) { - m_width = minWidth; - m_marginLeft = minMarginLeft; - m_marginRight = minMarginRight; - m_x = minXPos; - } - } - - // Put m_width into correct form. - m_width += bordersPlusPadding; -} - -void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock, EDirection containerDirection, - const int containerWidth, const int bordersPlusPadding, - const Length left, const Length right, const Length marginLeft, const Length marginRight, - short& widthValue, short& marginLeftValue, short& marginRightValue, short& xPos) -{ - // 'left' and 'right' cannot both be 'auto' because one would of been - // converted to the static postion already - assert(!(left.isVariable() && right.isVariable())); - - int leftValue = 0; - - bool widthIsAuto = width.isVariable(); - bool leftIsAuto = left.isVariable(); - bool rightIsAuto = right.isVariable(); - - if (!leftIsAuto && !widthIsAuto && !rightIsAuto) { - /*-----------------------------------------------------------------------*\ - * If none of the three is 'auto': If both 'margin-left' and 'margin- - * right' are 'auto', solve the equation under the extra constraint that - * the two margins get equal values, unless this would make them negative, - * in which case when direction of the containing block is 'ltr' ('rtl'), - * set 'margin-left' ('margin-right') to zero and solve for 'margin-right' - * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto', - * solve the equation for that value. If the values are over-constrained, - * ignore the value for 'left' (in case the 'direction' property of the - * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') - * and solve for that value. - \*-----------------------------------------------------------------------*/ - // NOTE: It is not necessary to solve for 'right' in the over constrained - // case because the value is not used for any further calculations. - - leftValue = left.width(containerWidth); - widthValue = calcContentWidth(width.width(containerWidth)); - - const int availableSpace = containerWidth - (leftValue + widthValue + right.width(containerWidth) + bordersPlusPadding); - - // Margins are now the only unknown - if (marginLeft.isVariable() && marginRight.isVariable()) { - // Both margins auto, solve for equality - if (availableSpace >= 0) { - marginLeftValue = availableSpace / 2; // split the diference - marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences - } else { - // see FIXME 1 - if (containerDirection == LTR) { - marginLeftValue = 0; - marginRightValue = availableSpace; // will be negative - } else { - marginLeftValue = availableSpace; // will be negative - marginRightValue = 0; - } - } - } else if (marginLeft.isVariable()) { - // Solve for left margin - marginRightValue = marginRight.width(containerWidth); - marginLeftValue = availableSpace - marginRightValue; - } else if (marginRight.isVariable()) { - // Solve for right margin - marginLeftValue = marginLeft.width(containerWidth); - marginRightValue = availableSpace - marginLeftValue; - } else { - // Over-constrained, solve for left if direction is RTL - marginLeftValue = marginLeft.width(containerWidth); - marginRightValue = marginRight.width(containerWidth); - - // see FIXME 1 -- used to be "this->style()->direction()" - if (containerDirection == RTL) - leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue; - } - } else { - /*--------------------------------------------------------------------*\ - * Otherwise, set 'auto' values for 'margin-left' and 'margin-right' - * to 0, and pick the one of the following six rules that applies. - * - * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the - * width is shrink-to-fit. Then solve for 'left' - * - * OMIT RULE 2 AS IT SHOULD NEVER BE HIT - * ------------------------------------------------------------------ - * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if - * the 'direction' property of the containing block is 'ltr' set - * 'left' to the static position, otherwise set 'right' to the - * static position. Then solve for 'left' (if 'direction is 'rtl') - * or 'right' (if 'direction' is 'ltr'). - * ------------------------------------------------------------------ - * - * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the - * width is shrink-to-fit . Then solve for 'right' - * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve - * for 'left' - * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve - * for 'width' - * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve - * for 'right' - * - * Calculation of the shrink-to-fit width is similar to calculating the - * width of a table cell using the automatic table layout algorithm. - * Roughly: calculate the preferred width by formatting the content - * without breaking lines other than where explicit line breaks occur, - * and also calculate the preferred minimum width, e.g., by trying all - * possible line breaks. CSS 2.1 does not define the exact algorithm. - * Thirdly, calculate the available width: this is found by solving - * for 'width' after setting 'left' (in case 1) or 'right' (in case 3) - * to 0. - * - * Then the shrink-to-fit width is: - * kMin(kMax(preferred minimum width, available width), preferred width). - \*--------------------------------------------------------------------*/ - // NOTE: For rules 3 and 6 it is not necessary to solve for 'right' - // because the value is not used for any further calculations. - - // Calculate margins, 'auto' margins are ignored. - marginLeftValue = marginLeft.minWidth(containerWidth); - marginRightValue = marginRight.minWidth(containerWidth); - - const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding); - - // FIXME: Is there a faster way to find the correct case? - // Use rule/case that applies. - if (leftIsAuto && widthIsAuto && !rightIsAuto) { - // RULE 1: (use shrink-to-fit for width, and solve of left) - int rightValue = right.width(containerWidth); - - // FIXME: would it be better to have shrink-to-fit in one step? - int preferredWidth = m_maxWidth - bordersPlusPadding; - int preferredMinWidth = m_minWidth - bordersPlusPadding; - int availableWidth = availableSpace - rightValue; - widthValue = kMin(kMax(preferredMinWidth, availableWidth), preferredWidth); - leftValue = availableSpace - (widthValue + rightValue); - } else if (!leftIsAuto && widthIsAuto && rightIsAuto) { - // RULE 3: (use shrink-to-fit for width, and no need solve of right) - leftValue = left.width(containerWidth); - - // FIXME: would it be better to have shrink-to-fit in one step? - int preferredWidth = m_maxWidth - bordersPlusPadding; - int preferredMinWidth = m_minWidth - bordersPlusPadding; - int availableWidth = availableSpace - leftValue; - widthValue = kMin(kMax(preferredMinWidth, availableWidth), preferredWidth); - } else if (leftIsAuto && !width.isVariable() && !rightIsAuto) { - // RULE 4: (solve for left) - widthValue = calcContentWidth(width.width(containerWidth)); - leftValue = availableSpace - (widthValue + right.width(containerWidth)); - } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) { - // RULE 5: (solve for width) - leftValue = left.width(containerWidth); - widthValue = availableSpace - (leftValue + right.width(containerWidth)); - } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) { - // RULE 6: (no need solve for right) - leftValue = left.width(containerWidth); - widthValue = calcContentWidth(width.width(containerWidth)); - } - } - - // Use computed values to calculate the horizontal position. - xPos = leftValue + marginLeftValue + containerBlock->borderLeft(); -} - - -void RenderBox::calcAbsoluteVertical() -{ - if (isReplaced()) { - calcAbsoluteVerticalReplaced(); - return; - } - - // The following is based off of the W3C Working Draft from April 11, 2006 of - // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements" - // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height> - // (block-style-comments in this function and in calcAbsoluteVerticalValues() - // correspond to text from the spec) - - - // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); - const int containerHeight = containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom(); - - const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom(); - const Length marginTop = style()->marginTop(); - const Length marginBottom = style()->marginBottom(); - Length top = style()->top(); - Length bottom = style()->bottom(); - - /*---------------------------------------------------------------------------*\ - * For the purposes of this section and the next, the term "static position" - * (of an element) refers, roughly, to the position an element would have had - * in the normal flow. More precisely, the static position for 'top' is the - * distance from the top edge of the containing block to the top margin edge - * of a hypothetical box that would have been the first box of the element if - * its 'position' property had been 'static' and 'float' had been 'none'. The - * value is negative if the hypothetical box is above the containing block. - * - * But rather than actually calculating the dimensions of that hypothetical - * box, user agents are free to make a guess at its probable position. - * - * For the purposes of calculating the static position, the containing block - * of fixed positioned elements is the initial containing block instead of - * the viewport. - \*---------------------------------------------------------------------------*/ - - // Calculate the static distance if needed. - if (top.isVariable() && bottom.isVariable()) { - // m_staticY should already have been set through layout of the parent() - int staticTop = m_staticY - containerBlock->borderTop(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - staticTop += po->yPos(); - } - top.setValue(Fixed, staticTop); - } - - - int height; // Needed to compute overflow. - - // Calculate constraint equation values for 'height' case. - calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding, - top, bottom, marginTop, marginBottom, - height, m_marginTop, m_marginBottom, m_y); - - // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults). - // see FIXME 2 - - // Calculate constraint equation values for 'max-height' case. - if (style()->maxHeight().value() != UNDEFINED) { - int maxHeight; - short maxMarginTop; - short maxMarginBottom; - int maxYPos; - - calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding, - top, bottom, marginTop, marginBottom, - maxHeight, maxMarginTop, maxMarginBottom, maxYPos); - - if (height > maxHeight) { - height = maxHeight; - m_marginTop = maxMarginTop; - m_marginBottom = maxMarginBottom; - m_y = maxYPos; - } - } - - // Calculate constraint equation values for 'min-height' case. - if (style()->minHeight().value()) { - int minHeight; - short minMarginTop; - short minMarginBottom; - int minYPos; - - calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding, - top, bottom, marginTop, marginBottom, - minHeight, minMarginTop, minMarginBottom, minYPos); - - if (height < minHeight) { - height = minHeight; - m_marginTop = minMarginTop; - m_marginBottom = minMarginBottom; - m_y = minYPos; - } - } - - height += bordersPlusPadding; - - // Set final height value. - m_height = height; -} - -void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock, - const int containerHeight, const int bordersPlusPadding, - const Length top, const Length bottom, const Length marginTop, const Length marginBottom, - int& heightValue, short& marginTopValue, short& marginBottomValue, int& yPos) -{ - // 'top' and 'bottom' cannot both be 'auto' because 'top would of been - // converted to the static position in calcAbsoluteVertical() - assert(!(top.isVariable() && bottom.isVariable())); - - int contentHeight = m_height - bordersPlusPadding; - - int topValue = 0; - - bool heightIsAuto = height.isVariable(); - bool topIsAuto = top.isVariable(); - bool bottomIsAuto = bottom.isVariable(); - - if (isTable() && heightIsAuto) { - // Height is never unsolved for tables. "auto" means shrink to fit. - // Use our height instead. - heightValue = contentHeight; - heightIsAuto = false; - } else if (!heightIsAuto) { - heightValue = calcContentHeight(height.width(containerHeight)); - if (contentHeight > heightValue) { - if (!isTable()) - contentHeight = heightValue; - else - heightValue = contentHeight; - } - } - - - if (!topIsAuto && !heightIsAuto && !bottomIsAuto) { - /*-----------------------------------------------------------------------*\ - * If none of the three are 'auto': If both 'margin-top' and 'margin- - * bottom' are 'auto', solve the equation under the extra constraint that - * the two margins get equal values. If one of 'margin-top' or 'margin- - * bottom' is 'auto', solve the equation for that value. If the values - * are over-constrained, ignore the value for 'bottom' and solve for that - * value. - \*-----------------------------------------------------------------------*/ - // NOTE: It is not necessary to solve for 'bottom' in the over constrained - // case because the value is not used for any further calculations. - - topValue = top.width(containerHeight); - - const int availableSpace = containerHeight - (topValue + heightValue + bottom.width(containerHeight) + bordersPlusPadding); - - // Margins are now the only unknown - if (marginTop.isVariable() && marginBottom.isVariable()) { - // Both margins auto, solve for equality - // NOTE: This may result in negative values. - marginTopValue = availableSpace / 2; // split the diference - marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences - } else if (marginTop.isVariable()) { - // Solve for top margin - marginBottomValue = marginBottom.width(containerHeight); - marginTopValue = availableSpace - marginBottomValue; - } else if (marginBottom.isVariable()) { - // Solve for bottom margin - marginTopValue = marginTop.width(containerHeight); - marginBottomValue = availableSpace - marginTopValue; - } else { - // Over-constrained, (no need solve for bottom) - marginTopValue = marginTop.width(containerHeight); - marginBottomValue = marginBottom.width(containerHeight); - } - } else { - /*--------------------------------------------------------------------*\ - * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom' - * to 0, and pick the one of the following six rules that applies. - * - * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then - * the height is based on the content, and solve for 'top'. - * - * OMIT RULE 2 AS IT SHOULD NEVER BE HIT - * ------------------------------------------------------------------ - * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then - * set 'top' to the static position, and solve for 'bottom'. - * ------------------------------------------------------------------ - * - * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then - * the height is based on the content, and solve for 'bottom'. - * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and - * solve for 'top'. - * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and - * solve for 'height'. - * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and - * solve for 'bottom'. - \*--------------------------------------------------------------------*/ - // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom' - // because the value is not used for any further calculations. - - // Calculate margins, 'auto' margins are ignored. - marginTopValue = marginTop.minWidth(containerHeight); - marginBottomValue = marginBottom.minWidth(containerHeight); - - const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding); - - // Use rule/case that applies. - if (topIsAuto && heightIsAuto && !bottomIsAuto) { - // RULE 1: (height is content based, solve of top) - heightValue = contentHeight; - topValue = availableSpace - (heightValue + bottom.width(containerHeight)); - } - else if (topIsAuto && !heightIsAuto && bottomIsAuto) { - // RULE 2: (shouldn't happen) - } - else if (!topIsAuto && heightIsAuto && bottomIsAuto) { - // RULE 3: (height is content based, no need solve of bottom) - heightValue = contentHeight; - topValue = top.width(containerHeight); - } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) { - // RULE 4: (solve of top) - topValue = availableSpace - (heightValue + bottom.width(containerHeight)); - } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) { - // RULE 5: (solve of height) - topValue = top.width(containerHeight); - heightValue = kMax(0, availableSpace - (topValue + bottom.width(containerHeight))); - } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) { - // RULE 6: (no need solve of bottom) - topValue = top.width(containerHeight); - } - } - - // Use computed values to calculate the vertical position. - yPos = topValue + marginTopValue + containerBlock->borderTop(); -} - -void RenderBox::calcAbsoluteHorizontalReplaced() -{ - // The following is based off of the W3C Working Draft from April 11, 2006 of - // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements" - // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width> - // (block-style-comments in this function correspond to text from the spec and - // the numbers correspond to numbers in spec) - - // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); - - // FIXME: This is incorrect for cases where the container block is a relatively - // positioned inline. - const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight(); - - // To match WinIE, in quirks mode use the parent's 'direction' property - // instead of the the container block's. - EDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction(); - - // Variables to solve. - Length left = style()->left(); - Length right = style()->right(); - Length marginLeft = style()->marginLeft(); - Length marginRight = style()->marginRight(); - - - /*-----------------------------------------------------------------------*\ - * 1. The used value of 'width' is determined as for inline replaced - * elements. - \*-----------------------------------------------------------------------*/ - // NOTE: This value of width is FINAL in that the min/max width calculations - // are dealt with in calcReplacedWidth(). This means that the steps to produce - // correct max/min in the non-replaced version, are not necessary. - m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight(); - const int availableSpace = containerWidth - m_width; - - /*-----------------------------------------------------------------------*\ - * 2. If both 'left' and 'right' have the value 'auto', then if 'direction' - * of the containing block is 'ltr', set 'left' to the static position; - * else if 'direction' is 'rtl', set 'right' to the static position. - \*-----------------------------------------------------------------------*/ - if (left.isVariable() && right.isVariable()) { - // see FIXME 1 - if (containerDirection == LTR) { - // 'm_staticX' should already have been set through layout of the parent. - int staticPosition = m_staticX - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) - staticPosition += po->xPos(); - left.setValue(Fixed, staticPosition); - } else { - RenderObject* po = parent(); - // 'm_staticX' should already have been set through layout of the parent. - int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width(); - for (; po && po != containerBlock; po = po->parent()) - staticPosition -= po->xPos(); - right.setValue(Fixed, staticPosition); - } - } - - /*-----------------------------------------------------------------------*\ - * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' - * or 'margin-right' with '0'. - \*-----------------------------------------------------------------------*/ - if (left.isVariable() || right.isVariable()) { - if (marginLeft.isVariable()) - marginLeft.setValue(Fixed, 0); - if (marginRight.isVariable()) - marginRight.setValue(Fixed, 0); - } - - /*-----------------------------------------------------------------------*\ - * 4. If at this point both 'margin-left' and 'margin-right' are still - * 'auto', solve the equation under the extra constraint that the two - * margins must get equal values, unless this would make them negative, - * in which case when the direction of the containing block is 'ltr' - * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for - * 'margin-right' ('margin-left'). - \*-----------------------------------------------------------------------*/ - int leftValue = 0; - int rightValue = 0; - - if (marginLeft.isVariable() && marginRight.isVariable()) { - // 'left' and 'right' cannot be 'auto' due to step 3 - assert(!(left.isVariable() && right.isVariable())); - - leftValue = left.width(containerWidth); - rightValue = right.width(containerWidth); - - int difference = availableSpace - (leftValue + rightValue); - if (difference > 0) { - m_marginLeft = difference / 2; // split the diference - m_marginRight = difference - m_marginLeft; // account for odd valued differences - } else { - // see FIXME 1 - if (containerDirection == LTR) { - m_marginLeft = 0; - m_marginRight = difference; // will be negative - } else { - m_marginLeft = difference; // will be negative - m_marginRight = 0; - } - } - - /*-----------------------------------------------------------------------*\ - * 5. If at this point there is an 'auto' left, solve the equation for - * that value. - \*-----------------------------------------------------------------------*/ - } else if (left.isVariable()) { - m_marginLeft = marginLeft.width(containerWidth); - m_marginRight = marginRight.width(containerWidth); - rightValue = right.width(containerWidth); - - // Solve for 'left' - leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight); - } else if (right.isVariable()) { - m_marginLeft = marginLeft.width(containerWidth); - m_marginRight = marginRight.width(containerWidth); - leftValue = left.width(containerWidth); - - // Solve for 'right' - rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight); - } else if (marginLeft.isVariable()) { - m_marginRight = marginRight.width(containerWidth); - leftValue = left.width(containerWidth); - rightValue = right.width(containerWidth); - - // Solve for 'margin-left' - m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight); - } else if (marginRight.isVariable()) { - m_marginLeft = marginLeft.width(containerWidth); - leftValue = left.width(containerWidth); - rightValue = right.width(containerWidth); - - // Solve for 'margin-right' - m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft); - } - - /*-----------------------------------------------------------------------*\ - * 6. If at this point the values are over-constrained, ignore the value - * for either 'left' (in case the 'direction' property of the - * containing block is 'rtl') or 'right' (in case 'direction' is - * 'ltr') and solve for that value. - \*-----------------------------------------------------------------------*/ - else { - m_marginLeft = marginLeft.width(containerWidth); - m_marginRight = marginRight.width(containerWidth); - if (containerDirection == LTR) { - leftValue = left.width(containerWidth); - rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight); - } - else { - rightValue = right.width(containerWidth); - leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight); - } - } - - int totalWidth = m_width + leftValue + rightValue + m_marginLeft + m_marginRight; - if (totalWidth > containerWidth && (containerDirection == RTL)) - leftValue = containerWidth - (totalWidth - leftValue); - - // Use computed values to calculate the horizontal position. - m_x = leftValue + m_marginLeft + containerBlock->borderLeft(); -} - -void RenderBox::calcAbsoluteVerticalReplaced() -{ - // The following is based off of the W3C Working Draft from April 11, 2006 of - // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements" - // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height> - // (block-style-comments in this function correspond to text from the spec and - // the numbers correspond to numbers in spec) - - // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); - const int containerHeight = containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom(); - - // Variables to solve. - Length top = style()->top(); - Length bottom = style()->bottom(); - Length marginTop = style()->marginTop(); - Length marginBottom = style()->marginBottom(); - - - /*-----------------------------------------------------------------------*\ - * 1. The used value of 'height' is determined as for inline replaced - * elements. - \*-----------------------------------------------------------------------*/ - // NOTE: This value of height is FINAL in that the min/max height calculations - // are dealt with in calcReplacedHeight(). This means that the steps to produce - // correct max/min in the non-replaced version, are not necessary. - m_height = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); - const int availableSpace = containerHeight - m_height; - - /*-----------------------------------------------------------------------*\ - * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' - * with the element's static position. - \*-----------------------------------------------------------------------*/ - if (top.isVariable() && bottom.isVariable()) { - // m_staticY should already have been set through layout of the parent(). - int staticTop = m_staticY - containerBlock->borderTop(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - staticTop += po->yPos(); - } - top.setValue(Fixed, staticTop); - } - - /*-----------------------------------------------------------------------*\ - * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or - * 'margin-bottom' with '0'. - \*-----------------------------------------------------------------------*/ - // FIXME: The spec. says that this step should only be taken when bottom is - // auto, but if only top is auto, this makes step 4 impossible. - if (top.isVariable() || bottom.isVariable()) { - if (marginTop.isVariable()) - marginTop.setValue(Fixed, 0); - if (marginBottom.isVariable()) - marginBottom.setValue(Fixed, 0); - } - - /*-----------------------------------------------------------------------*\ - * 4. If at this point both 'margin-top' and 'margin-bottom' are still - * 'auto', solve the equation under the extra constraint that the two - * margins must get equal values. - \*-----------------------------------------------------------------------*/ - int topValue = 0; - int bottomValue = 0; - - if (marginTop.isVariable() && marginBottom.isVariable()) { - // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded. - assert(!(top.isVariable() || bottom.isVariable())); - - topValue = top.width(containerHeight); - bottomValue = bottom.width(containerHeight); - - int difference = availableSpace - (topValue + bottomValue); - // NOTE: This may result in negative values. - m_marginTop = difference / 2; // split the difference - m_marginBottom = difference - m_marginTop; // account for odd valued differences - - /*-----------------------------------------------------------------------*\ - * 5. If at this point there is only one 'auto' left, solve the equation - * for that value. - \*-----------------------------------------------------------------------*/ - } else if (top.isVariable()) { - m_marginTop = marginTop.width(containerHeight); - m_marginBottom = marginBottom.width(containerHeight); - bottomValue = bottom.width(containerHeight); - - // Solve for 'top' - topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom); - } else if (bottom.isVariable()) { - m_marginTop = marginTop.width(containerHeight); - m_marginBottom = marginBottom.width(containerHeight); - topValue = top.width(containerHeight); - - // Solve for 'bottom' - // NOTE: It is not necessary to solve for 'bottom' because we don't ever - // use the value. - } else if (marginTop.isVariable()) { - m_marginBottom = marginBottom.width(containerHeight); - topValue = top.width(containerHeight); - bottomValue = bottom.width(containerHeight); - - // Solve for 'margin-top' - m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom); - } else if (marginBottom.isVariable()) { - m_marginTop = marginTop.width(containerHeight); - topValue = top.width(containerHeight); - bottomValue = bottom.width(containerHeight); - - // Solve for 'margin-bottom' - m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop); - } - - /*-----------------------------------------------------------------------*\ - * 6. If at this point the values are over-constrained, ignore the value - * for 'bottom' and solve for that value. - \*-----------------------------------------------------------------------*/ - else { - m_marginTop = marginTop.width(containerHeight); - m_marginBottom = marginBottom.width(containerHeight); - topValue = top.width(containerHeight); - - // Solve for 'bottom' - // NOTE: It is not necessary to solve for 'bottom' because we don't ever - // use the value. - } - - // Use computed values to calculate the vertical position. - m_y = topValue + m_marginTop + containerBlock->borderTop(); -} - -int RenderBox::highestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const -{ - return includeSelf ? 0 : m_height; -} - -int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const -{ - return includeSelf ? m_height : 0; -} - -int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const -{ - return includeSelf ? m_width : 0; -} - -int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const -{ - return includeSelf ? 0 : m_width; -} - -int RenderBox::pageTopAfter(int y) const -{ - RenderObject* cb = container(); - if (cb) - return cb->pageTopAfter(y+yPos()) - yPos(); - else - return 0; -} - -int RenderBox::crossesPageBreak(int t, int b) const -{ - RenderObject* cb = container(); - if (cb) - return cb->crossesPageBreak(yPos()+t, yPos()+b); - else - return false; -} - -void RenderBox::caretPos(int /*offset*/, int flags, int &_x, int &_y, int &width, int &height) -{ -#if 0 - _x = -1; - - // propagate it downwards to its children, someone will feel responsible - RenderObject *child = firstChild(); -// if (child) kdDebug(6040) << "delegating caretPos to " << child->renderName() << endl; - if (child) child->caretPos(offset, override, _x, _y, width, height); - - // if not, use the extents of this box. offset 0 means left, offset 1 means - // right - if (_x == -1) { - //kdDebug(6040) << "no delegation" << endl; - _x = xPos() + (offset == 0 ? 0 : m_width); - _y = yPos(); - height = m_height; - width = override && offset == 0 ? m_width : 1; - - // If height of box is smaller than font height, use the latter one, - // otherwise the caret might become invisible. - // FIXME: ignoring :first-line, missing good reason to take care of - int fontHeight = style()->fontMetrics().height(); - if (fontHeight > height) - height = fontHeight; - - int absx, absy; - - RenderObject *cb = containingBlock(); - - if (cb && cb != this && cb->absolutePosition(absx,absy)) { - //kdDebug(6040) << "absx=" << absx << " absy=" << absy << endl; - _x += absx; - _y += absy; - } else { - // we don't know our absolute position, and there is no point returning - // just a relative one - _x = _y = -1; - } - } -#endif - - _x = xPos(); - _y = yPos(); -// kdDebug(6040) << "_x " << _x << " _y " << _y << endl; - width = 1; // no override is indicated in boxes - - RenderBlock *cb = containingBlock(); - - // Place caret outside the border - if (flags & CFOutside) { - - RenderStyle *s = element() && element()->parent() - && element()->parent()->renderer() - ? element()->parent()->renderer()->style() - : cb->style(); - - const TQFontMetrics &fm = s->fontMetrics(); - height = fm.height(); - - bool rtl = s->direction() == RTL; - bool outsideEnd = flags & CFOutsideEnd; - - if (outsideEnd) { - _x += this->width(); - } else { - _x--; - } - - int hl = fm.leading() / 2; - if (!isReplaced() || style()->display() == BLOCK) { - if (!outsideEnd ^ rtl) - _y -= hl; - else - _y += kMax(this->height() - fm.ascent() - hl, 0); - } else { - _y += baselinePosition(false) - fm.ascent() - hl; - } - - // Place caret inside the element - } else { - const TQFontMetrics &fm = style()->fontMetrics(); - height = fm.height(); - - RenderStyle *s = style(); - - _x += borderLeft() + paddingLeft(); - _y += borderTop() + paddingTop(); - - // ### regard direction - switch (s->textAlign()) { - case LEFT: - case KHTML_LEFT: - case TAAUTO: // ### find out what this does - case JUSTIFY: - break; - case CENTER: - case KHTML_CENTER: - _x += contentWidth() / 2; - break; - case KHTML_RIGHT: - case RIGHT: - _x += contentWidth(); - break; - } - } - - int absx, absy; - if (cb && cb != this && cb->absolutePosition(absx,absy)) { -// kdDebug(6040) << "absx=" << absx << " absy=" << absy << endl; - _x += absx; - _y += absy; - } else { - // we don't know our absolute position, and there is no point returning - // just a relative one - _x = _y = -1; - } -} - -#undef DEBUG_LAYOUT diff --git a/khtml/rendering/render_box.h b/khtml/rendering/render_box.h deleted file mode 100644 index c0c618d5c..000000000 --- a/khtml/rendering/render_box.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -#ifndef RENDER_BOX_H -#define RENDER_BOX_H - -#include "render_container.h" - -namespace khtml { - -enum WidthType { Width, MinWidth, MaxWidth }; -enum HeightType { Height, MinHeight, MaxHeight }; - -class RenderBlock; - -class RenderBox : public RenderContainer -{ - - -// combines ElemImpl & PosElImpl (all rendering objects are positioned) -// should contain all border and padding handling - -public: - RenderBox(DOM::NodeImpl* node); - virtual ~RenderBox(); - - virtual const char *renderName() const { return "RenderBox"; } - virtual bool isBox() const { return true; } - - virtual void setStyle(RenderStyle *style); - virtual void paint(PaintInfo& i, int _tx, int _ty); - - virtual void close(); - - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox); - virtual void deleteInlineBoxes(RenderArena* arena=0); - - virtual void detach(); - - virtual short minWidth() const { return m_minWidth; } - virtual int maxWidth() const { return m_maxWidth; } - - virtual short contentWidth() const; - virtual int contentHeight() const; - - virtual bool absolutePosition(int &xPos, int &yPos, bool f = false) const; - - virtual void setPos( int xPos, int yPos ); - - virtual int xPos() const { return m_x; } - virtual int yPos() const { return m_y; } - virtual short width() const; - virtual int height() const; - - virtual short marginTop() const { return m_marginTop; } - virtual short marginBottom() const { return m_marginBottom; } - virtual short marginLeft() const { return m_marginLeft; } - virtual short marginRight() const { return m_marginRight; } - - virtual void setWidth( int width ); - virtual void setHeight( int height ); - - virtual void position(InlineBox* box, int from, int len, bool reverse); - - virtual int highestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - - virtual void repaint(Priority p=NormalPriority); - - virtual void repaintRectangle(int x, int y, int w, int h, Priority p=NormalPriority, bool f=false); - - virtual short containingBlockWidth() const; - void relativePositionOffset(int &tx, int &ty) const; - - virtual void calcWidth(); - virtual void calcHeight(); - - virtual short calcReplacedWidth() const; - virtual int calcReplacedHeight() const; - - virtual int availableHeight() const; - virtual int availableWidth() const; - - void calcVerticalMargins(); - - virtual RenderLayer* layer() const { return m_layer; } - - void setStaticX(short staticX); - void setStaticY(int staticY); - int staticX() const { return m_staticX; } - int staticY() const { return m_staticY; } - - virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height); - - void calcHorizontalMargins(const Length& ml, const Length& mr, int cw); - RenderBlock* createAnonymousBlock(); - - virtual int pageTopAfter(int y) const; - virtual int crossesPageBreak(int t, int b) const; - - int calcBoxWidth(int w) const; - int calcBoxHeight(int h) const; - int calcContentWidth(int w) const; - int calcContentHeight(int h) const; - -protected: - int calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType); - int calcHeightUsing(const Length& height); - int calcReplacedWidthUsing(WidthType widthType) const; - int calcReplacedHeightUsing(HeightType heightType) const; - int calcPercentageHeight(const Length& height, bool treatAsReplaced = false) const; - int availableHeightUsing(const Length& h) const; - int availableWidthUsing(const Length& w) const; - int calcImplicitHeight() const; - bool hasImplicitHeight() const { - return isPositioned() && !style()->top().isVariable() && !style()->bottom().isVariable(); - } - -protected: - virtual void paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty); - void paintRootBoxDecorations( PaintInfo& paintInfo, int _tx, int _ty); - - void paintBackgrounds(TQPainter *p, const TQColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int h); - void paintBackground(TQPainter *p, const TQColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int h); - - virtual void paintBackgroundExtended(TQPainter* /*p*/, const TQColor& /*c*/, const BackgroundLayer* /*bgLayer*/, - int /*clipy*/, int /*cliph*/, int /*_tx*/, int /*_ty*/, - int /*w*/, int /*height*/, int /*bleft*/, int /*bright*/, int /*pleft*/, int /*pright*/ ); - - void outlineBox(TQPainter *p, int _tx, int _ty, const char *color = "red"); - - void calcAbsoluteHorizontal(); - void calcAbsoluteVertical(); - void calcAbsoluteHorizontalValues(Length width, const RenderObject* cb, EDirection containerDirection, - const int containerWidth, const int bordersPlusPadding, - const Length left, const Length right, const Length marginLeft, const Length marginRight, - short& widthValue, short& marginLeftValue, short& marginRightValue, short& xPos); - void calcAbsoluteVerticalValues(Length height, const RenderObject* cb, - const int containerHeight, const int bordersPlusPadding, - const Length top, const Length bottom, const Length marginTop, const Length marginBottom, - int& heightValue, short& marginTopValue, short& marginBottomValue, int& yPos); - - void calcAbsoluteVerticalReplaced(); - void calcAbsoluteHorizontalReplaced(); - - TQRect getOverflowClipRect(int tx, int ty); - TQRect getClipRect(int tx, int ty); - - void restructureParentFlow(); - - - // the actual height of the contents + borders + padding (border-box) - int m_height; - int m_y; - - short m_width; - short m_x; - - short m_marginTop; - short m_marginBottom; - - short m_marginLeft; - short m_marginRight; - - /* - * the minimum width the element needs, to be able to render - * its content without clipping - */ - short m_minWidth; - /* The maximum width the element can fill horizontally - * ( = the width of the element with line breaking disabled) - */ - int m_maxWidth; - - // Cached normal flow values for absolute positioned elements with static left/top values. - short m_staticX; - int m_staticY; - - RenderLayer *m_layer; - - /* A box used to represent this object on a line - * when its inner content isn't contextually relevant - * (e.g replaced or positioned elements) - */ - InlineBox *m_placeHolderBox; -}; - - -} //namespace - -#endif diff --git a/khtml/rendering/render_br.cpp b/khtml/rendering/render_br.cpp deleted file mode 100644 index 69984b760..000000000 --- a/khtml/rendering/render_br.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 2000 Lars Knoll (knoll@kde.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_br.h" - -using namespace khtml; - - -RenderBR::RenderBR(DOM::NodeImpl* node) - : RenderText(node, new DOM::DOMStringImpl(TQChar('\n'))) -{ - m_hasReturn = true; -} - -RenderBR::~RenderBR() -{ -} - -#if 0 -void RenderBR::caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) -{ - RenderText::caretPos(offset,flags,_x,_y,width,height); - return; -#if 0 - if (previousSibling() && !previousSibling()->isBR() && !previousSibling()->isFloating()) { - int offset = 0; - if (previousSibling()->isText()) - offset = static_cast<RenderText*>(previousSibling())->maxOffset(); - - // FIXME: this won't return a big width in override mode (LS) - previousSibling()->caretPos(offset,override,_x,_y,width,height); - return; - } - - int absx, absy; - absolutePosition(absx,absy); - if (absx == -1) { - // we don't know out absolute position, and there is no point returning - // just a relative one - _x = _y = -1; - } - else { - _x += absx; - _y += absy; - } - height = RenderText::verticalPositionHint( false ); - width = override ? height / 2 : 1; -#endif -} -#endif - -FindSelectionResult RenderBR::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset, SelPointState &state) -{ - // Simply take result of previous one - RenderText *prev = static_cast<RenderText *>(previousSibling()); - if (!prev || !prev->isText() || !prev->inlineTextBoxCount() || prev->isBR()) - prev = this; - - //kdDebug(6040) << "delegated to " << prev->renderName() << "@" << prev << endl; - return prev->RenderText::checkSelectionPoint(_x, _y, _tx, _ty, node, offset, state); -} diff --git a/khtml/rendering/render_br.h b/khtml/rendering/render_br.h deleted file mode 100644 index f4175015f..000000000 --- a/khtml/rendering/render_br.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 2000 Lars Knoll (knoll@kde.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. - * - */ -#ifndef RENDER_BR_H -#define RENDER_BR_H - -#include "render_text.h" - -/* - * The whole class here is a hack to get <br> working, as long as we don't have support for - * CSS2 :before and :after pseudo elements - */ -namespace khtml { - -class RenderBR : public RenderText -{ -public: - RenderBR(DOM::NodeImpl* node); - virtual ~RenderBR(); - - virtual const char *renderName() const { return "RenderBR"; } - - virtual void paint( PaintInfo&, int, int) {} - - virtual unsigned int width(unsigned int, unsigned int, const Font *) const { return 0; } - virtual unsigned int width( unsigned int, unsigned int, bool) const { return 0; } - virtual short width() const { return RenderText::width(); } - - virtual int height() const { return 0; } - - // overrides - virtual void calcMinMaxWidth() {} - virtual short minWidth() const { return 0; } - virtual int maxWidth() const { return 0; } - - virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty, - DOM::NodeImpl*& node, int & offset, - SelPointState & ); - - virtual bool isBR() const { return true; } -#if 0 - virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height); -#endif - /** returns the lowest possible value the caret offset may have to - * still point to a valid position. - * - * Returns 0. - */ - virtual long minOffset() const { return 0; } - /** returns the highest possible value the caret offset may have to - * still point to a valid position. - * - * Returns also 0, as BRs have no width. - */ - virtual long maxOffset() const { return 0; } -}; - -} -#endif diff --git a/khtml/rendering/render_canvas.cpp b/khtml/rendering/render_canvas.cpp deleted file mode 100644 index e8540eba6..000000000 --- a/khtml/rendering/render_canvas.cpp +++ /dev/null @@ -1,780 +0,0 @@ -/** - * This file is part of the HTML widget for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2003 Apple Computer, Inc. - * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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 "rendering/render_canvas.h" -#include "rendering/render_layer.h" -#include "xml/dom_docimpl.h" - -#include "khtmlview.h" -#include "khtml_part.h" -#include <kdebug.h> -#include <kglobal.h> - -using namespace khtml; - -//#define BOX_DEBUG -//#define SPEED_DEBUG - -RenderCanvas::RenderCanvas(DOM::NodeImpl* node, KHTMLView *view) - : RenderBlock(node) -{ - // init RenderObject attributes - setInline(false); - setIsAnonymous(false); - - m_view = view; - // try to contrain the width to the views width - - m_minWidth = 0; - m_height = 0; - - m_width = m_minWidth; - m_maxWidth = m_minWidth; - - m_rootWidth = m_rootHeight = 0; - m_viewportWidth = m_viewportHeight = 0; - m_cachedDocWidth = m_cachedDocHeight = -1; - - setPositioned(true); // to 0,0 :) - - m_staticMode = false; - m_pagedMode = false; - m_printImages = true; - - m_pageTop = 0; - m_pageBottom = 0; - - m_page = 0; - - m_maximalOutlineSize = 0; - - m_selectionStart = 0; - m_selectionEnd = 0; - m_selectionStartPos = -1; - m_selectionEndPos = -1; - - m_needsWidgetMasks = false; - - // Create a new root layer for our layer hierarchy. - m_layer = new (node->getDocument()->renderArena()) RenderLayer(this); -} - -RenderCanvas::~RenderCanvas() -{ - delete m_page; -} - -void RenderCanvas::setStyle(RenderStyle* style) -{ - /* - if (m_pagedMode) - style->setOverflow(OHIDDEN); */ - RenderBlock::setStyle(style); -} - -void RenderCanvas::calcHeight() -{ - if (m_pagedMode || !m_view) - m_height = m_rootHeight; - else - m_height = m_view->visibleHeight(); -} - -void RenderCanvas::calcWidth() -{ - // the width gets set by KHTMLView::print when printing to a printer. - if(m_pagedMode || !m_view) - { - m_width = m_rootWidth; - return; - } - - m_width = m_view ? m_view->frameWidth() : m_minWidth; - - if (style()->marginLeft().isFixed()) - m_marginLeft = style()->marginLeft().value(); - else - m_marginLeft = 0; - - if (style()->marginRight().isFixed()) - m_marginRight = style()->marginRight().value(); - else - m_marginRight = 0; -} - -void RenderCanvas::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - RenderBlock::calcMinMaxWidth(); - - m_maxWidth = m_minWidth; - - setMinMaxKnown(); -} - -//#define SPEED_DEBUG - -void RenderCanvas::layout() -{ - if (m_pagedMode) { - m_minWidth = m_width; -// m_maxWidth = m_width; - } - - m_needsFullRepaint = markedForRepaint() || !view() || view()->needsFullRepaint() || m_pagedMode; - - setChildNeedsLayout(true); - setMinMaxKnown(false); - for(RenderObject* c = firstChild(); c; c = c->nextSibling()) - c->setChildNeedsLayout(true); - - int oldWidth = m_width; - int oldHeight = m_height; - - m_cachedDocWidth = m_cachedDocHeight = -1; - - if (m_pagedMode || !m_view) { - m_width = m_rootWidth; - m_height = m_rootHeight; - } - else - { - m_viewportWidth = m_width = m_view->visibleWidth(); - m_viewportHeight = m_height = m_view->visibleHeight(); - } - -#ifdef SPEED_DEBUG - TQTime qt; - qt.start(); -#endif - - if ( recalcMinMax() ) - recalcMinMaxWidths(); - -#ifdef SPEED_DEBUG - kdDebug() << "RenderCanvas::calcMinMax time used=" << qt.elapsed() << endl; - qt.start(); -#endif - - bool relayoutChildren = (oldWidth != m_width) || (oldHeight != m_height); - - RenderBlock::layoutBlock( relayoutChildren ); - -#ifdef SPEED_DEBUG - kdDebug() << "RenderCanvas::layout time used=" << qt.elapsed() << endl; - qt.start(); -#endif - - updateDocumentSize(); - - layer()->updateLayerPositions( layer(), needsFullRepaint(), true ); - - if (!m_pagedMode && m_needsWidgetMasks) - layer()->updateWidgetMasks(layer()); - - scheduleDeferredRepaints(); - setNeedsLayout(false); - -#ifdef SPEED_DEBUG - kdDebug() << "RenderCanvas::end time used=" << qt.elapsed() << endl; -#endif -} - -void RenderCanvas::updateDocumentSize() -{ - // update our cached document size - int hDocH = m_cachedDocHeight = docHeight(); - int hDocW = m_cachedDocWidth = docWidth(); - - if (!m_pagedMode && m_view) { - - bool vss = m_view->verticalScrollBar()->isShown(); - bool hss = m_view->horizontalScrollBar()->isShown(); - TQSize s = m_view->viewportSize(m_cachedDocWidth, m_cachedDocHeight); - - // 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 = kMin( m_cachedDocWidth, s.width() ); - - if (!hss && m_height - m_view->horizontalScrollBar()->sizeHint().height() == s.height() && - m_cachedDocHeight <= m_height) - hDocH = kMin( m_cachedDocHeight, 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()) - hDocW = s.width()+1; - - if (hss && s.height() > m_cachedDocHeight && m_cachedDocHeight > m_view->visibleHeight()) - hDocH = s.height()+1; - - m_view->resizeContents(hDocW, hDocH); - - setWidth( m_viewportWidth = s.width() ); - setHeight( m_viewportHeight = s.height() ); - } - layer()->resize( kMax( m_cachedDocWidth,int( m_width ) ), kMax( m_cachedDocHeight,m_height ) ); -} - -void RenderCanvas::updateDocSizeAfterLayerTranslation( RenderObject* o, bool posXOffset, bool posYOffset ) -{ - if (needsLayout()) - return; - int rightmost, lowest; - o->absolutePosition( rightmost, lowest ); - if (posXOffset) { - rightmost += o->rightmostPosition(false, true); - setCachedDocWidth( kMax(docWidth(), rightmost) ); - } else { - setCachedDocWidth( -1 ); - } - if (posYOffset) { - lowest += o->lowestPosition(false, true); - setCachedDocHeight( kMax(docHeight(), lowest) ); - } else { - setCachedDocHeight( -1 ); - } -// kdDebug() << " posXOffset: " << posXOffset << " posYOffset " << posYOffset << " m_cachedDocWidth " << m_cachedDocWidth << " m_cachedDocHeight " << m_cachedDocHeight << endl; - updateDocumentSize(); -} - -bool RenderCanvas::needsFullRepaint() const -{ - return m_needsFullRepaint || m_pagedMode; -} - -void RenderCanvas::repaintViewRectangle(int x, int y, int w, int h, bool asap) -{ - KHTMLAssert( view() ); - view()->scheduleRepaint( x, y, w, h, asap ); -} - -bool RenderCanvas::absolutePosition(int &xPos, int &yPos, bool f) const -{ - if ( f && m_pagedMode) { - xPos = 0; - yPos = m_pageTop; - } - else if ( f && m_view) { - xPos = m_view->contentsX(); - yPos = m_view->contentsY(); - } - else { - xPos = yPos = 0; - } - return true; -} - -void RenderCanvas::paint(PaintInfo& paintInfo, int _tx, int _ty) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl; -#endif - - // 1. paint background, borders etc - if(paintInfo.phase == PaintActionElementBackground) { - paintBoxDecorations(paintInfo, _tx, _ty); - return; - } - - // 2. paint contents - for( RenderObject *child = firstChild(); child; child=child->nextSibling()) - if(!child->layer() && !child->isFloating()) - child->paint(paintInfo, _tx, _ty); - - // 3. paint floats. - if (paintInfo.phase == PaintActionFloat) - paintFloats(paintInfo, _tx, _ty); - -#ifdef BOX_DEBUG - if (m_view) - { - _tx += m_view->contentsX(); - _ty += m_view->contentsY(); - } - - outlineBox(p, _tx, _ty); -#endif - -} - -void RenderCanvas::paintBoxDecorations(PaintInfo& paintInfo, int /*_tx*/, int /*_ty*/) -{ - if ((firstChild() && firstChild()->style()->visibility() == VISIBLE) || !view()) - return; - - paintInfo.p->fillRect(paintInfo.r, view()->palette().active().color(TQColorGroup::Base)); -} - -void RenderCanvas::repaintRectangle(int x, int y, int w, int h, Priority p, bool f) -{ - if (m_staticMode) return; -// kdDebug( 6040 ) << "updating views contents (" << x << "/" << y << ") (" << w << "/" << h << ")" << endl; - - if (f && m_pagedMode) { - y += m_pageTop; - } else - if ( f && m_view ) { - x += m_view->contentsX(); - y += m_view->contentsY(); - } - - TQRect vr = viewRect(); - TQRect ur(x, y, w, h); - - if (m_view && ur.intersects(vr)) { - - if (p == RealtimePriority) - // ### KWQ's updateContents has an additional parameter "now". - // It's not clear what the difference between updateContents(...,true) - // and repaintContents(...) is. As Qt doesn't have this, I'm leaving it out. (LS) - m_view->updateContents(ur/*, true*/); - else if (p == HighPriority) - m_view->scheduleRepaint(x, y, w, h, true /*asap*/); - else - m_view->scheduleRepaint(x, y, w, h); - } -} - -void RenderCanvas::deferredRepaint( RenderObject* o ) -{ - m_dirtyChildren.append( o ); -} - -void RenderCanvas::scheduleDeferredRepaints() -{ - if (!needsFullRepaint()) { - TQValueList<RenderObject*>::const_iterator it; - for ( it = m_dirtyChildren.begin(); it != m_dirtyChildren.end(); ++it ) - (*it)->repaint(); - } - //kdDebug(6040) << "scheduled deferred repaints: " << m_dirtyChildren.count() << " needed full repaint: " << needsFullRepaint() << endl; - m_dirtyChildren.clear(); -} - -void RenderCanvas::repaint(Priority p) -{ - if (m_view && !m_staticMode) { - if (p == RealtimePriority) { - //m_view->resizeContents(docWidth(), docHeight()); - m_view->unscheduleRepaint(); - if (needsLayout()) { - m_view->scheduleRelayout(); - return; - } - // ### same as in repaintRectangle - m_view->updateContents(m_view->contentsX(), m_view->contentsY(), - m_view->visibleWidth(), m_view->visibleHeight()/*, true*/); - } - else if (p == HighPriority) - m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(), - m_view->visibleWidth(), m_view->visibleHeight(), true /*asap*/); - else - m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(), - m_view->visibleWidth(), m_view->visibleHeight()); - } -} - -static TQRect enclosingPositionedRect (RenderObject *n) -{ - RenderObject *enclosingParent = n->containingBlock(); - TQRect rect(0,0,0,0); - if (enclosingParent) { - int ox, oy; - enclosingParent->absolutePosition(ox, oy); - int off = 0; - if (!enclosingParent->hasOverflowClip()) { - ox += enclosingParent->overflowLeft(); - oy += enclosingParent->overflowTop(); - } - rect.setX(ox); - rect.setY(oy); - rect.setWidth(enclosingParent->effectiveWidth()); - rect.setHeight(enclosingParent->effectiveHeight()); - } - return rect; -} - -TQRect RenderCanvas::selectionRect() const -{ - RenderObject *r = m_selectionStart; - if (!r) - return TQRect(); - - TQRect selectionRect = enclosingPositionedRect(r); - - while (r && r != m_selectionEnd) - { - RenderObject* n; - if ( !(n = r->firstChild()) ){ - if ( !(n = r->nextSibling()) ) - { - n = r->parent(); - while (n && !n->nextSibling()) - n = n->parent(); - if (n) - n = n->nextSibling(); - } - } - r = n; - if (r) { - selectionRect = selectionRect.unite(enclosingPositionedRect(r)); - } - } - - return selectionRect; -} - -void RenderCanvas::setSelection(RenderObject *s, int sp, RenderObject *e, int ep) -{ - // Check we got valid renderobjects. www.msnbc.com and clicking - // around, to find the case where this happened. - if ( !s || !e ) - { - kdWarning(6040) << "RenderCanvas::setSelection() called with start=" << s << " end=" << e << endl; - return; - } -// kdDebug( 6040 ) << "RenderCanvas::setSelection(" << s << "," << sp << "," << e << "," << ep << ")" << endl; - - bool changedSelectionBorder = ( s != m_selectionStart || e != m_selectionEnd ); - - // Cut out early if the selection hasn't changed. - if ( !changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos == ep ) - return; - - // Record the old selected objects. Will be used later - // to delta against the selected objects. - - RenderObject *oldStart = m_selectionStart; - int oldStartPos = m_selectionStartPos; - RenderObject *oldEnd = m_selectionEnd; - int oldEndPos = m_selectionEndPos; - TQPtrList<RenderObject> oldSelectedInside; - TQPtrList<RenderObject> newSelectedInside; - RenderObject *os = oldStart; - - while (os && os != oldEnd) - { - RenderObject* no; - if ( !(no = os->firstChild()) ){ - if ( !(no = os->nextSibling()) ) - { - no = os->parent(); - while (no && !no->nextSibling()) - no = no->parent(); - if (no) - no = no->nextSibling(); - } - } - if (os->selectionState() == SelectionInside && !oldSelectedInside.containsRef(os)) - oldSelectedInside.append(os); - - os = no; - } - if (changedSelectionBorder) - clearSelection(false); - - while (s->firstChild()) - s = s->firstChild(); - while (e->lastChild()) - e = e->lastChild(); - -#if 0 - bool changedSelectionBorder = ( s != m_selectionStart || e != m_selectionEnd ); - - if ( !changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos = ep ) - return; -#endif - - // set selection start - if (m_selectionStart) - m_selectionStart->setIsSelectionBorder(false); - m_selectionStart = s; - if (m_selectionStart) - m_selectionStart->setIsSelectionBorder(true); - m_selectionStartPos = sp; - - // set selection end - if (m_selectionEnd) - m_selectionEnd->setIsSelectionBorder(false); - m_selectionEnd = e; - if (m_selectionEnd) - m_selectionEnd->setIsSelectionBorder(true); - m_selectionEndPos = ep; - -#if 0 - kdDebug( 6040 ) << "old selection (" << oldStart << "," << oldStartPos << "," << oldEnd << "," << oldEndPos << ")" << endl; - kdDebug( 6040 ) << "new selection (" << s << "," << sp << "," << e << "," << ep << ")" << endl; -#endif - - // update selection status of all objects between m_selectionStart and m_selectionEnd - RenderObject* o = s; - - while (o && o!=e) - { - o->setSelectionState(SelectionInside); -// kdDebug( 6040 ) << "setting selected " << o << ", " << o->isText() << endl; - RenderObject* no; - if ( !(no = o->firstChild()) ) - if ( !(no = o->nextSibling()) ) - { - no = o->parent(); - while (no && !no->nextSibling()) - no = no->parent(); - if (no) - no = no->nextSibling(); - } - if (o->selectionState() == SelectionInside && !newSelectedInside.containsRef(o)) - newSelectedInside.append(o); - - o=no; - } - s->setSelectionState(SelectionStart); - e->setSelectionState(SelectionEnd); - if(s == e) s->setSelectionState(SelectionBoth); - - if (!m_view) - return; - - newSelectedInside.removeRef(s); - newSelectedInside.removeRef(e); - - TQRect updateRect; - - // Don't use repaint() because it will cause all rects to - // be united (see khtmlview::scheduleRepaint()). Instead - // just draw damage rects for objects that have a change - // in selection state. - // ### for Qt, updateContents will unite them, too. This has to be - // circumvented somehow (LS) - - // Are any of the old fully selected objects not in the new selection? - // If so we have to draw them. - // Could be faster by building list of non-intersecting rectangles rather - // than unioning rectangles. - TQPtrListIterator<RenderObject> oldIterator(oldSelectedInside); - bool firstRect = true; - for (; oldIterator.current(); ++oldIterator){ - if (!newSelectedInside.containsRef(oldIterator.current())){ - if (firstRect){ - updateRect = enclosingPositionedRect(oldIterator.current()); - firstRect = false; - } - else - updateRect = updateRect.unite(enclosingPositionedRect(oldIterator.current())); - } - } - if (!firstRect){ - m_view->updateContents( updateRect ); - } - - // Are any of the new fully selected objects not in the previous selection? - // If so we have to draw them. - // Could be faster by building list of non-intersecting rectangles rather - // than unioning rectangles. - TQPtrListIterator<RenderObject> newIterator(newSelectedInside); - firstRect = true; - for (; newIterator.current(); ++newIterator){ - if (!oldSelectedInside.containsRef(newIterator.current())){ - if (firstRect){ - updateRect = enclosingPositionedRect(newIterator.current()); - firstRect = false; - } - else - updateRect = updateRect.unite(enclosingPositionedRect(newIterator.current())); - } - } - if (!firstRect) { - m_view->updateContents( updateRect ); - } - - // Is the new starting object different, or did the position in the starting - // element change? If so we have to draw it. - if (oldStart != m_selectionStart || - (oldStart == oldEnd && (oldStartPos != m_selectionStartPos || oldEndPos != m_selectionEndPos)) || - (oldStart == m_selectionStart && oldStartPos != m_selectionStartPos)){ - m_view->updateContents( enclosingPositionedRect(m_selectionStart) ); - } - - // Draw the old selection start object if it's different than the new selection - // start object. - if (oldStart && oldStart != m_selectionStart){ - m_view->updateContents( enclosingPositionedRect(oldStart) ); - } - - // Does the selection span objects and is the new end object different, or did the position - // in the end element change? If so we have to draw it. - if (/*(oldStart != oldEnd || !oldEnd) &&*/ - (oldEnd != m_selectionEnd || - (oldEnd == m_selectionEnd && oldEndPos != m_selectionEndPos))){ - m_view->updateContents( enclosingPositionedRect(m_selectionEnd) ); - } - - // Draw the old selection end object if it's different than the new selection - // end object. - if (oldEnd && oldEnd != m_selectionEnd){ - m_view->updateContents( enclosingPositionedRect(oldEnd) ); - } -} - -void RenderCanvas::clearSelection(bool doRepaint) -{ - // update selection status of all objects between m_selectionStart and m_selectionEnd - RenderObject* o = m_selectionStart; - while (o && o!=m_selectionEnd) - { - if (o->selectionState()!=SelectionNone) - if (doRepaint) - o->repaint(); - o->setSelectionState(SelectionNone); - o->repaint(); - RenderObject* no; - if ( !(no = o->firstChild()) ) - if ( !(no = o->nextSibling()) ) - { - no = o->parent(); - while (no && !no->nextSibling()) - no = no->parent(); - if (no) - no = no->nextSibling(); - } - o=no; - } - if (m_selectionEnd) { - m_selectionEnd->setSelectionState(SelectionNone); - if (doRepaint) - m_selectionEnd->repaint(); - } - - // set selection start & end to 0 - if (m_selectionStart) - m_selectionStart->setIsSelectionBorder(false); - m_selectionStart = 0; - m_selectionStartPos = -1; - - if (m_selectionEnd) - m_selectionEnd->setIsSelectionBorder(false); - m_selectionEnd = 0; - m_selectionEndPos = -1; -} - -void RenderCanvas::selectionStartEnd(int& spos, int& epos) -{ - spos = m_selectionStartPos; - epos = m_selectionEndPos; -} - -TQRect RenderCanvas::viewRect() const -{ - if (m_pagedMode) - if (m_pageTop == m_pageBottom) { - kdDebug(6040) << "viewRect: " << TQRect(0, m_pageTop, m_width, m_height) << endl; - return TQRect(0, m_pageTop, m_width, m_height); - } - else { - kdDebug(6040) << "viewRect: " << TQRect(0, m_pageTop, m_width, m_pageBottom - m_pageTop) << endl; - return TQRect(0, m_pageTop, m_width, m_pageBottom - m_pageTop); - } - else if (m_view) - return TQRect(m_view->contentsX(), - m_view->contentsY(), - m_view->visibleWidth(), - m_view->visibleHeight()); - else - return TQRect(0,0,m_rootWidth,m_rootHeight); -} - -int RenderCanvas::docHeight() const -{ - if (m_cachedDocHeight != -1) - return m_cachedDocHeight; - - int h; - if (m_pagedMode || !m_view) - h = m_height; - else - h = 0; - - RenderObject *fc = firstChild(); - if(fc) { - int dh = fc->overflowHeight() + fc->marginTop() + fc->marginBottom(); - int lowestPos = fc->lowestPosition(false); -// kdDebug(6040) << "h " << h << " lowestPos " << lowestPos << " dh " << dh << " fc->rh " << fc->effectiveHeight() << " fc->height() " << fc->height() << endl; - if( lowestPos > dh ) - dh = lowestPos; - lowestPos = lowestAbsolutePosition(); - if( lowestPos > dh ) - dh = lowestPos; - if( dh > h ) - h = dh; - } - - RenderLayer *layer = m_layer; - h = kMax( h, layer->yPos() + layer->height() ); -// kdDebug(6040) << "h " << h << " layer(" << layer->renderer()->renderName() << "@" << layer->renderer() << ")->height " << layer->height() << " lp " << (layer->yPos() + layer->height()) << " height() " << layer->renderer()->height() << " rh " << layer->renderer()->effectiveHeight() << endl; - return h; -} - -int RenderCanvas::docWidth() const -{ - if (m_cachedDocWidth != -1) - return m_cachedDocWidth; - - int w; - if (m_pagedMode || !m_view) - w = m_width; - else - w = 0; - - RenderObject *fc = firstChild(); - if(fc) { - // ow: like effectiveWidth() but without the negative - const int ow = fc->hasOverflowClip() ? fc->width() : fc->overflowWidth(); - int dw = ow + fc->marginLeft() + fc->marginRight(); - int rightmostPos = fc->rightmostPosition(false); -// kdDebug(6040) << "w " << w << " rightmostPos " << rightmostPos << " dw " << dw << " fc->rw " << fc->effectiveWidth() << " fc->width() " << fc->width() << endl; - if( rightmostPos > dw ) - dw = rightmostPos; - rightmostPos = rightmostAbsolutePosition(); - if ( rightmostPos > dw ) - dw = rightmostPos; - if( dw > w ) - w = dw; - } - - RenderLayer *layer = m_layer; - w = kMax( w, layer->xPos() + layer->width() ); -// kdDebug(6040) << "w " << w << " layer(" << layer->renderer()->renderName() << ")->width " << layer->width() << " rm " << (layer->xPos() + layer->width()) << " width() " << layer->renderer()->width() << " rw " << layer->renderer()->effectiveWidth() << endl; - return w; -} - -RenderPage* RenderCanvas::page() { - if (!m_page) m_page = new RenderPage(this); - return m_page; -} diff --git a/khtml/rendering/render_canvas.h b/khtml/rendering/render_canvas.h deleted file mode 100644 index 17f279d7b..000000000 --- a/khtml/rendering/render_canvas.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * This file is part of the HTML widget for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ -#ifndef render_canvas_h -#define render_canvas_h - -#include "render_block.h" - -class KHTMLView; -class TQScrollView; - -namespace khtml { - -class RenderPage; -class RenderStyle; - -enum CanvasMode { - CanvasViewPort, // Paints inside a viewport - CanvasPage, // Paints one page - CanvasDocument // Paints the whole document -}; - -class RenderCanvas : public RenderBlock -{ -public: - RenderCanvas(DOM::NodeImpl* node, KHTMLView *view); - ~RenderCanvas(); - - virtual const char *renderName() const { return "RenderCanvas"; } - - virtual bool isCanvas() const { return true; } - - virtual void setStyle(RenderStyle *style); - virtual void layout(); - virtual void calcWidth(); - virtual void calcHeight(); - virtual void calcMinMaxWidth(); - virtual bool absolutePosition(int &xPos, int&yPos, bool f = false) const; - - int docHeight() const; - int docWidth() const; - - KHTMLView *view() const { return m_view; } - - virtual void repaint(Priority p=NormalPriority); - virtual void repaintRectangle(int x, int y, int w, int h, Priority p=NormalPriority, bool f=false); - void repaintViewRectangle(int x, int y, int w, int h, bool asap=false); - bool needsFullRepaint() const; - void deferredRepaint( RenderObject* o ); - void scheduleDeferredRepaints(); - - virtual void paint(PaintInfo&, int tx, int ty); - virtual void paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty); - virtual void setSelection(RenderObject *s, int sp, RenderObject *e, int ep); - virtual void clearSelection(bool doRepaint=true); - virtual RenderObject *selectionStart() const { return m_selectionStart; } - virtual RenderObject *selectionEnd() const { return m_selectionEnd; } - - void setPrintImages(bool enable) { m_printImages = enable; } - bool printImages() const { return m_printImages; } - - void setCanvasMode(CanvasMode mode) { m_canvasMode = mode; } - CanvasMode canvasMode() const { return m_canvasMode; } - - void setPagedMode(bool b) { m_pagedMode = b; } - void setStaticMode(bool b) { m_staticMode = b; } - - bool pagedMode() const { return m_pagedMode; } - bool staticMode() const { return m_staticMode; } - - void setPageTop(int top) { - m_pageTop = top; -// m_y = top; - } - void setPageBottom(int bottom) { m_pageBottom = bottom; } - int pageTop() const { return m_pageTop; } - int pageBottom() const { return m_pageBottom; } - - int pageTopAfter(int y) const { - if (pageHeight() == 0) return 0; - return (y / pageHeight() + 1) * pageHeight() ; - } - - int crossesPageBreak(int top, int bottom) const { - if (pageHeight() == 0) return false; - int pT = top / pageHeight(); - // bottom is actually the first line not in the box - int pB = (bottom-1) / pageHeight(); - return (pT == pB) ? 0 : (pB + 1); - } - - void setPageNumber(int number) { m_pageNr = number; } - int pageNumber() const { return m_pageNr; } - -public: - virtual void setWidth( int width ) { m_rootWidth = m_width = width; } - virtual void setHeight( int height ) { m_rootHeight = m_height = height; } - -// void setPageHeight( int height ) { m_viewportHeight = m_pageHeight = height; } - int pageHeight() const { return m_pageBottom - m_pageTop; } - - int viewportWidth() const { return m_viewportWidth; } - int viewportHeight() const { return m_viewportHeight; } - - RenderPage* page(); - - TQRect selectionRect() const; - - void setMaximalOutlineSize(int o) { m_maximalOutlineSize = o; } - int maximalOutlineSize() const { return m_maximalOutlineSize; } - - void setNeedsWidgetMasks( bool b=true) { m_needsWidgetMasks = b; } - bool needsWidgetMasks() const { return m_needsWidgetMasks; } - - void updateDocSizeAfterLayerTranslation( RenderObject* o, bool posXOffset, bool posYOffset ); -protected: - // makes sure document, scrollbars and viewport size are accurate - void updateDocumentSize(); - - // internal setters for cached values of document width/height - // Setting to -1/-1 invalidates the cache. - void setCachedDocWidth(int w ) { m_cachedDocWidth = w; } - void setCachedDocHeight(int h) { m_cachedDocHeight = h; } - - virtual void selectionStartEnd(int& spos, int& epos); - - virtual TQRect viewRect() const; - - KHTMLView *m_view; - - RenderObject* m_selectionStart; - RenderObject* m_selectionEnd; - int m_selectionStartPos; - int m_selectionEndPos; - - CanvasMode m_canvasMode; - - int m_rootWidth; - int m_rootHeight; - - int m_viewportWidth; - int m_viewportHeight; - - int m_cachedDocWidth; - int m_cachedDocHeight; - - bool m_printImages; - bool m_needsFullRepaint; - - // Canvas is not interactive - bool m_staticMode; - // Canvas is paged - bool m_pagedMode; - // Canvas contains overlaid widgets - bool m_needsWidgetMasks; - - short m_pageNr; - - int m_pageTop; - int m_pageBottom; - - RenderPage* m_page; - - int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables. - TQValueList<RenderObject*> m_dirtyChildren; -}; - -inline RenderCanvas* RenderObject::canvas() const -{ - return static_cast<RenderCanvas*>(document()->renderer()); -} - -// Represents the page-context of CSS -class RenderPage -{ -public: - RenderPage(RenderCanvas* canvas) : m_canvas(canvas), - m_marginTop(0), m_marginBottom(0), - m_marginLeft(0), m_marginRight(0), - m_pageWidth(0), m_pageHeight(0), - m_fixedSize(false) - { - m_style = new RenderPageStyle(); - } - virtual ~RenderPage() - { - delete m_style; - } - - int marginTop() const { return m_marginTop; } - int marginBottom() const { return m_marginBottom; } - int marginLeft() const { return m_marginLeft; } - int marginRight() const { return m_marginRight; } - - void setMarginTop(int margin) { m_marginTop = margin; } - void setMarginBottom(int margin) { m_marginBottom = margin; } - void setMarginLeft(int margin) { m_marginLeft = margin; } - void setMarginRight(int margin) { m_marginRight = margin; } - - int pageWidth() const { return m_pageWidth; } - int pageHeight() const { return m_pageHeight; } - - void setPageSize(int width, int height) { - m_pageWidth = width; - m_pageHeight = height; - } - - // Returns true if size was set by document, false if set by user-agent - bool fixedSize() const { return m_fixedSize; } - void setFixedSize(bool b) { m_fixedSize = b; } - - RenderPageStyle* style() { return m_style; } - const RenderPageStyle* style() const { return m_style; } - -protected: - RenderCanvas* m_canvas; - RenderPageStyle* m_style; - - int m_marginTop; - int m_marginBottom; - int m_marginLeft; - int m_marginRight; - - int m_pageWidth; - int m_pageHeight; - - bool m_fixedSize; -}; - -} -#endif diff --git a/khtml/rendering/render_container.cpp b/khtml/rendering/render_container.cpp deleted file mode 100644 index 69f987477..000000000 --- a/khtml/rendering/render_container.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2001-2003 Lars Knoll (knoll@kde.org) - * (C) 2001 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2002-2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -//#define DEBUG_LAYOUT - -#include "rendering/render_container.h" -#include "rendering/render_table.h" -#include "rendering/render_text.h" -#include "rendering/render_image.h" -#include "rendering/render_canvas.h" -#include "rendering/render_generated.h" -#include "rendering/render_inline.h" -#include "xml/dom_docimpl.h" -#include "css/css_valueimpl.h" - -#include <kdebug.h> -#include <assert.h> - -using namespace khtml; - -RenderContainer::RenderContainer(DOM::NodeImpl* node) - : RenderObject(node) -{ - m_first = 0; - m_last = 0; -} - -void RenderContainer::detach() -{ - if (continuation()) - continuation()->detach(); - - // We simulate removeNode calls for all our children - // and set parent to 0 to avoid removeNode from being called. - // First call removeLayers and removeFromObjectLists since they assume - // a valid render-tree - for(RenderObject* n = m_first; n; n = n->nextSibling() ) { - n->removeLayers(enclosingLayer()); - n->removeFromObjectLists(); - } - - RenderObject* next; - for(RenderObject* n = m_first; n; n = next ) { - n->setParent(0); - next = n->nextSibling(); - n->detach(); - } - m_first = 0; - m_last = 0; - - RenderObject::detach(); -} - -void RenderContainer::addChild(RenderObject *newChild, RenderObject *beforeChild) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << this << ": " << renderName() << "(RenderObject)::addChild( " << newChild << ": " << - newChild->renderName() << ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; -#endif - // protect ourselves from deletion - setDoNotDelete(true); - - bool needsTable = false; - - if(!newChild->isText() && !newChild->isReplaced()) { - switch(newChild->style()->display()) { - case INLINE: - case BLOCK: - case LIST_ITEM: - case RUN_IN: - case COMPACT: - case INLINE_BLOCK: - case TABLE: - case INLINE_TABLE: - break; - case TABLE_COLUMN: - if ( isTableCol() ) - break; - // nobreak - case TABLE_COLUMN_GROUP: - case TABLE_CAPTION: - case TABLE_ROW_GROUP: - case TABLE_HEADER_GROUP: - case TABLE_FOOTER_GROUP: - - //kdDebug( 6040 ) << "adding section" << endl; - if ( !isTable() ) - needsTable = true; - break; - case TABLE_ROW: - //kdDebug( 6040 ) << "adding row" << endl; - if ( !isTableSection() ) - needsTable = true; - break; - case TABLE_CELL: - //kdDebug( 6040 ) << "adding cell" << endl; - if ( !isTableRow() ) - needsTable = true; - // I'm not 100% sure this is the best way to fix this, but without this - // change we recurse infinitely when trying to render the CSS2 test page: - // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html. - if ( isTableCell() && !firstChild() && !newChild->isTableCell() ) - needsTable = false; - - break; - case NONE: - // RenderHtml and some others can have display:none - // KHTMLAssert(false); - break; - } - } - - if ( needsTable ) { - RenderTable *table; - RenderObject *last = beforeChild ? beforeChild->previousSibling() : lastChild(); - if ( last && last->isTable() && last->isAnonymous() ) { - table = static_cast<RenderTable *>(last); - } else { - //kdDebug( 6040 ) << "creating anonymous table, before=" << beforeChild << endl; - table = new (renderArena()) RenderTable(document() /* is anonymous */); - RenderStyle *newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay( TABLE ); - newStyle->setFlowAroundFloats( true ); - table->setParent( this ); // so it finds the arena - table->setStyle(newStyle); - table->setParent( 0 ); - addChild(table, beforeChild); - } - table->addChild(newChild); - } else { - // just add it... - insertChildNode(newChild, beforeChild); - } - - if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { - DOM::DOMStringImpl* textToTransform = static_cast<RenderText*>(newChild)->originalString(); - if (textToTransform) - static_cast<RenderText*>(newChild)->setText(textToTransform, true); - } - newChild->attach(); - - setDoNotDelete(false); -} - -RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild) -{ - KHTMLAssert(oldChild->parent() == this); - - // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or - // that a positioned child got yanked). We also repaint, so that the area exposed when the child - // disappears gets repainted properly. - if ( document()->renderer() ) { - oldChild->setNeedsLayoutAndMinMaxRecalc(); - oldChild->repaint(); - - // Keep our layer hierarchy updated. - oldChild->removeLayers(enclosingLayer()); - // remove the child from any special layout lists - oldChild->removeFromObjectLists(); - - // if oldChild is the start or end of the selection, then clear - // the selection to avoid problems of invalid pointers - - // ### This is not the "proper" solution... ideally the selection - // ### should be maintained based on DOM Nodes and a Range, which - // ### gets adjusted appropriately when nodes are deleted/inserted - // ### near etc. But this at least prevents crashes caused when - // ### the start or end of the selection is deleted and then - // ### accessed when the user next selects something. - - if (oldChild->isSelectionBorder()) { - RenderObject *root = oldChild; - while (root->parent()) - root = root->parent(); - if (root->isCanvas()) { - static_cast<RenderCanvas*>(root)->clearSelection(); - } - } - } - - // remove the child from the render-tree - if (oldChild->previousSibling()) - oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); - if (oldChild->nextSibling()) - oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); - - if (m_first == oldChild) - m_first = oldChild->nextSibling(); - if (m_last == oldChild) - m_last = oldChild->previousSibling(); - - oldChild->setPreviousSibling(0); - oldChild->setNextSibling(0); - oldChild->setParent(0); - - return oldChild; -} - -void RenderContainer::setStyle(RenderStyle* _style) -{ - RenderObject::setStyle(_style); - - // If we are a pseudo-container we need to restyle the children - if (style()->isGenerated()) - { - // ### we could save this call when the change only affected - // non inherited properties - RenderStyle *pseudoStyle = new RenderStyle(); - pseudoStyle->inheritFrom(style()); - pseudoStyle->ref(); - RenderObject *child = firstChild(); - while (child != 0) - { - child->setStyle(pseudoStyle); - child = child->nextSibling(); - } - pseudoStyle->deref(); - } -} - -void RenderContainer::updatePseudoChildren() -{ - // In CSS2, before/after pseudo-content cannot nest. Check this first. - // Remove when CSS 3 Generated Content becomes Candidate Recommendation - if (style()->styleType() == RenderStyle::BEFORE - || style()->styleType() == RenderStyle::AFTER) - return; - - updatePseudoChild(RenderStyle::BEFORE); - updatePseudoChild(RenderStyle::AFTER); - // updatePseudoChild(RenderStyle::MARKER, marker()); -} - -void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type) -{ - // The head manages generated content for its continuations - if (isInlineContinuation()) return; - - RenderStyle* pseudo = style()->getPseudoStyle(type); - - RenderObject* child = pseudoContainer(type); - - // Whether or not we currently have generated content attached. - bool oldContentPresent = child && (child->style()->styleType() == type); - - // Whether or not we now want generated content. - bool newContentWanted = pseudo && pseudo->display() != NONE; - - // No generated content - if (!oldContentPresent && !newContentWanted) - return; - - bool movedContent = (type == RenderStyle::AFTER && isRenderInline() && continuation()); - - // Whether or not we want the same old content. - bool sameOldContent = oldContentPresent && newContentWanted && !movedContent - && (child->style()->contentDataEquivalent(pseudo)); - - // No change in content, update style - if( sameOldContent ) { - child->setStyle(pseudo); - return; - } - - // If we don't want generated content any longer, or if we have generated content, - // but it's no longer identical to the new content data we want to build - // render objects for, then we nuke all of the old generated content. - if (oldContentPresent && (!newContentWanted || !sameOldContent)) - { - // The child needs to be removed. - oldContentPresent = false; - child->detach(); - child = 0; - } - - // If we have no pseudo-style or if the pseudo's display type is NONE, then we - // have no generated content and can now return. - if (!newContentWanted) - return; - - // Generated content consists of a single container that houses multiple children (specified - // by the content property). This pseudo container gets the pseudo style set on it. - RenderContainer* pseudoContainer = 0; - pseudoContainer = RenderFlow::createFlow(element(), pseudo, renderArena()); - pseudoContainer->setIsAnonymous( true ); - pseudoContainer->createGeneratedContent(); - - // Only add the container if it had content - if (pseudoContainer->firstChild()) { - addPseudoContainer(pseudoContainer); - pseudoContainer->close(); - } -} - -void RenderContainer::createGeneratedContent() -{ - RenderStyle* pseudo = style(); - RenderStyle* style = new RenderStyle(); - style->ref(); - style->inheritFrom(pseudo); - - // Now walk our list of generated content and create render objects for every type - // we encounter. - for (ContentData* contentData = pseudo->contentData(); - contentData; contentData = contentData->_nextContent) - { - if (contentData->_contentType == CONTENT_TEXT) - { - RenderText* t = new (renderArena()) RenderText( node(), 0); - t->setIsAnonymous( true ); - t->setStyle(style); - t->setText(contentData->contentText()); - addChild(t); - } - else if (contentData->_contentType == CONTENT_OBJECT) - { - RenderImage* img = new (renderArena()) RenderImage(node()); - img->setIsAnonymous( true ); - img->setStyle(style); - img->setContentObject(contentData->contentObject()); - addChild(img); - } - else if (contentData->_contentType == CONTENT_COUNTER) - { - // really a counter or just a glyph? - EListStyleType type = (EListStyleType)contentData->contentCounter()->listStyle(); - RenderObject *t = 0; - if (isListStyleCounted(type)) { - t = new (renderArena()) RenderCounter( node(), contentData->contentCounter() ); - } - else { - t = new (renderArena()) RenderGlyph( node(), type ); - } - t->setIsAnonymous( true ); - t->setStyle(style); - addChild(t); - } - else if (contentData->_contentType == CONTENT_QUOTE) - { - RenderQuote* t = new (renderArena()) RenderQuote( node(), contentData->contentQuote() ); - t->setIsAnonymous( true ); - t->setStyle(style); - addChild(t); - } - } - style->deref(); -} - -RenderContainer* RenderContainer::pseudoContainer(RenderStyle::PseudoId type) const -{ - RenderObject *child = 0; - switch (type) { - case RenderStyle::AFTER: - child = lastChild(); - break; - case RenderStyle::BEFORE: - child = firstChild(); - break; - case RenderStyle::REPLACED: - child = lastChild(); - if (child && child->style()->styleType() == RenderStyle::AFTER) - child = child->previousSibling(); - break; - default: - child = 0; - } - - if (child && child->style()->styleType() == type) { - assert(child->isRenderBlock() || child->isRenderInline()); - return static_cast<RenderContainer*>(child); - } - if (type == RenderStyle::AFTER) { - // check continuations - if (continuation()) - return continuation()->pseudoContainer(type); - } - if (child && child->isAnonymousBlock()) - return static_cast<RenderBlock*>(child)->pseudoContainer(type); - return 0; -} - -void RenderContainer::addPseudoContainer(RenderObject* child) -{ - RenderStyle::PseudoId type = child->style()->styleType(); - switch (type) { - case RenderStyle::AFTER: { - RenderObject *o = this; - while (o->continuation()) o = o->continuation(); - - // Coalesce inlines - if (child->style()->display() == INLINE && o->lastChild() && o->lastChild()->isAnonymousBlock()) { - o->lastChild()->addChild(child, 0); - } else - o->addChild(child, 0); - break; - } - case RenderStyle::BEFORE: - // Coalesce inlines - if (child->style()->display() == INLINE && firstChild() && firstChild()->isAnonymousBlock()) { - firstChild()->addChild(child, firstChild()->firstChild()); - } else - addChild(child, firstChild()); - break; - case RenderStyle::REPLACED: - addChild(child, pseudoContainer(RenderStyle::AFTER)); - break; - default: - break; - } -} - -void RenderContainer::updateReplacedContent() -{ - // Only for normal elements - if (!style() || style()->styleType() != RenderStyle::NOPSEUDO) - return; - - // delete old generated content - RenderContainer *container = pseudoContainer(RenderStyle::REPLACED); - if (container) { - container->detach(); - } - - if (style()->useNormalContent()) return; - - // create generated content - RenderStyle* pseudo = style()->getPseudoStyle(RenderStyle::REPLACED); - if (!pseudo) { - pseudo = new RenderStyle(); - pseudo->inheritFrom(style()); - pseudo->setStyleType(RenderStyle::REPLACED); - } - if (pseudo->useNormalContent()) - pseudo->setContentData(style()->contentData()); - - container = RenderFlow::createFlow(node(), pseudo, renderArena()); - container->setIsAnonymous( true ); - container->createGeneratedContent(); - - addChild(container, pseudoContainer(RenderStyle::AFTER)); -} - -void RenderContainer::appendChildNode(RenderObject* newChild) -{ - KHTMLAssert(newChild->parent() == 0); - - newChild->setParent(this); - RenderObject* lChild = lastChild(); - - if(lChild) - { - newChild->setPreviousSibling(lChild); - lChild->setNextSibling(newChild); - } - else - setFirstChild(newChild); - - setLastChild(newChild); - - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children - // and don't have a layer attached to ourselves. - if (newChild->firstChild() || newChild->layer()) { - RenderLayer* layer = enclosingLayer(); - newChild->addLayers(layer, newChild); - } - - newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy. - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. -} - -void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild) -{ - if(!beforeChild) { - appendChildNode(child); - return; - } - - KHTMLAssert(!child->parent()); - while ( beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock() ) - beforeChild = beforeChild->parent(); - KHTMLAssert(beforeChild->parent() == this); - - if(beforeChild == firstChild()) - setFirstChild(child); - - RenderObject* prev = beforeChild->previousSibling(); - child->setNextSibling(beforeChild); - beforeChild->setPreviousSibling(child); - if(prev) prev->setNextSibling(child); - child->setPreviousSibling(prev); - child->setParent(this); - - // Keep our layer hierarchy updated. - RenderLayer* layer = enclosingLayer(); - child->addLayers(layer, child); - - child->setNeedsLayoutAndMinMaxRecalc(); - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. -} - - -void RenderContainer::layout() -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - const bool pagedMode = canvas()->pagedMode(); - RenderObject *child = firstChild(); - while( child ) { - if (pagedMode) child->setNeedsLayout(true); - child->layoutIfNeeded(); - if (child->containsPageBreak()) setContainsPageBreak(true); - if (child->needsPageClear()) setNeedsPageClear(true); - child = child->nextSibling(); - } - setNeedsLayout(false); -} - -void RenderContainer::removeLeftoverAnonymousBoxes() -{ - // we have to go over all child nodes and remove anonymous boxes, that do _not_ - // have inline children to keep the tree flat - RenderObject *child = firstChild(); - while( child ) { - RenderObject *next = child->nextSibling(); - - if ( child->isRenderBlock() && child->isAnonymousBlock() && !child->continuation() && - !child->childrenInline() && !child->isTableCell() && !child->doNotDelete()) { - RenderObject *firstAnChild = child->firstChild(); - RenderObject *lastAnChild = child->lastChild(); - if ( firstAnChild ) { - RenderObject *o = firstAnChild; - while( o ) { - o->setParent( this ); - o = o->nextSibling(); - } - firstAnChild->setPreviousSibling( child->previousSibling() ); - lastAnChild->setNextSibling( child->nextSibling() ); - if ( child->previousSibling() ) - child->previousSibling()->setNextSibling( firstAnChild ); - if ( child->nextSibling() ) - child->nextSibling()->setPreviousSibling( lastAnChild ); - if ( child == firstChild() ) - m_first = firstAnChild; - if ( child == lastChild() ) - m_last = lastAnChild; - } else { - if ( child->previousSibling() ) - child->previousSibling()->setNextSibling( child->nextSibling() ); - if ( child->nextSibling() ) - child->nextSibling()->setPreviousSibling( child->previousSibling() ); - if ( child == firstChild() ) - m_first = child->nextSibling(); - if ( child == lastChild() ) - m_last = child->previousSibling(); - } - child->setParent( 0 ); - child->setPreviousSibling( 0 ); - child->setNextSibling( 0 ); - if ( !child->isText() ) { - RenderContainer *c = static_cast<RenderContainer *>(child); - c->m_first = 0; - c->m_next = 0; - } - child->detach(); - } - child = next; - } - if ( parent() ) - parent()->removeLeftoverAnonymousBoxes(); -} - -#undef DEBUG_LAYOUT diff --git a/khtml/rendering/render_container.h b/khtml/rendering/render_container.h deleted file mode 100644 index 4cf386140..000000000 --- a/khtml/rendering/render_container.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2001 Antti Koivisto (koivisto@kde.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. - * - */ -#ifndef render_container_h -#define render_container_h - -#include "render_object.h" - -namespace khtml -{ - - -/** - * Base class for rendering objects that can have children - */ -class RenderContainer : public RenderObject -{ -public: - RenderContainer(DOM::NodeImpl* node); - - void detach(); - - RenderObject *firstChild() const { return m_first; } - RenderObject *lastChild() const { return m_last; } - - virtual bool childAllowed() const { - // Prevent normal children when we are replaced by generated content - if (style()) return style()->useNormalContent(); - return true; - } - - virtual void addChild(RenderObject *newChild, RenderObject *beforeChild = 0); - - virtual RenderObject* removeChildNode(RenderObject* child); - virtual void appendChildNode(RenderObject* child); - virtual void insertChildNode(RenderObject* child, RenderObject* before); - - virtual void layout(); - virtual void calcMinMaxWidth() { setMinMaxKnown( true ); } - - virtual void removeLeftoverAnonymousBoxes(); - - virtual void setStyle(RenderStyle* _style); - -protected: - // Generate CSS content - void createGeneratedContent(); - void updateReplacedContent(); - - void updatePseudoChildren(); - void updatePseudoChild(RenderStyle::PseudoId type); - - RenderContainer* pseudoContainer( RenderStyle::PseudoId type ) const; - void addPseudoContainer(RenderObject* child); -private: - - void setFirstChild(RenderObject *first) { m_first = first; } - void setLastChild(RenderObject *last) { m_last = last; } - -protected: - - RenderObject *m_first; - RenderObject *m_last; -}; - -} -#endif diff --git a/khtml/rendering/render_flow.cpp b/khtml/rendering/render_flow.cpp deleted file mode 100644 index ae579bd46..000000000 --- a/khtml/rendering/render_flow.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003-2006 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -// ------------------------------------------------------------------------- - -#include <kdebug.h> -#include <assert.h> -#include <tqpainter.h> -#include <kglobal.h> - -#include "rendering/render_flow.h" -#include "rendering/render_text.h" -#include "rendering/render_table.h" -#include "rendering/render_canvas.h" -#include "rendering/render_inline.h" -#include "rendering/render_block.h" -#include "rendering/render_arena.h" -#include "rendering/render_line.h" -#include "xml/dom_nodeimpl.h" -#include "xml/dom_docimpl.h" -#include "misc/htmltags.h" -#include "html/html_formimpl.h" - -#include "khtmlview.h" - -using namespace DOM; -using namespace khtml; - -RenderFlow* RenderFlow::createFlow(DOM::NodeImpl* node, RenderStyle* style, RenderArena* arena) -{ - RenderFlow* result; - if (style->display() == INLINE) - result = new (arena) RenderInline(node); - else - result = new (arena) RenderBlock(node); - result->setStyle(style); - return result; -} - -RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild) -{ - if (beforeChild && beforeChild->parent() == this) - return this; - - RenderFlow* curr = continuation(); - RenderFlow* nextToLast = this; - RenderFlow* last = this; - while (curr) { - if (beforeChild && beforeChild->parent() == curr) { - if (curr->firstChild() == beforeChild) - return last; - return curr; - } - - nextToLast = last; - last = curr; - curr = curr->continuation(); - } - - if (!beforeChild && !last->firstChild()) - return nextToLast; - return last; -} - -void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild) -{ - RenderFlow* flow = continuationBefore(beforeChild); - while(beforeChild && beforeChild->parent() != flow && !beforeChild->parent()->isAnonymousBlock()) { - // skip implicit containers around beforeChild - beforeChild = beforeChild->parent(); - } - RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) : - (flow->continuation() ? flow->continuation() : flow); - - if (newChild->isFloatingOrPositioned()) - return beforeChildParent->addChildToFlow(newChild, beforeChild); - - // A continuation always consists of two potential candidates: an inline or an anonymous - // block box holding block children. - bool childInline = newChild->isInline(); - bool bcpInline = beforeChildParent->isInline(); - bool flowInline = flow->isInline(); - - if (flow == beforeChildParent) - return flow->addChildToFlow(newChild, beforeChild); - else { - // The goal here is to match up if we can, so that we can coalesce and create the - // minimal # of continuations needed for the inline. - if (childInline == bcpInline) - return beforeChildParent->addChildToFlow(newChild, beforeChild); - else if (flowInline == childInline) - return flow->addChildToFlow(newChild, 0); // Just treat like an append. - else - return beforeChildParent->addChildToFlow(newChild, beforeChild); - } -} - -void RenderFlow::addChild(RenderObject *newChild, RenderObject *beforeChild) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(RenderFlow)::addChild( " << newChild->renderName() << - ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; - kdDebug( 6040 ) << "current height = " << m_height << endl; -#endif - - if (continuation()) - return addChildWithContinuation(newChild, beforeChild); - return addChildToFlow(newChild, beforeChild); -} - -void RenderFlow::deleteInlineBoxes(RenderArena* arena) -{ - RenderBox::deleteInlineBoxes(arena); //In case we upcalled - //during construction - if (m_firstLineBox) { - if (!arena) - arena = renderArena(); - InlineRunBox *curr=m_firstLineBox, *next=0; - while (curr) { - next = curr->nextLineBox(); - curr->detach(arena); - curr = next; - } - m_firstLineBox = 0; - m_lastLineBox = 0; - } -} - -void RenderFlow::deleteLastLineBox(RenderArena* arena) -{ - if (m_lastLineBox) { - if (!arena) - arena = renderArena(); - InlineRunBox *curr=m_lastLineBox, *prev = m_lastLineBox; - if (m_firstLineBox == m_lastLineBox) - m_firstLineBox = m_lastLineBox = 0; - else { - prev = curr->prevLineBox(); - while (!prev->isInlineFlowBox()) { - prev = prev->prevLineBox(); - prev->detach(arena); - } - m_lastLineBox = static_cast<InlineFlowBox*>(prev); - prev->setNextLineBox(0); - } - if (curr->parent()) { - curr->parent()->removeFromLine(curr); - } - curr->detach(arena); - } -} - -InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox) -{ - if ( !isRootLineBox && - (isReplaced() || makePlaceHolderBox) ) // Inline tables and inline blocks - return RenderBox::createInlineBox(false, false); // (or positioned element placeholders). - - InlineFlowBox* flowBox = 0; - if (isInlineFlow()) - flowBox = new (renderArena()) InlineFlowBox(this); - else - flowBox = new (renderArena()) RootInlineBox(this); - - if (!m_firstLineBox) { - m_firstLineBox = m_lastLineBox = flowBox; - } else { - m_lastLineBox->setNextLineBox(flowBox); - flowBox->setPreviousLineBox(m_lastLineBox); - m_lastLineBox = flowBox; - } - - return flowBox; -} - -void RenderFlow::paintLines(PaintInfo& i, int _tx, int _ty) -{ - // Only paint during the foreground/selection phases. - if (i.phase != PaintActionForeground && i.phase != PaintActionSelection && i.phase != PaintActionOutline) - return; - - if (!firstLineBox()) - return; - - // We can check the first box and last box and avoid painting if we don't - // intersect. This is a quick short-circuit that we can take to avoid walking any lines. - // FIXME: This check is flawed in two extremely obscure ways. - // (1) If some line in the middle has a huge overflow, it might actually extend below the last line. - // (2) The overflow from an inline block on a line is not reported to the line. - int maxOutlineSize = maximalOutlineSize(i.phase); - int yPos = firstLineBox()->root()->topOverflow() - maxOutlineSize; - int h = maxOutlineSize + lastLineBox()->root()->bottomOverflow() - yPos; - yPos += _ty; - if ((yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y())) - return; - for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { - yPos = curr->root()->topOverflow() - maxOutlineSize; - h = curr->root()->bottomOverflow() + maxOutlineSize - yPos; - yPos += _ty; - if ((yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y())) - curr->paint(i, _tx, _ty); - } - - if (i.phase == PaintActionOutline && i.outlineObjects) { - TQValueList<RenderFlow *>::iterator it;; - for( it = (*i.outlineObjects).begin(); it != (*i.outlineObjects).end(); ++it ) - if ((*it)->isRenderInline()) - static_cast<RenderInline*>(*it)->paintOutlines(i.p, _tx, _ty); - i.outlineObjects->clear(); - } -} - - -bool RenderFlow::hitTestLines(NodeInfo& i, int x, int y, int tx, int ty, HitTestAction hitTestAction) -{ - (void) hitTestAction; - /* - if (hitTestAction != HitTestForeground) // ### port hitTest - return false; - */ - - if (!firstLineBox()) - return false; - - // We can check the first box and last box and avoid hit testing if we don't - // contain the point. This is a quick short-circuit that we can take to avoid walking any lines. - // FIXME: This check is flawed in two extremely obscure ways. - // (1) If some line in the middle has a huge overflow, it might actually extend below the last line. - // (2) The overflow from an inline block on a line is not reported to the line. - if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow())) - return false; - - // See if our root lines contain the point. If so, then we hit test - // them further. Note that boxes can easily overlap, so we can't make any assumptions - // based off positions of our first line box or our last line box. - for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) { - if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) { - bool inside = curr->nodeAtPoint(i, x, y, tx, ty); - if (inside) { - setInnerNode(i); - return true; - } - } - } - - return false; -} - - -void RenderFlow::repaint(Priority prior) -{ - if (isInlineFlow()) { - // Find our leftmost position. - int left = 0; - // root inline box not reliably availabe during relayout - int top = firstLineBox() ? ( - needsLayout() ? firstLineBox()->xPos() : firstLineBox()->root()->topOverflow() - ) : 0; - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - if (curr == firstLineBox() || curr->xPos() < left) - left = curr->xPos(); - - // Now invalidate a rectangle. - int ow = style() ? style()->outlineSize() : 0; - - // We need to add in the relative position offsets of any inlines (including us) up to our - // containing block. - RenderBlock* cb = containingBlock(); - for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; - inlineFlow = inlineFlow->parent()) { - if (inlineFlow->style() && inlineFlow->style()->position() == RELATIVE && inlineFlow->layer()) { - KHTMLAssert(inlineFlow->isBox()); - static_cast<RenderBox*>(inlineFlow)->relativePositionOffset(left, top); - } - } - - RootInlineBox *lastRoot = lastLineBox() && !needsLayout() ? lastLineBox()->root() : 0; - containingBlock()->repaintRectangle(-ow+left, -ow+top, - width()+ow*2, - (lastRoot ? lastRoot->bottomOverflow() - top : height())+ow*2, prior); - } - else { - if (firstLineBox() && firstLineBox()->topOverflow() < 0) { - int ow = style() ? style()->outlineSize() : 0; - repaintRectangle(-ow, -ow+firstLineBox()->topOverflow(), - effectiveWidth()+ow*2, effectiveHeight()+ow*2, prior); - } - else - return RenderBox::repaint(prior); - } -} - -int -RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return bottom; - - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { - int lp = c->yPos() + c->lowestPosition(false); - bottom = kMax(bottom, lp); - } - } - - if (isRelPositioned()) { - int x; - relativePositionOffset(x, bottom); - } - - return bottom; -} - -int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return right; - - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { - int rp = c->xPos() + c->rightmostPosition(false); - right = kMax(right, rp); - } - } - - if (isRelPositioned()) { - int y; - relativePositionOffset(right, y); - } - - return right; -} - -int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return left; - - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { - int lp = c->xPos() + c->leftmostPosition(false); - left = kMin(left, lp); - } - } - - if (isRelPositioned()) { - int y; - relativePositionOffset(left, y); - } - - return left; -} - -int RenderFlow::highestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int top = RenderBox::highestPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return top; - - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { - int hp = c->yPos() + c->highestPosition(false); - top = kMin(top, hp); - } - } - - if (isRelPositioned()) { - int x; - relativePositionOffset(x, top); - } - - return top; -} diff --git a/khtml/rendering/render_flow.h b/khtml/rendering/render_flow.h deleted file mode 100644 index 1e23822bb..000000000 --- a/khtml/rendering/render_flow.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -#ifndef RENDER_FLOW_H -#define RENDER_FLOW_H - -#include "render_box.h" -#include "bidi.h" -#include "render_line.h" - -namespace khtml { - -/** - * all geometry managing stuff is only in the block elements. - * - * Inline elements don't layout themselves, but the whole paragraph - * gets flowed by the surrounding block element. This is, because - * one needs to know the whole paragraph to calculate bidirectional - * behaviour of text, so putting the layouting routines in the inline - * elements is impossible. - */ -class RenderFlow : public RenderBox -{ -public: - RenderFlow(DOM::NodeImpl* node) - : RenderBox(node) - { m_continuation = 0; m_firstLineBox = 0; m_lastLineBox = 0; } - - virtual RenderFlow* continuation() const { return m_continuation; } - void setContinuation(RenderFlow* c) { m_continuation = c; } - RenderFlow* continuationBefore(RenderObject* beforeChild); - - void addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild); - virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) = 0; - virtual void addChild(RenderObject *newChild, RenderObject *beforeChild = 0); - - static RenderFlow* createFlow(DOM::NodeImpl* node, RenderStyle* style, RenderArena* arena); - - virtual void deleteLastLineBox(RenderArena* arena=0); - virtual void deleteInlineBoxes(RenderArena* arena=0); - - - InlineFlowBox* firstLineBox() const { return m_firstLineBox; } - InlineFlowBox* lastLineBox() const { return m_lastLineBox; } - - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox); - - void paintLines(PaintInfo& i, int _tx, int _ty); - bool hitTestLines(NodeInfo& i, int x, int y, int tx, int ty, HitTestAction hitTestAction); - - virtual void repaint(Priority p=NormalPriority); - - virtual int highestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const; - -protected: - // An inline can be split with blocks occurring in between the inline content. - // When this occurs we need a pointer to our next object. We can basically be - // split into a sequence of inlines and blocks. The continuation will either be - // an anonymous block (that houses other blocks) or it will be an inline flow. - RenderFlow* m_continuation; - - // For block flows, each box represents the root inline box for a line in the - // paragraph. - // For inline flows, each box represents a portion of that inline. - InlineFlowBox* m_firstLineBox; - InlineFlowBox* m_lastLineBox; -}; - - -} //namespace - -#endif diff --git a/khtml/rendering/render_form.cpp b/khtml/rendering/render_form.cpp deleted file mode 100644 index 81005de85..000000000 --- a/khtml/rendering/render_form.cpp +++ /dev/null @@ -1,1914 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * (C) 2006 Maksim Orlovich (maksim@kde.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 <kcompletionbox.h> -#include <kcursor.h> -#include <kdebug.h> -#include <kfiledialog.h> -#include <kfind.h> -#include <kfinddialog.h> -#include <kiconloader.h> -#include <klocale.h> -#include <kmessagebox.h> -#include <kreplace.h> -#include <kreplacedialog.h> -#include <kspell.h> -#include <kurlcompletion.h> -#include <twin.h> - -#include <tqstyle.h> - -#include "misc/helper.h" -#include "xml/dom2_eventsimpl.h" -#include "html/html_formimpl.h" -#include "misc/htmlhashes.h" - -#include "rendering/render_form.h" -#include <assert.h> - -#include "khtmlview.h" -#include "khtml_ext.h" -#include "xml/dom_docimpl.h" - -#include <tqpopupmenu.h> -#include <tqbitmap.h> - -using namespace khtml; - -RenderFormElement::RenderFormElement(HTMLGenericFormElementImpl *element) - : RenderWidget(element) -{ - // init RenderObject attributes - setInline(true); // our object is Inline - - m_state = 0; -} - -RenderFormElement::~RenderFormElement() -{ -} - -short RenderFormElement::baselinePosition( bool f ) const -{ - return RenderWidget::baselinePosition( f ) - 2 - style()->fontMetrics().descent(); -} - -void RenderFormElement::updateFromElement() -{ - m_widget->setEnabled(!element()->disabled()); - RenderWidget::updateFromElement(); -} - -void RenderFormElement::layout() -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - // minimum height - m_height = 0; - - calcWidth(); - calcHeight(); - - if ( m_widget ) - resizeWidget(m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), - m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom()); - - setNeedsLayout(false); -} - -TQ_Alignment RenderFormElement::textAlignment() const -{ - switch (style()->textAlign()) { - case LEFT: - case KHTML_LEFT: - return Qt::AlignLeft; - case RIGHT: - case KHTML_RIGHT: - return Qt::AlignRight; - case CENTER: - case KHTML_CENTER: - return Qt::AlignHCenter; - case JUSTIFY: - // Just fall into the auto code for justify. - case TAAUTO: - return style()->direction() == RTL ? Qt::AlignRight : Qt::AlignLeft; - } - assert(false); // Should never be reached. - return Qt::AlignLeft; -} - -// ------------------------------------------------------------------------- - -RenderButton::RenderButton(HTMLGenericFormElementImpl *element) - : RenderFormElement(element) -{ -} - -short RenderButton::baselinePosition( bool f ) const -{ - return RenderWidget::baselinePosition( f ) - 2; -} - -// ------------------------------------------------------------------------------- - - -RenderCheckBox::RenderCheckBox(HTMLInputElementImpl *element) - : RenderButton(element) -{ - TQCheckBox* b = new TQCheckBox(view()->viewport(), "__khtml"); - b->setAutoMask(true); - b->setMouseTracking(true); - setQWidget(b); - - // prevent firing toggled() signals on initialization - b->setChecked(element->checked()); - - connect(b,TQT_SIGNAL(stateChanged(int)),this,TQT_SLOT(slotStateChanged(int))); -} - - -void RenderCheckBox::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - TQCheckBox *cb = static_cast<TQCheckBox *>( m_widget ); - TQSize s( cb->style().pixelMetric( TQStyle::PM_IndicatorWidth ), - cb->style().pixelMetric( TQStyle::PM_IndicatorHeight ) ); - setIntrinsicWidth( s.width() ); - setIntrinsicHeight( s.height() ); - - RenderButton::calcMinMaxWidth(); -} - -void RenderCheckBox::updateFromElement() -{ - widget()->setChecked(element()->checked()); - - RenderButton::updateFromElement(); -} - -void RenderCheckBox::slotStateChanged(int state) -{ - element()->setChecked(state == TQButton::On); - element()->setIndeterminate(state == TQButton::NoChange); - - ref(); - element()->onChange(); - deref(); -} - -// ------------------------------------------------------------------------------- - -RenderRadioButton::RenderRadioButton(HTMLInputElementImpl *element) - : RenderButton(element) -{ - TQRadioButton* b = new TQRadioButton(view()->viewport(), "__khtml"); - b->setMouseTracking(true); - setQWidget(b); - - // prevent firing toggled() signals on initialization - b->setChecked(element->checked()); - - connect(b,TQT_SIGNAL(toggled(bool)),this,TQT_SLOT(slotToggled(bool))); -} - -void RenderRadioButton::updateFromElement() -{ - widget()->setChecked(element()->checked()); - - RenderButton::updateFromElement(); -} - -void RenderRadioButton::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - TQRadioButton *rb = static_cast<TQRadioButton *>( m_widget ); - TQSize s( rb->style().pixelMetric( TQStyle::PM_ExclusiveIndicatorWidth ), - rb->style().pixelMetric( TQStyle::PM_ExclusiveIndicatorHeight ) ); - setIntrinsicWidth( s.width() ); - setIntrinsicHeight( s.height() ); - - RenderButton::calcMinMaxWidth(); -} - -void RenderRadioButton::slotToggled(bool activated) -{ - if(activated) { - ref(); - element()->onChange(); - deref(); - } -} - -// ------------------------------------------------------------------------------- - - -RenderSubmitButton::RenderSubmitButton(HTMLInputElementImpl *element) - : RenderButton(element) -{ - TQPushButton* p = new TQPushButton(view()->viewport(), "__khtml"); - setQWidget(p); - p->setAutoMask(true); - p->setMouseTracking(true); -} - -TQString RenderSubmitButton::rawText() -{ - TQString value = element()->valueWithDefault().string(); - value = value.stripWhiteSpace(); - TQString raw; - for(unsigned int i = 0; i < value.length(); i++) { - raw += value[i]; - if(value[i] == '&') - raw += '&'; - } - return raw; -} - -void RenderSubmitButton::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - TQString raw = rawText(); - TQPushButton* pb = static_cast<TQPushButton*>(m_widget); - pb->setText(raw); - pb->setFont(style()->font()); - - bool empty = raw.isEmpty(); - if ( empty ) - raw = TQString::fromLatin1("X"); - TQFontMetrics fm = pb->fontMetrics(); - TQSize ts = fm.size( ShowPrefix, raw); - TQSize s(pb->style().tqsizeFromContents( TQStyle::CT_PushButton, pb, ts ) - .expandedTo(TQApplication::globalStrut())); - int margin = pb->style().pixelMetric( TQStyle::PM_ButtonMargin, pb) + - pb->style().pixelMetric( TQStyle::PM_DefaultFrameWidth, pb ) * 2; - int w = ts.width() + margin; - int h = s.height(); - if (pb->isDefault() || pb->autoDefault()) { - int dbw = pb->style().pixelMetric( TQStyle::PM_ButtonDefaultIndicator, pb ) * 2; - w += dbw; - } - - // add 30% margins to the width (heuristics to make it look similar to IE) - s = TQSize( w*13/10, h ).expandedTo(TQApplication::globalStrut()); - - setIntrinsicWidth( s.width() ); - setIntrinsicHeight( s.height() ); - - RenderButton::calcMinMaxWidth(); -} - -void RenderSubmitButton::updateFromElement() -{ - TQString oldText = static_cast<TQPushButton*>(m_widget)->text(); - TQString newText = rawText(); - static_cast<TQPushButton*>(m_widget)->setText(newText); - if ( oldText != newText ) - setNeedsLayoutAndMinMaxRecalc(); - RenderFormElement::updateFromElement(); -} - -short RenderSubmitButton::baselinePosition( bool f ) const -{ - return RenderFormElement::baselinePosition( f ); -} - -// ------------------------------------------------------------------------------- - -RenderResetButton::RenderResetButton(HTMLInputElementImpl *element) - : RenderSubmitButton(element) -{ -} - -// ------------------------------------------------------------------------------- - -LineEditWidget::LineEditWidget(DOM::HTMLInputElementImpl* input, KHTMLView* view, TQWidget* parent) - : KLineEdit(parent, "__khtml"), m_input(input), m_view(view), m_spell(0) -{ - setMouseTracking(true); - KActionCollection *ac = new KActionCollection(this); - m_spellAction = KStdAction::spelling( TQT_TQOBJECT(this), TQT_SLOT( slotCheckSpelling() ), ac ); -} - -LineEditWidget::~LineEditWidget() -{ - delete m_spell; - m_spell = 0L; -} - -void LineEditWidget::slotCheckSpelling() -{ - if ( text().isEmpty() ) { - return; - } - - delete m_spell; - m_spell = new KSpell( this, i18n( "Spell Checking" ), TQT_TQOBJECT(this), TQT_SLOT( slotSpellCheckReady( KSpell *) ), 0, true, true); - - connect( m_spell, TQT_SIGNAL( death() ),this, TQT_SLOT( spellCheckerFinished() ) ); - connect( m_spell, TQT_SIGNAL( misspelling( const TQString &, const TQStringList &, unsigned int ) ),this, TQT_SLOT( spellCheckerMisspelling( const TQString &, const TQStringList &, unsigned int ) ) ); - connect( m_spell, TQT_SIGNAL( corrected( const TQString &, const TQString &, unsigned int ) ),this, TQT_SLOT( spellCheckerCorrected( const TQString &, const TQString &, unsigned int ) ) ); -} - -void LineEditWidget::spellCheckerMisspelling( const TQString &_text, const TQStringList &, unsigned int pos) -{ - highLightWord( _text.length(),pos ); -} - -void LineEditWidget::highLightWord( unsigned int length, unsigned int pos ) -{ - setSelection ( pos, length ); -} - -void LineEditWidget::spellCheckerCorrected( const TQString &old, const TQString &corr, unsigned int pos ) -{ - if( old!= corr ) - { - setSelection ( pos, old.length() ); - insert( corr ); - setSelection ( pos, corr.length() ); - } -} - -void LineEditWidget::spellCheckerFinished() -{ -} - -void LineEditWidget::slotSpellCheckReady( KSpell *s ) -{ - s->check( text() ); - connect( s, TQT_SIGNAL( done( const TQString & ) ), this, TQT_SLOT( slotSpellCheckDone( const TQString & ) ) ); -} - -void LineEditWidget::slotSpellCheckDone( const TQString &s ) -{ - if( s != text() ) - setText( s ); -} - - -TQPopupMenu *LineEditWidget::createPopupMenu() -{ - TQPopupMenu *popup = KLineEdit::createPopupMenu(); - - if ( !popup ) { - return 0L; - } - - connect( popup, TQT_SIGNAL( activated( int ) ), - this, TQT_SLOT( extendedMenuActivated( int ) ) ); - - if (m_input->autoComplete()) { - popup->insertSeparator(); - int id = popup->insertItem( SmallIconSet("edit"), i18n("&Edit History..."), EditHistory ); - popup->setItemEnabled( id, (compObj() && !compObj()->isEmpty()) ); - id = popup->insertItem( SmallIconSet("history_clear"), i18n("Clear &History"), ClearHistory ); - popup->setItemEnabled( id, (compObj() && !compObj()->isEmpty()) ); - } - - if (echoMode() == TQLineEdit::Normal && - !isReadOnly()) { - popup->insertSeparator(); - - m_spellAction->plug(popup); - m_spellAction->setEnabled( !text().isEmpty() ); - } - - return popup; -} - - -void LineEditWidget::extendedMenuActivated( int id) -{ - switch ( id ) - { - case ClearHistory: - m_view->clearCompletionHistory(m_input->name().string()); - if (compObj()) - compObj()->clear(); - case EditHistory: - { - KHistoryComboEditor dlg( compObj() ? compObj()->items() : TQStringList(), this ); - connect( &dlg, TQT_SIGNAL( removeFromHistory(const TQString&) ), TQT_SLOT( slotRemoveFromHistory(const TQString&)) ); - dlg.exec(); - } - default: - break; - } -} - -void LineEditWidget::slotRemoveFromHistory(const TQString &entry) -{ - m_view->removeFormCompletionItem(m_input->name().string(), entry); - if (compObj()) - compObj()->removeItem(entry); -} - - -bool LineEditWidget::event( TQEvent *e ) -{ - if (KLineEdit::event(e)) - return true; - - if ( e->type() == TQEvent::AccelAvailable && isReadOnly() ) { - TQKeyEvent* ke = (TQKeyEvent*) e; - if ( ke->state() & ControlButton ) { - switch ( ke->key() ) { - case Key_Left: - case Key_Right: - case Key_Up: - case Key_Down: - case Key_Home: - case Key_End: - ke->accept(); - default: - break; - } - } - } - return false; -} - -void LineEditWidget::mouseMoveEvent(TQMouseEvent *e) -{ - // hack to prevent Qt from calling setCursor on the widget - setDragEnabled(false); - KLineEdit::mouseMoveEvent(e); - setDragEnabled(true); -} - - -// ----------------------------------------------------------------------------- - -RenderLineEdit::RenderLineEdit(HTMLInputElementImpl *element) - : RenderFormElement(element) -{ - LineEditWidget *edit = new LineEditWidget(element, view(), view()->viewport()); - connect(edit,TQT_SIGNAL(returnPressed()), this, TQT_SLOT(slotReturnPressed())); - connect(edit,TQT_SIGNAL(textChanged(const TQString &)),this,TQT_SLOT(slotTextChanged(const TQString &))); - - if(element->inputType() == HTMLInputElementImpl::PASSWORD) - edit->setEchoMode( TQLineEdit::Password ); - - if ( element->autoComplete() ) { - TQStringList completions = view()->formCompletionItems(element->name().string()); - if (completions.count()) { - edit->completionObject()->setItems(completions); - edit->setContextMenuEnabled(true); - edit->completionBox()->setTabHandling( false ); - } - } - - setQWidget(edit); -} - -void RenderLineEdit::setStyle(RenderStyle* _style) -{ - RenderFormElement::setStyle( _style ); - - widget()->setAlignment(textAlignment()); -} - -void RenderLineEdit::highLightWord( unsigned int length, unsigned int pos ) -{ - LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); - if ( w ) - w->highLightWord( length, pos ); -} - - -void RenderLineEdit::slotReturnPressed() -{ - // don't submit the form when return was pressed in a completion-popup - KCompletionBox *box = widget()->completionBox(false); - - if ( box && box->isVisible() && box->currentItem() != -1 ) { - box->hide(); - return; - } - - // Emit onChange if necessary - // Works but might not be enough, dirk said he had another solution at - // hand (can't remember which) - David - handleFocusOut(); - - HTMLFormElementImpl* fe = element()->form(); - if ( fe ) - fe->submitFromKeyboard(); -} - -void RenderLineEdit::handleFocusOut() -{ - if ( widget() && widget()->edited() ) { - element()->onChange(); - widget()->setEdited( false ); - } -} - -void RenderLineEdit::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - const TQFontMetrics &fm = style()->fontMetrics(); - TQSize s; - - int size = element()->size(); - - int h = fm.lineSpacing(); - int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17); // "some" - s = TQSize(w + 2 + 2*widget()->frameWidth(), - kMax(h, 14) + 2 + 2*widget()->frameWidth()) - .expandedTo(TQApplication::globalStrut()); - - setIntrinsicWidth( s.width() ); - setIntrinsicHeight( s.height() ); - - RenderFormElement::calcMinMaxWidth(); -} - -void RenderLineEdit::updateFromElement() -{ - int ml = element()->maxLength(); - if ( ml < 0 ) - ml = 32767; - - if ( widget()->maxLength() != ml ) { - widget()->setMaxLength( ml ); - } - - if (element()->value().string() != widget()->text()) { - widget()->blockSignals(true); - int pos = widget()->cursorPosition(); - widget()->setText(element()->value().string()); - - widget()->setEdited( false ); - - widget()->setCursorPosition(pos); - widget()->blockSignals(false); - } - widget()->setReadOnly(element()->readOnly()); - - RenderFormElement::updateFromElement(); -} - -void RenderLineEdit::slotTextChanged(const TQString &string) -{ - // don't use setValue here! - element()->m_value = string; - element()->m_unsubmittedFormChange = true; -} - -void RenderLineEdit::select() -{ - static_cast<LineEditWidget*>(m_widget)->selectAll(); -} - -long RenderLineEdit::selectionStart() -{ - LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); - if (w->hasSelectedText()) - return w->selectionStart(); - else - return w->cursorPosition(); -} - - -long RenderLineEdit::selectionEnd() -{ - LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); - if (w->hasSelectedText()) - return w->selectionStart() + w->selectedText().length(); - else - return w->cursorPosition(); -} - -void RenderLineEdit::setSelectionStart(long pos) -{ - LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); - //See whether we have a non-empty selection now. - long end = selectionEnd(); - if (end > pos) - w->setSelection(pos, end - pos); - w->setCursorPosition(pos); -} - -void RenderLineEdit::setSelectionEnd(long pos) -{ - LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); - //See whether we have a non-empty selection now. - long start = selectionStart(); - if (start < pos) - w->setSelection(start, pos - start); - - w->setCursorPosition(pos); -} - -void RenderLineEdit::setSelectionRange(long start, long end) -{ - LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); - w->setCursorPosition(end); - w->setSelection(start, end - start); -} - -// --------------------------------------------------------------------------- - -RenderFieldset::RenderFieldset(HTMLGenericFormElementImpl *element) - : RenderBlock(element) -{ -} - -RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) -{ - RenderObject* legend = findLegend(); - if (legend) { - if (relayoutChildren) - legend->setNeedsLayout(true); - legend->layoutIfNeeded(); - - int xPos = borderLeft() + paddingLeft() + legend->marginLeft(); - if (style()->direction() == RTL) - xPos = m_width - paddingRight() - borderRight() - legend->width() - legend->marginRight(); - int b = borderTop(); - int h = legend->height(); - legend->setPos(xPos, kMax((b-h)/2, 0)); - m_height = kMax(b,h) + paddingTop(); - } - return legend; -} - -RenderObject* RenderFieldset::findLegend() -{ - for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) { - if (!legend->isFloatingOrPositioned() && legend->element() && - legend->element()->id() == ID_LEGEND) - return legend; - } - return 0; -} - -void RenderFieldset::paintBoxDecorations(PaintInfo& pI, int _tx, int _ty) -{ - //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl; - - RenderObject* legend = findLegend(); - if (!legend) - return RenderBlock::paintBoxDecorations(pI, _tx, _ty); - - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - int yOff = (legend->yPos() > 0) ? 0 : (legend->height()-borderTop())/2; - h -= yOff; - _ty += yOff - borderTopExtra(); - - int my = kMax(_ty,pI.r.y()); - int end = kMin( pI.r.y() + pI.r.height(), _ty + h ); - int mh = end - my; - - paintBackground(pI.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h); - - if ( style()->hasBorder() ) - paintBorderMinusLegend(pI.p, _tx, _ty, w, h, style(), legend->xPos(), legend->width()); -} - -void RenderFieldset::paintBorderMinusLegend(TQPainter *p, int _tx, int _ty, int w, int h, - const RenderStyle* style, int lx, int lw) -{ - - const TQColor& tc = style->borderTopColor(); - const TQColor& bc = style->borderBottomColor(); - - EBorderStyle ts = style->borderTopStyle(); - EBorderStyle bs = style->borderBottomStyle(); - EBorderStyle ls = style->borderLeftStyle(); - EBorderStyle rs = style->borderRightStyle(); - - bool render_t = ts > BHIDDEN; - bool render_l = ls > BHIDDEN; - bool render_r = rs > BHIDDEN; - bool render_b = bs > BHIDDEN; - - if(render_t) { - drawBorder(p, _tx, _ty, _tx + lx, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, - (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE)?style->borderLeftWidth():0), 0); - drawBorder(p, _tx+lx+lw, _ty, _tx + w, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, - 0, (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE)?style->borderRightWidth():0)); - } - - if(render_b) - drawBorder(p, _tx, _ty + h - style->borderBottomWidth(), _tx + w, _ty + h, BSBottom, bc, style->color(), bs, - (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE)?style->borderLeftWidth():0), - (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE)?style->borderRightWidth():0)); - - if(render_l) - { - const TQColor& lc = style->borderLeftColor(); - - bool ignore_top = - (tc == lc) && - (ls >= OUTSET) && - (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); - - bool ignore_bottom = - (bc == lc) && - (ls >= OUTSET) && - (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); - - drawBorder(p, _tx, _ty, _tx + style->borderLeftWidth(), _ty + h, BSLeft, lc, style->color(), ls, - ignore_top?0:style->borderTopWidth(), - ignore_bottom?0:style->borderBottomWidth()); - } - - if(render_r) - { - const TQColor& rc = style->borderRightColor(); - - bool ignore_top = - (tc == rc) && - (rs >= DOTTED || rs == INSET) && - (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); - - bool ignore_bottom = - (bc == rc) && - (rs >= DOTTED || rs == INSET) && - (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); - - drawBorder(p, _tx + w - style->borderRightWidth(), _ty, _tx + w, _ty + h, BSRight, rc, style->color(), rs, - ignore_top?0:style->borderTopWidth(), - ignore_bottom?0:style->borderBottomWidth()); - } -} - -void RenderFieldset::setStyle(RenderStyle* _style) -{ - RenderBlock::setStyle(_style); - - // WinIE renders fieldsets with display:inline like they're inline-blocks. For us, - // an inline-block is just a block element with replaced set to true and inline set - // to true. Ensure that if we ended up being inline that we set our replaced flag - // so that we're treated like an inline-block. - if (isInline()) - setReplaced(true); -} - -// ------------------------------------------------------------------------- - -RenderFileButton::RenderFileButton(HTMLInputElementImpl *element) - : RenderFormElement(element) -{ - KURLRequester* w = new KURLRequester( view()->viewport(), "__khtml" ); - - w->setMode(KFile::File | KFile::ExistingOnly); - w->completionObject()->setDir(TDEGlobalSettings::documentPath()); - - connect(w->lineEdit(), TQT_SIGNAL(returnPressed()), this, TQT_SLOT(slotReturnPressed())); - connect(w->lineEdit(), TQT_SIGNAL(textChanged(const TQString &)),this,TQT_SLOT(slotTextChanged(const TQString &))); - connect(w, TQT_SIGNAL(urlSelected(const TQString &)),this,TQT_SLOT(slotUrlSelected(const TQString &))); - - setQWidget(w); - m_haveFocus = false; -} - - - -void RenderFileButton::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - const TQFontMetrics &fm = style()->fontMetrics(); - int size = element()->size(); - - int h = fm.lineSpacing(); - int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17); // "some" - KLineEdit* edit = static_cast<KURLRequester*>( m_widget )->lineEdit(); - TQSize s = edit->style().tqsizeFromContents(TQStyle::CT_LineEdit, - edit, - TQSize(w + 2 + 2*edit->frameWidth(), kMax(h, 14) + 2 + 2*edit->frameWidth())) - .expandedTo(TQApplication::globalStrut()); - TQSize bs = static_cast<KURLRequester*>( m_widget )->minimumSizeHint() - edit->minimumSizeHint(); - - setIntrinsicWidth( s.width() + bs.width() ); - setIntrinsicHeight( kMax(s.height(), bs.height()) ); - - RenderFormElement::calcMinMaxWidth(); -} - -void RenderFileButton::handleFocusOut() -{ - if ( widget()->lineEdit() && widget()->lineEdit()->edited() ) { - element()->onChange(); - widget()->lineEdit()->setEdited( false ); - } -} - -void RenderFileButton::updateFromElement() -{ - KLineEdit* edit = widget()->lineEdit(); - edit->blockSignals(true); - edit->setText(element()->value().string()); - edit->blockSignals(false); - edit->setEdited( false ); - - RenderFormElement::updateFromElement(); -} - -void RenderFileButton::slotReturnPressed() -{ - handleFocusOut(); - - if (element()->form()) - element()->form()->submitFromKeyboard(); -} - -void RenderFileButton::slotTextChanged(const TQString &/*string*/) -{ - element()->m_value = KURL( widget()->url() ).prettyURL( 0, KURL::StripFileProtocol ); -} - -void RenderFileButton::slotUrlSelected(const TQString &) -{ - element()->onChange(); -} - -void RenderFileButton::select() -{ - widget()->lineEdit()->selectAll(); -} - -// ------------------------------------------------------------------------- - -RenderLabel::RenderLabel(HTMLGenericFormElementImpl *element) - : RenderFormElement(element) -{ - -} - -// ------------------------------------------------------------------------- - -RenderLegend::RenderLegend(HTMLGenericFormElementImpl *element) - : RenderBlock(element) -{ -} - -// ------------------------------------------------------------------------------- - -ComboBoxWidget::ComboBoxWidget(TQWidget *parent) - : KComboBox(false, parent, "__khtml") -{ - setAutoMask(true); - if (listBox()) listBox()->installEventFilter(this); - setMouseTracking(true); -} - -bool ComboBoxWidget::event(TQEvent *e) -{ - if (KComboBox::event(e)) - return true; - if (e->type()==TQEvent::KeyPress) - { - TQKeyEvent *ke = TQT_TQKEYEVENT(e); - switch(ke->key()) - { - case Key_Return: - case Key_Enter: - popup(); - ke->accept(); - return true; - default: - return false; - } - } - return false; -} - -bool ComboBoxWidget::eventFilter(TQObject *dest, TQEvent *e) -{ - if (TQT_BASE_OBJECT(dest)==TQT_BASE_OBJECT(listBox()) && e->type()==TQEvent::KeyPress) - { - TQKeyEvent *ke = TQT_TQKEYEVENT(e); - bool forward = false; - switch(ke->key()) - { - case Key_Tab: - forward=true; - case Key_BackTab: - // ugly hack. emulate popdownlistbox() (private in TQComboBox) - // we re-use ke here to store the reference to the generated event. - ke = new TQKeyEvent(TQEvent::KeyPress, Key_Escape, 0, 0); - TQApplication::sendEvent(dest,ke); - focusNextPrevChild(forward); - delete ke; - return true; - default: - return KComboBox::eventFilter(dest, e); - } - } - return KComboBox::eventFilter(dest, e); -} - -// ------------------------------------------------------------------------- - -RenderSelect::RenderSelect(HTMLSelectElementImpl *element) - : RenderFormElement(element) -{ - m_ignoreSelectEvents = false; - m_multiple = element->multiple(); - m_size = element->size(); - m_useListBox = (m_multiple || m_size > 1); - m_selectionChanged = true; - m_optionsChanged = true; - - if(m_useListBox) - setQWidget(createListBox()); - else - setQWidget(createComboBox()); -} - -void RenderSelect::updateFromElement() -{ - m_ignoreSelectEvents = true; - - // change widget type - bool oldMultiple = m_multiple; - unsigned oldSize = m_size; - bool oldListbox = m_useListBox; - - m_multiple = element()->multiple(); - m_size = element()->size(); - m_useListBox = (m_multiple || m_size > 1); - - if (oldMultiple != m_multiple || oldSize != m_size) { - if (m_useListBox != oldListbox) { - // type of select has changed - if(m_useListBox) - setQWidget(createListBox()); - else - setQWidget(createComboBox()); - } - - if (m_useListBox && oldMultiple != m_multiple) { - static_cast<KListBox*>(m_widget)->setSelectionMode(m_multiple ? TQListBox::Extended : TQListBox::Single); - } - m_selectionChanged = true; - m_optionsChanged = true; - } - - // update contents listbox/combobox based on options in m_element - if ( m_optionsChanged ) { - if (element()->m_recalcListItems) - element()->recalcListItems(); - TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); - int listIndex; - - if(m_useListBox) { - static_cast<KListBox*>(m_widget)->clear(); - } - - else - static_cast<KComboBox*>(m_widget)->clear(); - - for (listIndex = 0; listIndex < int(listItems.size()); listIndex++) { - if (listItems[listIndex]->id() == ID_OPTGROUP) { - DOMString text = listItems[listIndex]->getAttribute(ATTR_LABEL); - if (text.isNull()) - text = ""; - - if(m_useListBox) { - TQListBoxText *item = new TQListBoxText(TQString(text.implementation()->s, text.implementation()->l)); - static_cast<KListBox*>(m_widget) - ->insertItem(item, listIndex); - item->setSelectable(false); - } - else { - static_cast<KComboBox*>(m_widget) - ->insertItem(TQString(text.implementation()->s, text.implementation()->l), listIndex); - static_cast<KComboBox*>(m_widget)->listBox()->item(listIndex)->setSelectable(false); - } - } - else if (listItems[listIndex]->id() == ID_OPTION) { - HTMLOptionElementImpl* optElem = static_cast<HTMLOptionElementImpl*>(listItems[listIndex]); - TQString text = optElem->text().string(); - if (optElem->parentNode()->id() == ID_OPTGROUP) - { - // Prefer label if set - DOMString label = optElem->getAttribute(ATTR_LABEL); - if (!label.isEmpty()) - text = label.string(); - text = TQString::fromLatin1(" ")+text; - } - - if(m_useListBox) { - KListBox *l = static_cast<KListBox*>(m_widget); - l->insertItem(text, listIndex); - DOMString disabled = optElem->getAttribute(ATTR_DISABLED); - if (!disabled.isNull() && l->item( listIndex )) { - l->item( listIndex )->setSelectable( false ); - } - } else - static_cast<KComboBox*>(m_widget)->insertItem(text, listIndex); - } - else - KHTMLAssert(false); - m_selectionChanged = true; - } - - // TQComboBox caches the size hint unless you call setFont (ref: TT docu) - if(!m_useListBox) { - KComboBox *that = static_cast<KComboBox*>(m_widget); - that->setFont( that->font() ); - } - setNeedsLayoutAndMinMaxRecalc(); - m_optionsChanged = false; - } - - // update selection - if (m_selectionChanged) { - updateSelection(); - } - - - m_ignoreSelectEvents = false; - - RenderFormElement::updateFromElement(); -} - -void RenderSelect::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - if (m_optionsChanged) - updateFromElement(); - - // ### ugly HACK FIXME!!! - setMinMaxKnown(); - layoutIfNeeded(); - setNeedsLayoutAndMinMaxRecalc(); - // ### end FIXME - - RenderFormElement::calcMinMaxWidth(); -} - -void RenderSelect::layout( ) -{ - KHTMLAssert(needsLayout()); - KHTMLAssert(minMaxKnown()); - - // ### maintain selection properly between type/size changes, and work - // out how to handle multiselect->singleselect (probably just select - // first selected one) - - // calculate size - if(m_useListBox) { - KListBox* w = static_cast<KListBox*>(m_widget); - - TQListBoxItem* p = w->firstItem(); - int width = 0; - int height = 0; - while(p) { - width = kMax(width, p->width(p->listBox())); - height = kMax(height, p->height(p->listBox())); - p = p->next(); - } - if ( !height ) - height = w->fontMetrics().height(); - if ( !width ) - width = w->fontMetrics().width( 'x' ); - - int size = m_size; - // check if multiple and size was not given or invalid - // Internet Exploder sets size to kMin(number of elements, 4) - // Netscape seems to simply set it to "number of elements" - // the average of that is IMHO kMin(number of elements, 10) - // so I did that ;-) - if(size < 1) - size = kMin(static_cast<KListBox*>(m_widget)->count(), 10u); - - width += 2*w->frameWidth() + w->verticalScrollBar()->sizeHint().width(); - height = size*height + 2*w->frameWidth(); - - setIntrinsicWidth( width ); - setIntrinsicHeight( height ); - } - else { - TQSize s(m_widget->sizeHint()); - setIntrinsicWidth( s.width() ); - setIntrinsicHeight( s.height() ); - } - - /// uuh, ignore the following line.. - setNeedsLayout(true); - RenderFormElement::layout(); - - // and now disable the widget in case there is no <option> given - TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); - - bool foundOption = false; - for (uint i = 0; i < listItems.size() && !foundOption; i++) - foundOption = (listItems[i]->id() == ID_OPTION); - - m_widget->setEnabled(foundOption && ! element()->disabled()); -} - -void RenderSelect::slotSelected(int index) // emitted by the combobox only -{ - if ( m_ignoreSelectEvents ) return; - - KHTMLAssert( !m_useListBox ); - - TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); - if(index >= 0 && index < int(listItems.size())) - { - bool found = ( listItems[index]->id() == ID_OPTION ); - - if ( !found ) { - // this one is not selectable, we need to find an option element - while ( ( unsigned ) index < listItems.size() ) { - if ( listItems[index]->id() == ID_OPTION ) { - found = true; - break; - } - ++index; - } - - if ( !found ) { - while ( index >= 0 ) { - if ( listItems[index]->id() == ID_OPTION ) { - found = true; - break; - } - --index; - } - } - } - - if ( found ) { - bool changed = false; - - for ( unsigned int i = 0; i < listItems.size(); ++i ) - if ( listItems[i]->id() == ID_OPTION && i != (unsigned int) index ) - { - HTMLOptionElementImpl* opt = static_cast<HTMLOptionElementImpl*>( listItems[i] ); - changed |= (opt->m_selected == true); - opt->m_selected = false; - } - - HTMLOptionElementImpl* opt = static_cast<HTMLOptionElementImpl*>(listItems[index]); - changed |= (opt->m_selected == false); - opt->m_selected = true; - - if ( index != static_cast<ComboBoxWidget*>( m_widget )->currentItem() ) - static_cast<ComboBoxWidget*>( m_widget )->setCurrentItem( index ); - - // When selecting an optgroup item, and we move forward to we - // shouldn't emit onChange. Hence this bool, the if above doesn't do it. - if ( changed ) - { - ref(); - element()->onChange(); - deref(); - } - } - } -} - - -void RenderSelect::slotSelectionChanged() // emitted by the listbox only -{ - if ( m_ignoreSelectEvents ) return; - - // don't use listItems() here as we have to avoid recalculations - changing the - // option list will make use update options not in the way the user expects them - TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->m_listItems; - for ( unsigned i = 0; i < listItems.count(); i++ ) - // don't use setSelected() here because it will cause us to be called - // again with updateSelection. - if ( listItems[i]->id() == ID_OPTION ) - static_cast<HTMLOptionElementImpl*>( listItems[i] ) - ->m_selected = static_cast<KListBox*>( m_widget )->isSelected( i ); - - ref(); - element()->onChange(); - deref(); -} - -void RenderSelect::setOptionsChanged(bool _optionsChanged) -{ - m_optionsChanged = _optionsChanged; -} - -KListBox* RenderSelect::createListBox() -{ - KListBox *lb = new KListBox(view()->viewport(), "__khtml"); - lb->setSelectionMode(m_multiple ? TQListBox::Extended : TQListBox::Single); - // ### looks broken - //lb->setAutoMask(true); - connect( lb, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotSelectionChanged() ) ); -// connect( lb, TQT_SIGNAL( clicked( TQListBoxItem * ) ), this, TQT_SLOT( slotClicked() ) ); - m_ignoreSelectEvents = false; - lb->setMouseTracking(true); - - return lb; -} - -ComboBoxWidget *RenderSelect::createComboBox() -{ - ComboBoxWidget *cb = new ComboBoxWidget(view()->viewport()); - connect(cb, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSelected(int))); - return cb; -} - -void RenderSelect::updateSelection() -{ - TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); - int i; - if (m_useListBox) { - // if multi-select, we select only the new selected index - KListBox *listBox = static_cast<KListBox*>(m_widget); - for (i = 0; i < int(listItems.size()); i++) - listBox->setSelected(i,listItems[i]->id() == ID_OPTION && - static_cast<HTMLOptionElementImpl*>(listItems[i])->selected()); - } - else { - bool found = false; - unsigned firstOption = listItems.size(); - i = listItems.size(); - while (i--) - if (listItems[i]->id() == ID_OPTION) { - if (found) - static_cast<HTMLOptionElementImpl*>(listItems[i])->m_selected = false; - else if (static_cast<HTMLOptionElementImpl*>(listItems[i])->selected()) { - static_cast<KComboBox*>( m_widget )->setCurrentItem(i); - found = true; - } - firstOption = i; - } - - Q_ASSERT(firstOption == listItems.size() || found); - } - - m_selectionChanged = false; -} - - -// ------------------------------------------------------------------------- - -TextAreaWidget::TextAreaWidget(int wrap, TQWidget* parent) - : KTextEdit(parent, "__khtml"), m_findDlg(0), m_find(0), m_repDlg(0), m_replace(0) -{ - if(wrap != DOM::HTMLTextAreaElementImpl::ta_NoWrap) { - setWordWrap(TQTextEdit::WidgetWidth); - setHScrollBarMode( AlwaysOff ); - setVScrollBarMode( AlwaysOn ); - } - else { - setWordWrap(TQTextEdit::NoWrap); - setHScrollBarMode( Auto ); - setVScrollBarMode( Auto ); - } - KCursor::setAutoHideCursor(viewport(), true); - setTextFormat(TQTextEdit::PlainText); - setAutoMask(true); - setMouseTracking(true); - - KActionCollection *ac = new KActionCollection(this); - m_findAction = KStdAction::find( TQT_TQOBJECT(this), TQT_SLOT( slotFind() ), ac ); - m_findNextAction = KStdAction::findNext( TQT_TQOBJECT(this), TQT_SLOT( slotFindNext() ), ac ); - m_replaceAction = KStdAction::replace( TQT_TQOBJECT(this), TQT_SLOT( slotReplace() ), ac ); -} - - -TextAreaWidget::~TextAreaWidget() -{ - delete m_replace; - m_replace = 0L; - delete m_find; - m_find = 0L; - delete m_repDlg; - m_repDlg = 0L; - delete m_findDlg; - m_findDlg = 0L; -} - - -TQPopupMenu *TextAreaWidget::createPopupMenu(const TQPoint& pos) -{ - TQPopupMenu *popup = KTextEdit::createPopupMenu(pos); - - if ( !popup ) { - return 0L; - } - - if (!isReadOnly()) { - popup->insertSeparator(); - - m_findAction->plug(popup); - m_findAction->setEnabled( !text().isEmpty() ); - - m_findNextAction->plug(popup); - m_findNextAction->setEnabled( m_find != 0 ); - - m_replaceAction->plug(popup); - m_replaceAction->setEnabled( !text().isEmpty() ); - } - - return popup; -} - - -void TextAreaWidget::slotFindHighlight(const TQString& text, int matchingIndex, int matchingLength) -{ - Q_UNUSED(text) - //kdDebug() << "Highlight: [" << text << "] mi:" << matchingIndex << " ml:" << matchingLength << endl; - if (sender() == m_replace) { - setSelection(m_repPara, matchingIndex, m_repPara, matchingIndex + matchingLength); - setCursorPosition(m_repPara, matchingIndex); - } else { - setSelection(m_findPara, matchingIndex, m_findPara, matchingIndex + matchingLength); - setCursorPosition(m_findPara, matchingIndex); - } - ensureCursorVisible(); -} - - -void TextAreaWidget::slotReplaceText(const TQString &text, int replacementIndex, int /*replacedLength*/, int matchedLength) { - Q_UNUSED(text) - //kdDebug() << "Replace: [" << text << "] ri:" << replacementIndex << " rl:" << replacedLength << " ml:" << matchedLength << endl; - setSelection(m_repPara, replacementIndex, m_repPara, replacementIndex + matchedLength); - removeSelectedText(); - insertAt(m_repDlg->replacement(), m_repPara, replacementIndex); - if (m_replace->options() & KReplaceDialog::PromptOnReplace) { - ensureCursorVisible(); - } -} - - -void TextAreaWidget::slotDoReplace() -{ - if (!m_repDlg) { - // Should really assert() - return; - } - - delete m_replace; - m_replace = new KReplace(m_repDlg->pattern(), m_repDlg->replacement(), m_repDlg->options(), this); - if (m_replace->options() & KFindDialog::FromCursor) { - getCursorPosition(&m_repPara, &m_repIndex); - } else if (m_replace->options() & KFindDialog::FindBackwards) { - m_repPara = paragraphs() - 1; - m_repIndex = paragraphLength(m_repPara) - 1; - } else { - m_repPara = 0; - m_repIndex = 0; - } - - // Connect highlight signal to code which handles highlighting - // of found text. - connect(m_replace, TQT_SIGNAL(highlight(const TQString &, int, int)), - this, TQT_SLOT(slotFindHighlight(const TQString &, int, int))); - connect(m_replace, TQT_SIGNAL(findNext()), this, TQT_SLOT(slotReplaceNext())); - connect(m_replace, TQT_SIGNAL(replace(const TQString &, int, int, int)), - this, TQT_SLOT(slotReplaceText(const TQString &, int, int, int))); - - m_repDlg->close(); - slotReplaceNext(); -} - - -void TextAreaWidget::slotReplaceNext() -{ - if (!m_replace) { - // assert? - return; - } - - if (!(m_replace->options() & KReplaceDialog::PromptOnReplace)) { - viewport()->setUpdatesEnabled(false); - } - - KFind::Result res = KFind::NoMatch; - while (res == KFind::NoMatch) { - // If we're done..... - if (m_replace->options() & KFindDialog::FindBackwards) { - if (m_repIndex == 0 && m_repPara == 0) { - break; - } - } else { - if (m_repPara == paragraphs() - 1 && - m_repIndex == paragraphLength(m_repPara) - 1) { - break; - } - } - - if (m_replace->needData()) { - m_replace->setData(text(m_repPara), m_repIndex); - } - - res = m_replace->replace(); - - if (res == KFind::NoMatch) { - if (m_replace->options() & KFindDialog::FindBackwards) { - if (m_repPara == 0) { - m_repIndex = 0; - } else { - m_repPara--; - m_repIndex = paragraphLength(m_repPara) - 1; - } - } else { - if (m_repPara == paragraphs() - 1) { - m_repIndex = paragraphLength(m_repPara) - 1; - } else { - m_repPara++; - m_repIndex = 0; - } - } - } - } - - if (!(m_replace->options() & KReplaceDialog::PromptOnReplace)) { - viewport()->setUpdatesEnabled(true); - repaintChanged(); - } - - if (res == KFind::NoMatch) { // at end - m_replace->displayFinalDialog(); - delete m_replace; - m_replace = 0; - ensureCursorVisible(); - //or if ( m_replace->shouldRestart() ) { reinit (w/o FromCursor) and call slotReplaceNext(); } - } else { - //m_replace->closeReplaceNextDialog(); - } -} - - -void TextAreaWidget::slotDoFind() -{ - if (!m_findDlg) { - // Should really assert() - return; - } - - delete m_find; - m_find = new KFind(m_findDlg->pattern(), m_findDlg->options(), this); - if (m_find->options() & KFindDialog::FromCursor) { - getCursorPosition(&m_findPara, &m_findIndex); - } else if (m_find->options() & KFindDialog::FindBackwards) { - m_findPara = paragraphs() - 1; - m_findIndex = paragraphLength(m_findPara) - 1; - } else { - m_findPara = 0; - m_findIndex = 0; - } - - // Connect highlight signal to code which handles highlighting - // of found text. - connect(m_find, TQT_SIGNAL(highlight(const TQString &, int, int)), - this, TQT_SLOT(slotFindHighlight(const TQString &, int, int))); - connect(m_find, TQT_SIGNAL(findNext()), this, TQT_SLOT(slotFindNext())); - - m_findDlg->close(); - m_find->closeFindNextDialog(); - slotFindNext(); -} - - -void TextAreaWidget::slotFindNext() -{ - if (!m_find) { - // assert? - return; - } - - KFind::Result res = KFind::NoMatch; - while (res == KFind::NoMatch) { - // If we're done..... - if (m_find->options() & KFindDialog::FindBackwards) { - if (m_findIndex == 0 && m_findPara == 0) { - break; - } - } else { - if (m_findPara == paragraphs() - 1 && - m_findIndex == paragraphLength(m_findPara) - 1) { - break; - } - } - - if (m_find->needData()) { - m_find->setData(text(m_findPara), m_findIndex); - } - - res = m_find->find(); - - if (res == KFind::NoMatch) { - if (m_find->options() & KFindDialog::FindBackwards) { - if (m_findPara == 0) { - m_findIndex = 0; - } else { - m_findPara--; - m_findIndex = paragraphLength(m_findPara) - 1; - } - } else { - if (m_findPara == paragraphs() - 1) { - m_findIndex = paragraphLength(m_findPara) - 1; - } else { - m_findPara++; - m_findIndex = 0; - } - } - } - } - - if (res == KFind::NoMatch) { // at end - m_find->displayFinalDialog(); - delete m_find; - m_find = 0; - //or if ( m_find->shouldRestart() ) { reinit (w/o FromCursor) and call slotFindNext(); } - } else { - //m_find->closeFindNextDialog(); - } -} - - -void TextAreaWidget::slotFind() -{ - if( text().isEmpty() ) // saves having to track the text changes - return; - - if ( m_findDlg ) { - KWin::activateWindow( m_findDlg->winId() ); - } else { - m_findDlg = new KFindDialog(false, this, "KHTML Text Area Find Dialog"); - connect( m_findDlg, TQT_SIGNAL(okClicked()), this, TQT_SLOT(slotDoFind()) ); - } - m_findDlg->show(); -} - - -void TextAreaWidget::slotReplace() -{ - if( text().isEmpty() ) // saves having to track the text changes - return; - - if ( m_repDlg ) { - KWin::activateWindow( m_repDlg->winId() ); - } else { - m_repDlg = new KReplaceDialog(this, "KHTMLText Area Replace Dialog", 0, - TQStringList(), TQStringList(), false); - connect( m_repDlg, TQT_SIGNAL(okClicked()), this, TQT_SLOT(slotDoReplace()) ); - } - m_repDlg->show(); -} - - -bool TextAreaWidget::event( TQEvent *e ) -{ - if ( e->type() == TQEvent::AccelAvailable && isReadOnly() ) { - TQKeyEvent* ke = (TQKeyEvent*) e; - if ( ke->state() & ControlButton ) { - switch ( ke->key() ) { - case Key_Left: - case Key_Right: - case Key_Up: - case Key_Down: - case Key_Home: - case Key_End: - ke->accept(); - default: - break; - } - } - } - return KTextEdit::event( e ); -} - -// ------------------------------------------------------------------------- - -RenderTextArea::RenderTextArea(HTMLTextAreaElementImpl *element) - : RenderFormElement(element) -{ - scrollbarsStyled = false; - - TextAreaWidget *edit = new TextAreaWidget(element->wrap(), view()); - setQWidget(edit); - const KHTMLSettings *settings = view()->part()->settings(); - edit->setCheckSpellingEnabled( settings->autoSpellCheck() ); - edit->setTabChangesFocus( ! settings->allowTabulation() ); - - connect(edit,TQT_SIGNAL(textChanged()),this,TQT_SLOT(slotTextChanged())); -} - -RenderTextArea::~RenderTextArea() -{ - if ( element()->m_dirtyvalue ) { - element()->m_value = text(); - element()->m_dirtyvalue = false; - } -} - -void RenderTextArea::handleFocusOut() -{ - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - if ( w && element()->m_dirtyvalue ) { - element()->m_value = text(); - element()->m_dirtyvalue = false; - } - - if ( w && element()->m_changed ) { - element()->m_changed = false; - element()->onChange(); - } -} - -void RenderTextArea::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - const TQFontMetrics &m = style()->fontMetrics(); - w->setTabStopWidth(8 * m.width(" ")); - TQSize size( kMax(element()->cols(), 1L)*m.width('x') + w->frameWidth() + - w->verticalScrollBar()->sizeHint().width(), - kMax(element()->rows(), 1L)*m.lineSpacing() + w->frameWidth()*4 + - (w->wordWrap() == TQTextEdit::NoWrap ? - w->horizontalScrollBar()->sizeHint().height() : 0) - ); - - setIntrinsicWidth( size.width() ); - setIntrinsicHeight( size.height() ); - - RenderFormElement::calcMinMaxWidth(); -} - -void RenderTextArea::setStyle(RenderStyle* _style) -{ - bool unsubmittedFormChange = element()->m_unsubmittedFormChange; - - RenderFormElement::setStyle(_style); - - widget()->blockSignals(true); - widget()->setAlignment(textAlignment()); - widget()->blockSignals(false); - - scrollbarsStyled = false; - - element()->m_unsubmittedFormChange = unsubmittedFormChange; -} - -void RenderTextArea::layout() -{ - KHTMLAssert( needsLayout() ); - - RenderFormElement::layout(); - - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - - if (!scrollbarsStyled) { - w->horizontalScrollBar()->setPalette(style()->palette()); - w->verticalScrollBar()->setPalette(style()->palette()); - scrollbarsStyled=true; - } -} - -void RenderTextArea::updateFromElement() -{ - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - w->setReadOnly(element()->readOnly()); - TQString elementText = element()->value().string(); - if ( elementText != text() ) - { - w->blockSignals(true); - int line, col; - w->getCursorPosition( &line, &col ); - int cx = w->contentsX(); - int cy = w->contentsY(); - w->setText( elementText ); - w->setCursorPosition( line, col ); - w->scrollBy( cx, cy ); - w->blockSignals(false); - } - element()->m_dirtyvalue = false; - - RenderFormElement::updateFromElement(); -} - -void RenderTextArea::close( ) -{ - element()->setValue( element()->defaultValue() ); - - RenderFormElement::close(); -} - - -TQString RenderTextArea::text() -{ - TQString txt; - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - - if(element()->wrap() == DOM::HTMLTextAreaElementImpl::ta_Physical) { - // yeah, TQTextEdit has no accessor for getting the visually wrapped text - for (int p=0; p < w->paragraphs(); ++p) { - int ll = 0; - int lindex = w->lineOfChar(p, 0); - TQString paragraphText = w->text(p); - int pl = w->paragraphLength(p); - paragraphText = paragraphText.left(pl); //Snip invented space. - for (int l = 0; l < pl; ++l) { - if (lindex != w->lineOfChar(p, l)) { - paragraphText.insert(l+ll++, TQString::fromLatin1("\n")); - lindex = w->lineOfChar(p, l); - } - } - txt += paragraphText; - if (p < w->paragraphs() - 1) - txt += TQString::fromLatin1("\n"); - } - } - else - txt = w->text(); - - return txt; -} - -int RenderTextArea::queryParagraphInfo(int para, Mode m, int param) { - /* We have to be a bit careful here, as we need to match up the positions - to what our value returns here*/ - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - int length = 0; - - bool physWrap = element()->wrap() == DOM::HTMLTextAreaElementImpl::ta_Physical; - - TQString paragraphText = w->text(para); - int pl = w->paragraphLength(para); - int physicalPL = pl; - if (m == ParaPortionLength) - pl = param; - - if (physWrap) { - //Go through all the chars of paragraph, and count line changes, chars, etc. - int lindex = w->lineOfChar(para, 0); - for (int c = 0; c < pl; ++c) { - ++length; - // Is there a change after this char? - if (c+1 < physicalPL && lindex != w->lineOfChar(para, c+1)) { - lindex = w->lineOfChar(para, c+1); - ++length; - } - if (m == ParaPortionOffset && length > param) - return c; - } - } else { - //Make sure to count the LF, CR as appropriate. ### this is stupid now, simplify - for (int c = 0; c < pl; ++c) { - ++length; - if (m == ParaPortionOffset && length > param) - return c; - } - } - if (m == ParaPortionOffset) - return pl; - if (m == ParaPortionLength) - return length; - return length + 1; -} - -long RenderTextArea::computeCharOffset(int para, int index) { - if (para < 0) - return 0; - - long pos = 0; - for (int cp = 0; cp < para; ++cp) - pos += queryParagraphInfo(cp, ParaLength); - - if (index >= 0) - pos += queryParagraphInfo(para, ParaPortionLength, index); - return pos; -} - -void RenderTextArea::computeParagraphAndIndex(long offset, int* para, int* index) { - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - - if (!w->paragraphs()) { - *para = -1; - *index = -1; - return; - } - - //Find the paragraph that contains us.. - int containingPar = 0; - long endPos = 0; - long startPos = 0; - for (int p = 0; p < w->paragraphs(); ++p) { - int len = queryParagraphInfo(p, ParaLength); - endPos += len; - if (endPos > offset) { - containingPar = p; - break; - } - startPos += len; - } - - *para = containingPar; - - //Now, scan within the paragraph to find the position.. - long localOffset = offset - startPos; - - *index = queryParagraphInfo(containingPar, ParaPortionOffset, localOffset); -} - -void RenderTextArea::highLightWord( unsigned int length, unsigned int pos ) -{ - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - if ( w ) - w->highLightWord( length, pos ); -} - - -void RenderTextArea::slotTextChanged() -{ - element()->m_dirtyvalue = true; - element()->m_changed = true; - if (element()->m_value != text()) - element()->m_unsubmittedFormChange = true; -} - -void RenderTextArea::select() -{ - static_cast<TextAreaWidget *>(m_widget)->selectAll(); -} - -long RenderTextArea::selectionStart() -{ - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - int para, index, dummy1, dummy2; - w->getSelection(¶, &index, &dummy1, &dummy2); - if (para == -1 || index == -1) - w->getCursorPosition(¶, &index); - - return computeCharOffset(para, index); -} - -long RenderTextArea::selectionEnd() -{ - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - int para, index, dummy1, dummy2; - w->getSelection(&dummy1, &dummy2, ¶, &index); - if (para == -1 || index == -1) - w->getCursorPosition(¶, &index); - - return computeCharOffset(para, index); -} - -void RenderTextArea::setSelectionStart(long offset) { - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - int fromPara, fromIndex, toPara, toIndex; - w->getSelection(&fromPara, &fromIndex, &toPara, &toIndex); - computeParagraphAndIndex(offset, &fromPara, &fromIndex); - if (toPara == -1 || toIndex == -1) { - toPara = fromPara; - toIndex = fromIndex; - } - w->setSelection(fromPara, fromIndex, toPara, toIndex); -} - -void RenderTextArea::setSelectionEnd(long offset) { - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - int fromPara, fromIndex, toPara, toIndex; - w->getSelection(&fromPara, &fromIndex, &toPara, &toIndex); - computeParagraphAndIndex(offset, &toPara, &toIndex); - w->setSelection(fromPara, fromIndex, toPara, toIndex); -} - -void RenderTextArea::setSelectionRange(long start, long end) { - TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); - int fromPara, fromIndex, toPara, toIndex; - computeParagraphAndIndex(start, &fromPara, &fromIndex); - computeParagraphAndIndex(end, &toPara, &toIndex); - w->setSelection(fromPara, fromIndex, toPara, toIndex); -} -// --------------------------------------------------------------------------- - -#include "render_form.moc" diff --git a/khtml/rendering/render_form.h b/khtml/rendering/render_form.h deleted file mode 100644 index db5088d20..000000000 --- a/khtml/rendering/render_form.h +++ /dev/null @@ -1,511 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.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. - * - */ -#ifndef RENDER_FORM_H -#define RENDER_FORM_H - -#include "rendering/render_replaced.h" -#include "rendering/render_image.h" -#include "rendering/render_flow.h" -#include "rendering/render_style.h" -#include "html/html_formimpl.h" - -class TQWidget; -class TQLineEdit; -class QListboxItem; - -#include <ktextedit.h> -#include <kurlrequester.h> -#include <klineedit.h> -#include <tqcheckbox.h> -#include <tqradiobutton.h> -#include <tqpushbutton.h> -#include <tqhbox.h> -#include <klistbox.h> -#include <kcombobox.h> -#include "dom/dom_misc.h" - -class KHTMLPartBrowserExtension; -class KSpell; -class KFindDialog; -class KReplaceDialog; -class KFind; -class KReplace; -class KAction; -class KURLRequester; - -namespace DOM { - class HTMLFormElementImpl; - class HTMLInputElementImpl; - class HTMLSelectElementImpl; - class HTMLGenericFormElementImpl; - class HTMLTextAreaElementImpl; -} - -namespace khtml { - -class DocLoader; - -// ------------------------------------------------------------------------- - -class RenderFormElement : public khtml::RenderWidget -{ -public: - RenderFormElement(DOM::HTMLGenericFormElementImpl* node); - virtual ~RenderFormElement(); - - virtual const char *renderName() const { return "RenderForm"; } - - virtual bool isFormElement() const { return true; } - - // form elements never have padding - virtual int paddingTop() const { return 0; } - virtual int paddingBottom() const { return 0; } - virtual int paddingLeft() const { return 0; } - virtual int paddingRight() const { return 0; } - - virtual void updateFromElement(); - - virtual void layout(); - virtual short baselinePosition( bool ) const; - - DOM::HTMLGenericFormElementImpl *element() const - { return static_cast<DOM::HTMLGenericFormElementImpl*>(RenderObject::element()); } - -protected: - virtual bool isRenderButton() const { return false; } - virtual bool isEditable() const { return false; } - TQ_Alignment textAlignment() const; - - TQPoint m_mousePos; - int m_state; -}; - -// ------------------------------------------------------------------------- - -// generic class for all buttons -class RenderButton : public RenderFormElement -{ - Q_OBJECT -public: - RenderButton(DOM::HTMLGenericFormElementImpl* node); - - virtual const char *renderName() const { return "RenderButton"; } - - virtual short baselinePosition( bool ) const; - - // don't even think about making this method virtual! - DOM::HTMLInputElementImpl* element() const - { return static_cast<DOM::HTMLInputElementImpl*>(RenderObject::element()); } - -protected: - virtual bool isRenderButton() const { return true; } -}; - -// ------------------------------------------------------------------------- - -class RenderCheckBox : public RenderButton -{ - Q_OBJECT -public: - RenderCheckBox(DOM::HTMLInputElementImpl* node); - - virtual const char *renderName() const { return "RenderCheckBox"; } - virtual void updateFromElement(); - virtual void calcMinMaxWidth(); - - virtual bool handleEvent(const DOM::EventImpl&) { return false; } - - TQCheckBox *widget() const { return static_cast<TQCheckBox*>(m_widget); } - -public slots: - virtual void slotStateChanged(int state); -}; - -// ------------------------------------------------------------------------- - -class RenderRadioButton : public RenderButton -{ - Q_OBJECT -public: - RenderRadioButton(DOM::HTMLInputElementImpl* node); - - virtual const char *renderName() const { return "RenderRadioButton"; } - - virtual void calcMinMaxWidth(); - virtual void updateFromElement(); - - virtual bool handleEvent(const DOM::EventImpl&) { return false; } - - TQRadioButton *widget() const { return static_cast<TQRadioButton*>(m_widget); } - -public slots: - virtual void slotToggled(bool); -}; - -// ------------------------------------------------------------------------- - -class RenderSubmitButton : public RenderButton -{ -public: - RenderSubmitButton(DOM::HTMLInputElementImpl *element); - - virtual const char *renderName() const { return "RenderSubmitButton"; } - - virtual void calcMinMaxWidth(); - virtual void updateFromElement(); - virtual short baselinePosition( bool ) const; -private: - TQString rawText(); -}; - -// ------------------------------------------------------------------------- - -class RenderImageButton : public RenderImage -{ -public: - RenderImageButton(DOM::HTMLInputElementImpl *element) - : RenderImage(element) {} - - virtual const char *renderName() const { return "RenderImageButton"; } -}; - - -// ------------------------------------------------------------------------- - -class RenderResetButton : public RenderSubmitButton -{ -public: - RenderResetButton(DOM::HTMLInputElementImpl *element); - - virtual const char *renderName() const { return "RenderResetButton"; } - -}; - -// ------------------------------------------------------------------------- - -class RenderPushButton : public RenderSubmitButton -{ -public: - RenderPushButton(DOM::HTMLInputElementImpl *element) - : RenderSubmitButton(element) {} - -}; - -// ------------------------------------------------------------------------- - -class RenderLineEdit : public RenderFormElement -{ - Q_OBJECT -public: - RenderLineEdit(DOM::HTMLInputElementImpl *element); - - virtual void calcMinMaxWidth(); - - virtual const char *renderName() const { return "RenderLineEdit"; } - virtual void updateFromElement(); - virtual void setStyle(RenderStyle *style); - - void select(); - - KLineEdit *widget() const { return static_cast<KLineEdit*>(m_widget); } - DOM::HTMLInputElementImpl* element() const - { return static_cast<DOM::HTMLInputElementImpl*>(RenderObject::element()); } - void highLightWord( unsigned int length, unsigned int pos ); - - long selectionStart(); - long selectionEnd(); - void setSelectionStart(long pos); - void setSelectionEnd(long pos); - void setSelectionRange(long start, long end); -public slots: - void slotReturnPressed(); - void slotTextChanged(const TQString &string); -protected: - virtual void handleFocusOut(); - -private: - virtual bool isEditable() const { return true; } - virtual bool canHaveBorder() const { return true; } -}; - -// ------------------------------------------------------------------------- - -class LineEditWidget : public KLineEdit -{ - Q_OBJECT -public: - LineEditWidget(DOM::HTMLInputElementImpl* input, - KHTMLView* view, TQWidget* parent); - ~LineEditWidget(); - void highLightWord( unsigned int length, unsigned int pos ); - -protected: - virtual bool event( TQEvent *e ); - virtual void mouseMoveEvent(TQMouseEvent *e); - virtual TQPopupMenu *createPopupMenu(); -private slots: - void extendedMenuActivated( int id); - void slotCheckSpelling(); - void slotSpellCheckReady( KSpell *s ); - void slotSpellCheckDone( const TQString &s ); - void spellCheckerMisspelling( const TQString &text, const TQStringList &, unsigned int pos); - void spellCheckerCorrected( const TQString &, const TQString &, unsigned int ); - void spellCheckerFinished(); - void slotRemoveFromHistory( const TQString & ); - -private: - enum LineEditMenuID { - ClearHistory, - EditHistory - }; - DOM::HTMLInputElementImpl* m_input; - KHTMLView* m_view; - KSpell *m_spell; - KAction *m_spellAction; -}; - -// ------------------------------------------------------------------------- - -class RenderFieldset : public RenderBlock -{ -public: - RenderFieldset(DOM::HTMLGenericFormElementImpl *element); - - virtual const char *renderName() const { return "RenderFieldSet"; } - virtual RenderObject* layoutLegend(bool relayoutChildren); - virtual void setStyle(RenderStyle* _style); - -protected: - virtual void paintBoxDecorations(PaintInfo& pI, int _tx, int _ty); - void paintBorderMinusLegend(TQPainter *p, int _tx, int _ty, int w, - int h, const RenderStyle *style, int lx, int lw); - RenderObject* findLegend(); -}; - -// ------------------------------------------------------------------------- - -class RenderFileButton : public RenderFormElement -{ - Q_OBJECT -public: - RenderFileButton(DOM::HTMLInputElementImpl *element); - - virtual const char *renderName() const { return "RenderFileButton"; } - virtual void calcMinMaxWidth(); - virtual void updateFromElement(); - void select(); - - KURLRequester *widget() const { return static_cast<KURLRequester*>(m_widget); } - - DOM::HTMLInputElementImpl *element() const - { return static_cast<DOM::HTMLInputElementImpl*>(RenderObject::element()); } - -public slots: - void slotReturnPressed(); - void slotTextChanged(const TQString &string); - void slotUrlSelected(const TQString &string); - -protected: - virtual void handleFocusOut(); - - virtual bool isEditable() const { return true; } - virtual bool canHaveBorder() const { return true; } - virtual bool acceptsSyntheticEvents() const { return false; } - - bool m_clicked; - bool m_haveFocus; -}; - - -// ------------------------------------------------------------------------- - -class RenderLabel : public RenderFormElement -{ -public: - RenderLabel(DOM::HTMLGenericFormElementImpl *element); - - virtual const char *renderName() const { return "RenderLabel"; } - -protected: - virtual bool canHaveBorder() const { return true; } -}; - - -// ------------------------------------------------------------------------- - -class RenderLegend : public RenderBlock -{ -public: - RenderLegend(DOM::HTMLGenericFormElementImpl *element); - - virtual const char *renderName() const { return "RenderLegend"; } -}; - -// ------------------------------------------------------------------------- - -class ComboBoxWidget : public KComboBox -{ -public: - ComboBoxWidget(TQWidget *parent); - -protected: - virtual bool event(TQEvent *); - virtual bool eventFilter(TQObject *dest, TQEvent *e); -}; - -// ------------------------------------------------------------------------- - -class RenderSelect : public RenderFormElement -{ - Q_OBJECT -public: - RenderSelect(DOM::HTMLSelectElementImpl *element); - - virtual const char *renderName() const { return "RenderSelect"; } - - virtual void calcMinMaxWidth(); - virtual void layout(); - - void setOptionsChanged(bool _optionsChanged); - - bool selectionChanged() { return m_selectionChanged; } - void setSelectionChanged(bool _selectionChanged) { m_selectionChanged = _selectionChanged; } - virtual void updateFromElement(); - - void updateSelection(); - - DOM::HTMLSelectElementImpl *element() const - { return static_cast<DOM::HTMLSelectElementImpl*>(RenderObject::element()); } - -protected: - KListBox *createListBox(); - ComboBoxWidget *createComboBox(); - - unsigned m_size; - bool m_multiple; - bool m_useListBox; - bool m_selectionChanged; - bool m_ignoreSelectEvents; - bool m_optionsChanged; - -protected slots: - void slotSelected(int index); - void slotSelectionChanged(); -}; - -// ------------------------------------------------------------------------- -class TextAreaWidget : public KTextEdit -{ - Q_OBJECT -public: - TextAreaWidget(int wrap, TQWidget* parent); - virtual ~TextAreaWidget(); - -protected: - virtual bool event (TQEvent *e ); - virtual TQPopupMenu *createPopupMenu(const TQPoint& pos); - virtual TQPopupMenu* createPopupMenu() { return KTextEdit::createPopupMenu(); } -private slots: - void slotFind(); - void slotDoFind(); - void slotFindNext(); - void slotReplace(); - void slotDoReplace(); - void slotReplaceNext(); - void slotReplaceText(const TQString&, int, int, int); - void slotFindHighlight(const TQString&, int, int); -private: - KFindDialog *m_findDlg; - KFind *m_find; - KReplaceDialog *m_repDlg; - KReplace *m_replace; - KAction *m_findAction; - KAction *m_findNextAction; - KAction *m_replaceAction; - int m_findIndex, m_findPara; - int m_repIndex, m_repPara; -}; - - -// ------------------------------------------------------------------------- - -class RenderTextArea : public RenderFormElement -{ - Q_OBJECT -public: - RenderTextArea(DOM::HTMLTextAreaElementImpl *element); - ~RenderTextArea(); - - virtual const char *renderName() const { return "RenderTextArea"; } - virtual void calcMinMaxWidth(); - virtual void layout(); - virtual void setStyle(RenderStyle *style); - - virtual void close ( ); - virtual void updateFromElement(); - - // don't even think about making this method virtual! - TextAreaWidget *widget() const { return static_cast<TextAreaWidget*>(m_widget); } - DOM::HTMLTextAreaElementImpl* element() const - { return static_cast<DOM::HTMLTextAreaElementImpl*>(RenderObject::element()); } - - TQString text(); - void highLightWord( unsigned int length, unsigned int pos ); - - void select(); - - long selectionStart(); - long selectionEnd(); - void setSelectionStart(long pos); - void setSelectionEnd(long pos); - void setSelectionRange(long start, long end); -protected slots: - void slotTextChanged(); - -protected: - virtual void handleFocusOut(); - - virtual bool isEditable() const { return true; } - virtual bool canHaveBorder() const { return true; } - - bool scrollbarsStyled; -private: - //Convert para, index -> offset - long computeCharOffset(int para, int index); - - //Convert offset -> para, index - void computeParagraphAndIndex(long offset, int* para, int* index); - - //Helper for doing the conversion.. - enum Mode { ParaLength, //Returns the length of the entire paragraph - ParaPortionLength, //Return length of paragraph portion set by threshold - ParaPortionOffset }; //Return offset that matches the length threshold. - int queryParagraphInfo(int para, Mode m, int param = -1); -}; - -// ------------------------------------------------------------------------- - -} //namespace - -#endif diff --git a/khtml/rendering/render_frames.cpp b/khtml/rendering/render_frames.cpp deleted file mode 100644 index 2535b534e..000000000 --- a/khtml/rendering/render_frames.cpp +++ /dev/null @@ -1,1025 +0,0 @@ -/** - * 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) - * (C) 2003 Apple Computer, Inc. - * (C) 2005 Niels Leenheer <niels.leenheer@gmail.com> - * - * 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. - * - */ -//#define DEBUG_LAYOUT - -#include "rendering/render_frames.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 "misc/htmltags.h" -#include "khtmlview.h" -#include "khtml_part.h" -#include "misc/knsplugininstaller.h" - -#include <kapplication.h> -#include <kmessagebox.h> -#include <kmimetype.h> -#include <klocale.h> -#include <kdebug.h> -#include <tqtimer.h> -#include <tqpainter.h> -#include <tqcursor.h> - -#include <assert.h> - -using namespace khtml; -using namespace DOM; - -RenderFrameSet::RenderFrameSet( HTMLFrameSetElementImpl *frameSet) - : RenderBox(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_cursor = Qt::ArrowCursor; - - m_hSplit = -1; - m_vSplit = -1; - - m_hSplitVar = 0; - m_vSplitVar = 0; -} - -RenderFrameSet::~RenderFrameSet() -{ - for (int k = 0; k < 2; ++k) { - delete [] m_gridLayout[k]; - delete [] m_gridDelta[k]; - } - delete [] m_hSplitVar; - delete [] m_vSplitVar; -} - -bool RenderFrameSet::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inBox) -{ - RenderBox::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox); - - bool inside = m_resizing || canResize(_x, _y); - - if ( inside && element() && !element()->noResize() && !info.readonly()) { - info.setInnerNode(element()); - info.setInnerNonSharedNode(element()); - } - - return inside || m_clientresizing; -} - -void RenderFrameSet::layout( ) -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - if ( !parent()->isFrameSet() ) { - KHTMLView* view = canvas()->view(); - m_width = view ? view->visibleWidth() : 0; - m_height = view ? view->visibleHeight() : 0; - } - -#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(); - for (int k = 0; k < 2; ++k) { - delete [] m_gridDelta[k]; - m_gridDelta[k] = new int[m_gridLen[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; - } - } - - for (int k = 0; k < 2; ++k) { - int totalRelative = 0; - int totalFixed = 0; - int totalPercent = 0; - int countRelative = 0; - int countFixed = 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 we need to investigate how many columns of each type we have and - // how much space these columns are going to require. - for (int i = 0; i < gridLen; ++i) { - // Count the total length of all of the fixed columns/rows -> totalFixed - // Count the number of columns/rows which are fixed -> countFixed - if (grid[i].isFixed()) { - gridLayout[i] = kMax(grid[i].value(), 0); - totalFixed += gridLayout[i]; - countFixed++; - } - - // Count the total percentage of all of the percentage columns/rows -> totalPercent - // Count the number of columns/rows which are percentages -> countPercent - if (grid[i].isPercent()) { - gridLayout[i] = kMax(grid[i].width(availableLen[k]), 0); - totalPercent += gridLayout[i]; - countPercent++; - } - - // Count the total relative of all the relative columns/rows -> totalRelative - // Count the number of columns/rows which are relative -> countRelative - if (grid[i].isRelative()) { - totalRelative += kMax(grid[i].value(), 1); - countRelative++; - } - } - - // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed - // columns/rows we need to proportionally adjust their size. - if (totalFixed > remainingLen[k]) { - int remainingFixed = remainingLen[k]; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isFixed()) { - gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed; - remainingLen[k] -= gridLayout[i]; - } - } - } else { - remainingLen[k] -= totalFixed; - } - - // Percentage columns/rows are our second priority. Divide the remaining space proportionally - // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative - // to 100%, but to the total percentage. For example, if there are three columns, each of 75%, - // and the available space is 300px, each column will become 100px in width. - if (totalPercent > remainingLen[k]) { - int remainingPercent = remainingLen[k]; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isPercent()) { - gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent; - remainingLen[k] -= gridLayout[i]; - } - } - } else { - remainingLen[k] -= totalPercent; - } - - // Relative columns/rows are our last priority. Divide the remaining space proportionally - // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*. - if (countRelative) { - int lastRelative = 0; - int remainingRelative = remainingLen[k]; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isRelative()) { - gridLayout[i] = (kMax(grid[i].value(), 1) * remainingRelative) / totalRelative; - remainingLen[k] -= gridLayout[i]; - lastRelative = i; - } - } - - // If we could not evently distribute the available space of all of the relative - // columns/rows, the remainder will be added to the last column/row. - // For example: if we have a space of 100px and three columns (*,*,*), the remainder will - // be 1px and will be added to the last column: 33px, 33px, 34px. - if (remainingLen[k]) { - gridLayout[lastRelative] += remainingLen[k]; - remainingLen[k] = 0; - } - } - - // If we still have some left over space we need to divide it over the already existing - // columns/rows - if (remainingLen[k]) { - // Our first priority is to spread if over the percentage columns. The remaining - // space is spread evenly, for example: if we have a space of 100px, the columns - // definition of 25%,25% used to result in two columns of 25px. After this the - // columns will each be 50px in width. - if (countPercent && totalPercent) { - int remainingPercent = remainingLen[k]; - int changePercent = 0; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isPercent()) { - changePercent = (remainingPercent * gridLayout[i]) / totalPercent; - gridLayout[i] += changePercent; - remainingLen[k] -= changePercent; - } - } - } else if (totalFixed) { - // Our last priority is to spread the remaining space over the fixed columns. - // For example if we have 100px of space and two column of each 40px, both - // columns will become exactly 50px. - int remainingFixed = remainingLen[k]; - int changeFixed = 0; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isFixed()) { - changeFixed = (remainingFixed * gridLayout[i]) / totalFixed; - gridLayout[i] += changeFixed; - remainingLen[k] -= changeFixed; - } - } - } - } - - // If we still have some left over space we probably ended up with a remainder of - // a division. We can not spread it evenly anymore. If we have any percentage - // columns/rows simply spread the remainder equally over all available percentage columns, - // regardless of their size. - if (remainingLen[k] && countPercent) { - int remainingPercent = remainingLen[k]; - int changePercent = 0; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isPercent()) { - changePercent = remainingPercent / countPercent; - gridLayout[i] += changePercent; - remainingLen[k] -= changePercent; - } - } - } - - // If we don't have any percentage columns/rows we only have fixed columns. Spread - // the remainder equally over all fixed columns/rows. - else if (remainingLen[k] && countFixed) { - int remainingFixed = remainingLen[k]; - int changeFixed = 0; - - for (int i = 0; i < gridLen; ++i) { - if (grid[i].isFixed()) { - changeFixed = remainingFixed / countFixed; - gridLayout[i] += changeFixed; - remainingLen[k] -= changeFixed; - } - } - } - - // Still some left over... simply add it to the last column, because it is impossible - // spread it evenly or equally. - if (remainingLen[k]) { - gridLayout[gridLen - 1] += remainingLen[k]; - } - - // 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) - { - m_vSplitVar = new bool[element()->totalCols()]; - for(int i = 0; i < element()->totalCols(); i++) m_vSplitVar[i] = true; - } - if(!m_hSplitVar && element()->totalRows() > 1) - { - m_hSplitVar = new bool[element()->totalRows()]; - 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; - - for(r = 0; r < element()->totalRows(); r++) - { - int xPos = 0; - for(c = 0; c < element()->totalCols(); c++) - { - 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 - if ((m_gridLayout[1][c] != child->width()) || (m_gridLayout[0][r] != child->height())) { - child->setWidth( m_gridLayout[1][c] ); - child->setHeight( m_gridLayout[0][r] ); - child->setNeedsLayout(true); - child->layout(); - } - - xPos += m_gridLayout[1][c] + element()->border(); - child = child->nextSibling(); - - if ( !child ) - return; - - } - - yPos += m_gridLayout[0][r] + element()->border(); - } - - // all the remaining frames are hidden to avoid ugly - // spurious unflowed frames - while ( child ) { - child->setWidth( 0 ); - child->setHeight( 0 ); - child->setNeedsLayout(false); - - child = child->nextSibling(); - } -} - -bool RenderFrameSet::userResize( MouseEventImpl *evt ) -{ - if (needsLayout()) return false; - - bool res = false; - int _x = evt->clientX(); - int _y = evt->clientY(); - - if ( !m_resizing && evt->id() == EventImpl::MOUSEMOVE_EVENT || evt->id() == EventImpl::MOUSEDOWN_EVENT ) - { -#ifdef DEBUG_LAYOUT - kdDebug( 6031 ) << "mouseEvent:check" << endl; -#endif - - m_hSplit = -1; - m_vSplit = -1; - //bool resizePossible = true; - - // check if we're over a horizontal or vertical boundary - int pos = m_gridLayout[1][0] + xPos(); - for(int c = 1; c < element()->totalCols(); c++) - { - if(_x >= pos && _x <= pos+element()->border()) - { - if(m_vSplitVar && m_vSplitVar[c-1] == true) m_vSplit = c-1; -#ifdef DEBUG_LAYOUT - kdDebug( 6031 ) << "vsplit!" << endl; -#endif - res = true; - break; - } - pos += m_gridLayout[1][c] + element()->border(); - } - - pos = m_gridLayout[0][0] + yPos(); - for(int r = 1; r < element()->totalRows(); r++) - { - if( _y >= pos && _y <= pos+element()->border()) - { - if(m_hSplitVar && m_hSplitVar[r-1] == true) m_hSplit = r-1; -#ifdef DEBUG_LAYOUT - kdDebug( 6031 ) << "hsplitvar = " << m_hSplitVar << endl; - kdDebug( 6031 ) << "hsplit!" << endl; -#endif - res = true; - break; - } - pos += m_gridLayout[0][r] + element()->border(); - } -#ifdef DEBUG_LAYOUT - kdDebug( 6031 ) << m_hSplit << "/" << m_vSplit << endl; -#endif - } - - - m_cursor = Qt::ArrowCursor; - if(m_hSplit != -1 && m_vSplit != -1) - m_cursor = Qt::SizeAllCursor; - else if( m_vSplit != -1 ) - m_cursor = Qt::SizeHorCursor; - else if( m_hSplit != -1 ) - m_cursor = Qt::SizeVerCursor; - - if(!m_resizing && evt->id() == EventImpl::MOUSEDOWN_EVENT) - { - setResizing(true); - TDEApplication::setOverrideCursor(TQCursor(m_cursor)); - m_vSplitPos = _x; - m_hSplitPos = _y; - m_oldpos = -1; - } - - // ### check the resize is not going out of bounds. - if(m_resizing && evt->id() == EventImpl::MOUSEUP_EVENT) - { - setResizing(false); - TDEApplication::restoreOverrideCursor(); - - if(m_vSplit != -1 ) - { -#ifdef DEBUG_LAYOUT - kdDebug( 6031 ) << "split xpos=" << _x << endl; -#endif - int delta = m_vSplitPos - _x; - m_gridDelta[1][m_vSplit] -= delta; - m_gridDelta[1][m_vSplit+1] += delta; - } - if(m_hSplit != -1 ) - { -#ifdef DEBUG_LAYOUT - kdDebug( 6031 ) << "split ypos=" << _y << endl; -#endif - int delta = m_hSplitPos - _y; - m_gridDelta[0][m_hSplit] -= delta; - m_gridDelta[0][m_hSplit+1] += delta; - } - - // this just schedules the relayout - // important, otherwise the moving indicator is not correctly erased - setNeedsLayout(true); - } - - KHTMLView *view = canvas()->view(); - if ((m_resizing || evt->id() == EventImpl::MOUSEUP_EVENT) && view) { - TQPainter paint( view ); - paint.setPen( Qt::gray ); - paint.setBrush( Qt::gray ); - paint.setRasterOp( TQt::XorROP ); - TQRect r(xPos(), yPos(), width(), height()); - const int rBord = 3; - int sw = element()->border(); - int p = m_resizing ? (m_vSplit > -1 ? _x : _y) : -1; - if (m_vSplit > -1) { - if ( m_oldpos >= 0 ) - paint.drawRect( m_oldpos + sw/2 - rBord , r.y(), - 2*rBord, r.height() ); - if ( p >= 0 ) - paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() ); - } else { - if ( m_oldpos >= 0 ) - paint.drawRect( r.x(), m_oldpos + sw/2 - rBord, - r.width(), 2*rBord ); - if ( p >= 0 ) - paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord ); - } - m_oldpos = p; - } - - return res; -} - -void RenderFrameSet::setResizing(bool e) -{ - m_resizing = e; - for (RenderObject* p = parent(); p; p = p->parent()) - if (p->isFrameSet()) static_cast<RenderFrameSet*>(p)->m_clientresizing = m_resizing; -} - -bool RenderFrameSet::canResize( int _x, int _y ) -{ - // if we haven't received a layout, then the gridLayout doesn't contain useful data yet - if (needsLayout() || !m_gridLayout[0] || !m_gridLayout[1] ) return false; - - // check if we're over a horizontal or vertical boundary - int pos = m_gridLayout[1][0]; - for(int c = 1; c < element()->totalCols(); c++) - if(_x >= pos && _x <= pos+element()->border()) - return true; - - pos = m_gridLayout[0][0]; - for(int r = 1; r < element()->totalRows(); r++) - if( _y >= pos && _y <= pos+element()->border()) - return true; - - return false; -} - -#ifdef ENABLE_DUMP -void RenderFrameSet::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderBox::dump(stream,ind); - stream << " totalrows=" << element()->totalRows(); - stream << " totalcols=" << element()->totalCols(); - - if ( m_hSplitVar ) - for (uint i = 0; i < (uint)element()->totalRows(); i++) { - stream << " hSplitvar(" << i << ")=" << m_hSplitVar[i]; - } - - if ( m_vSplitVar ) - for (uint i = 0; i < (uint)element()->totalCols(); i++) - stream << " vSplitvar(" << i << ")=" << m_vSplitVar[i]; -} -#endif - -/**************************************************************************************/ - -RenderPart::RenderPart(DOM::HTMLElementImpl* node) - : RenderWidget(node) -{ - // init RenderObject attributes - setInline(false); -} - -void RenderPart::setWidget( TQWidget *widget ) -{ -#ifdef DEBUG_LAYOUT - kdDebug(6031) << "RenderPart::setWidget()" << endl; -#endif - - setQWidget( widget ); - widget->setFocusPolicy(TQ_WheelFocus); - if(widget->inherits("KHTMLView")) - connect( widget, TQT_SIGNAL( cleared() ), this, TQT_SLOT( slotViewCleared() ) ); - - setNeedsLayoutAndMinMaxRecalc(); - - // make sure the scrollbars are set correctly for restore - // ### find better fix - slotViewCleared(); -} - -bool RenderPart::partLoadingErrorNotify(khtml::ChildFrame *, const KURL& , const TQString& ) -{ - return false; -} - -short RenderPart::intrinsicWidth() const -{ - return 300; -} - -int RenderPart::intrinsicHeight() const -{ - return 150; -} - -void RenderPart::slotViewCleared() -{ -} - -/***************************************************************************************/ - -RenderFrame::RenderFrame( DOM::HTMLFrameElementImpl *frame ) - : RenderPart(frame) -{ - setInline( false ); -} - -void RenderFrame::slotViewCleared() -{ - if(m_widget->inherits(TQSCROLLVIEW_OBJECT_NAME_STRING)) { -#ifdef DEBUG_LAYOUT - kdDebug(6031) << "frame is a scrollview!" << endl; -#endif - TQScrollView *view = static_cast<TQScrollView *>(m_widget); - if(!element()->frameBorder || !((static_cast<HTMLFrameSetElementImpl *>(element()->parentNode()))->frameBorder())) - view->setFrameStyle(TQFrame::NoFrame); - view->setVScrollBarMode(element()->scrolling ); - view->setHScrollBarMode(element()->scrolling ); - if(view->inherits("KHTMLView")) { -#ifdef DEBUG_LAYOUT - kdDebug(6031) << "frame is a KHTMLview!" << endl; -#endif - KHTMLView *htmlView = static_cast<KHTMLView *>(view); - if(element()->marginWidth != -1) htmlView->setMarginWidth(element()->marginWidth); - if(element()->marginHeight != -1) htmlView->setMarginHeight(element()->marginHeight); - } - } -} - -/****************************************************************************************/ - -RenderPartObject::RenderPartObject( DOM::HTMLElementImpl* element ) - : RenderPart( element ) -{ - // init RenderObject attributes - setInline(true); -} - -void RenderPartObject::updateWidget() -{ - TQString url; - KHTMLPart *part = m_view->part(); - - setNeedsLayoutAndMinMaxRecalc(); - - if (element()->id() == ID_IFRAME) { - - HTMLIFrameElementImpl *o = static_cast<HTMLIFrameElementImpl *>(element()); - url = o->url.string(); - if (!o->getDocument()->isURLAllowed(url)) return; - part->requestFrame( this, url, o->name.string(), TQStringList(), true ); - // ### this should be constant true - move iframe to somewhere else - } else { - - TQStringList params; - HTMLObjectBaseElementImpl * objbase = static_cast<HTMLObjectBaseElementImpl *>(element()); - url = objbase->url; - - for (NodeImpl* child = element()->firstChild(); child; child=child->nextSibling()) { - if ( child->id() == ID_PARAM ) { - HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>( child ); - - TQString aStr = p->name(); - aStr += TQString::fromLatin1("=\""); - aStr += p->value(); - aStr += TQString::fromLatin1("\""); - TQString name_lower = p->name().lower(); - if (name_lower == TQString::fromLatin1("type") && objbase->id() != ID_APPLET) { - objbase->setServiceType(p->value()); - } else if (url.isEmpty() && - (name_lower == TQString::fromLatin1("src") || - name_lower == TQString::fromLatin1("movie") || - name_lower == TQString::fromLatin1("code"))) { - url = p->value(); - } - params.append(aStr); - } - } - if (element()->id() != ID_OBJECT) { - // add all attributes set on the embed object - NamedAttrMapImpl* a = objbase->attributes(); - if (a) { - for (unsigned long i = 0; i < a->length(); ++i) { - NodeImpl::Id id = a->idAt(i); - DOMString value = a->valueAt(i); - params.append(objbase->getDocument()->getName(NodeImpl::AttributeId, id).string() + "=\"" + value.string() + "\""); - } - } - } - params.append( TQString::fromLatin1("__KHTML__PLUGINEMBED=\"YES\"") ); - params.append( TQString::fromLatin1("__KHTML__PLUGINBASEURL=\"%1\"").arg(element()->getDocument()->baseURL().url())); - - HTMLEmbedElementImpl *embed = 0; - TQString classId; - TQString serviceType = objbase->serviceType; - if ( element()->id() == ID_EMBED ) { - - embed = static_cast<HTMLEmbedElementImpl *>( objbase ); - - } - else { // if(element()->id() == ID_OBJECT || element()->id() == ID_APPLET) - - // check for embed child object - for (NodeImpl *child = objbase->firstChild(); child; child = child->nextSibling()) - if ( child->id() == ID_EMBED ) { - embed = static_cast<HTMLEmbedElementImpl *>( child ); - break; - } - classId = objbase->classId; - - params.append( TQString::fromLatin1("__KHTML__CLASSID=\"%1\"").arg( classId ) ); - params.append( TQString::fromLatin1("__KHTML__CODEBASE=\"%1\"").arg( objbase->getAttribute(ATTR_CODEBASE).string() ) ); - if (!objbase->getAttribute(ATTR_WIDTH).isEmpty()) - params.append( TQString::fromLatin1("WIDTH=\"%1\"").arg( objbase->getAttribute(ATTR_WIDTH).string() ) ); - else if (embed && !embed->getAttribute(ATTR_WIDTH).isEmpty()) { - params.append( TQString::fromLatin1("WIDTH=\"%1\"").arg( embed->getAttribute(ATTR_WIDTH).string() ) ); - objbase->setAttribute(ATTR_WIDTH, embed->getAttribute(ATTR_WIDTH)); - } - if (!objbase->getAttribute(ATTR_HEIGHT).isEmpty()) - params.append( TQString::fromLatin1("HEIGHT=\"%1\"").arg( objbase->getAttribute(ATTR_HEIGHT).string() ) ); - else if (embed && !embed->getAttribute(ATTR_HEIGHT).isEmpty()) { - params.append( TQString::fromLatin1("HEIGHT=\"%1\"").arg( embed->getAttribute(ATTR_HEIGHT).string() ) ); - objbase->setAttribute(ATTR_HEIGHT, embed->getAttribute(ATTR_HEIGHT)); - } - - if ( embed ) { - // render embed object - url = embed->url; - if (!embed->serviceType.isEmpty()) - serviceType = embed->serviceType; - } else if (url.isEmpty() && objbase->classId.startsWith("java:")) { - serviceType = "application/x-java-applet"; - url = objbase->classId.mid(5); - } - if ( (serviceType.isEmpty() || - serviceType == "application/x-oleobject") && - !objbase->classId.isEmpty()) - { -#if 0 - // We have a clsid, means this is activex (Niko) - serviceType = "application/x-activex-handler"; -#endif - - if(classId.find(TQString::fromLatin1("D27CDB6E-AE6D-11cf-96B8-444553540000")) >= 0) { - // It is ActiveX, but the nsplugin system handling - // should also work, that's why we don't override the - // serviceType with application/x-activex-handler - // but let the KTrader in khtmlpart::createPart() detect - // the user's preference: launch with activex viewer or - // with nspluginviewer (Niko) - serviceType = "application/x-shockwave-flash"; - } - else if(classId.find(TQString::fromLatin1("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) >= 0) - serviceType = "audio/x-pn-realaudio-plugin"; - else if(classId.find(TQString::fromLatin1("8AD9C840-044E-11D1-B3E9-00805F499D93")) >= 0 || - objbase->classId.find(TQString::fromLatin1("CAFEEFAC-0014-0000-0000-ABCDEFFEDCBA")) >= 0) - serviceType = "application/x-java-applet"; - // http://www.apple.com/quicktime/tools_tips/tutorials/activex.html - else if(classId.find(TQString::fromLatin1("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) >= 0) - serviceType = "video/quicktime"; - // http://msdn.microsoft.com/library/en-us/dnwmt/html/adding_windows_media_to_web_pages__etse.asp?frame=true - else if(objbase->classId.find(TQString::fromLatin1("6BF52A52-394A-11d3-B153-00C04F79FAA6")) >= 0 || - classId.find(TQString::fromLatin1("22D6f312-B0F6-11D0-94AB-0080C74C7E95")) >= 0) - serviceType = "video/x-msvideo"; - - else - kdDebug(6031) << "ActiveX classId " << objbase->classId << endl; - - // TODO: add more plugins here - } - } - if ((url.isEmpty() && !embed && - (serviceType.isEmpty() || classId.isEmpty())) || - !document()->isURLAllowed(url) || - !part->requestObject( this, url, serviceType, params )) - objbase->renderAlternative(); - } -} - -// ugly.. -void RenderPartObject::close() -{ - RenderPart::close(); - - if ( element()->id() != ID_IFRAME ) - updateWidget(); - // deleted here -} - - -bool RenderPartObject::partLoadingErrorNotify( khtml::ChildFrame *childFrame, const KURL& url, const TQString& serviceType ) -{ - KHTMLPart *part = static_cast<KHTMLView *>(m_view)->part(); - kdDebug(6031) << "RenderPartObject::partLoadingErrorNotify serviceType=" << serviceType << endl; - // Check if we just tried with e.g. nsplugin - // and fallback to the activexhandler if there is a classid - // and a codebase, where we may download the ocx if it's missing - if( serviceType != "application/x-activex-handler" && element()->id()==ID_OBJECT ) { - - // check for embed child object - HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element()); - HTMLEmbedElementImpl *embed = 0; - NodeImpl *child = o->firstChild(); - while ( child ) { - if ( child->id() == ID_EMBED ) - embed = static_cast<HTMLEmbedElementImpl *>( child ); - - child = child->nextSibling(); - } - if( embed && !o->classId.isEmpty() && - !( static_cast<ElementImpl *>(o)->getAttribute(ATTR_CODEBASE).string() ).isEmpty() ) - { - KParts::URLArgs args; - args.serviceType = "application/x-activex-handler"; - kdDebug(6031) << "set to activex" << endl; - if (part->requestObject( childFrame, url, args )) - return true; // success - - return false; - } - } - // Dissociate ourselves from the current event loop (to prevent crashes - // due to the message box staying up) - TQTimer::singleShot( 0, this, TQT_SLOT( slotPartLoadingErrorNotify() ) ); -#if 0 - Tokenizer *tokenizer = static_cast<DOM::DocumentImpl *>(part->document().handle())->tokenizer(); - if (tokenizer) tokenizer->setOnHold( true ); - slotPartLoadingErrorNotify(); - if (tokenizer) tokenizer->setOnHold( false ); -#endif - return false; -} - -void RenderPartObject::slotPartLoadingErrorNotify() -{ - // First we need to find out the servicetype - again - this code is too duplicated ! - HTMLEmbedElementImpl *embed = 0; - TQString serviceType; - if( element()->id()==ID_OBJECT ) { - - // check for embed child object - HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element()); - serviceType = o->serviceType; - NodeImpl *child = o->firstChild(); - while ( child ) { - if ( child->id() == ID_EMBED ) - embed = static_cast<HTMLEmbedElementImpl *>( child ); - - child = child->nextSibling(); - } - - } else if( element()->id()==ID_EMBED ) { - embed = static_cast<HTMLEmbedElementImpl *>(element()); - } - if ( embed ) - serviceType = embed->serviceType; - - // prepare for the local eventloop in KMessageBox - ref(); - - KHTMLPart *part = static_cast<KHTMLView *>(m_view)->part(); - KParts::BrowserExtension *ext = part->browserExtension(); - if( embed && !embed->pluginPage.isEmpty() && ext ) { - // Prepare the mimetype to show in the question (comment if available, name as fallback) - TQString mimeName = serviceType; - KMimeType::Ptr mime = KMimeType::mimeType(serviceType); - if ( mime->name() != KMimeType::defaultMimeType() ) - mimeName = mime->comment(); - - // Check if we already asked the user, for this page - if (!mimeName.isEmpty() && part->docImpl() && !part->pluginPageQuestionAsked( serviceType ) ) - { - part->setPluginPageQuestionAsked( serviceType ); - bool pluginAvailable; - pluginAvailable = false; - // check if a pluginList file is in the config - if(KNSPluginInstallEngine::isActive()) - { - KNSPluginWizard pluginWizard(m_view, "pluginInstaller", mime); - if(pluginWizard.pluginAvailable()) { - pluginAvailable = true; - pluginWizard.exec(); - } - } - if(!pluginAvailable) { - // Prepare the URL to show in the question (host only if http, to make it short) - KURL pluginPageURL( embed->pluginPage ); - TQString shortURL = pluginPageURL.protocol() == "http" ? pluginPageURL.host() : pluginPageURL.prettyURL(); - int res = KMessageBox::questionYesNo( m_view, - i18n("No plugin found for '%1'.\nDo you want to download one from %2?").arg(mimeName).arg(shortURL), - i18n("Missing Plugin"), i18n("Download"), i18n("Do Not Download"), TQString("plugin-")+serviceType); - if ( res == KMessageBox::Yes ) - { - // Display vendor download page - ext->createNewWindow( pluginPageURL ); - return; - } - } - } - } - - // didn't work, render alternative content. - if ( element() && ( - element()->id() == ID_OBJECT || element()->id() == ID_EMBED || element()->id() == ID_APPLET)) - static_cast<HTMLObjectBaseElementImpl*>( element() )->renderAlternative(); - - deref(); -} - -void RenderPartObject::layout( ) -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - calcWidth(); - calcHeight(); - - RenderPart::layout(); - - setNeedsLayout(false); -} - -void RenderPartObject::slotViewCleared() -{ - if(m_widget->inherits(TQSCROLLVIEW_OBJECT_NAME_STRING) ) { -#ifdef DEBUG_LAYOUT - kdDebug(6031) << "iframe is a scrollview!" << endl; -#endif - TQScrollView *view = static_cast<TQScrollView *>(m_widget); - int frameStyle = TQFrame::NoFrame; - TQScrollView::ScrollBarMode scroll = TQScrollView::Auto; - int marginw = -1; - int marginh = -1; - if ( element()->id() == ID_IFRAME) { - HTMLIFrameElementImpl *frame = static_cast<HTMLIFrameElementImpl *>(element()); - if(frame->frameBorder) - frameStyle = TQFrame::Box; - scroll = frame->scrolling; - marginw = frame->marginWidth; - marginh = frame->marginHeight; - } - view->setFrameStyle(frameStyle); - view->setVScrollBarMode(scroll ); - view->setHScrollBarMode(scroll ); - if(view->inherits("KHTMLView")) { -#ifdef DEBUG_LAYOUT - kdDebug(6031) << "frame is a KHTMLview!" << endl; -#endif - KHTMLView *htmlView = static_cast<KHTMLView *>(view); - htmlView->setIgnoreWheelEvents( element()->id() == ID_IFRAME ); - if(marginw != -1) htmlView->setMarginWidth(marginw); - if(marginh != -1) htmlView->setMarginHeight(marginh); - } - } -} - - -#include "render_frames.moc" diff --git a/khtml/rendering/render_frames.h b/khtml/rendering/render_frames.h deleted file mode 100644 index 3dd7ed0d9..000000000 --- a/khtml/rendering/render_frames.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 2000 Simon Hausmann <hausmann@kde.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. - * - */ -#ifndef __render_frames_h__ -#define __render_frames_h__ - -#include "rendering/render_replaced.h" -#include "xml/dom_nodeimpl.h" -#include "html/html_baseimpl.h" -class KHTMLView; - -namespace DOM -{ - class HTMLFrameElementImpl; - class HTMLElementImpl; - class MouseEventImpl; -} - -namespace khtml -{ - class ChildFrame; - -class RenderFrameSet : public RenderBox -{ - friend class DOM::HTMLFrameSetElementImpl; -public: - RenderFrameSet( DOM::HTMLFrameSetElementImpl *frameSet ); - - virtual ~RenderFrameSet(); - - virtual const char *renderName() const { return "RenderFrameSet"; } - virtual bool isFrameSet() const { return true; } - - virtual void layout(); - - void positionFrames( ); - - bool resizing() const { return m_resizing; } - bool noResize() const { return element()->noResize(); } - - bool userResize( DOM::MouseEventImpl *evt ); - bool canResize( int _x, int _y); - void setResizing(bool e); - - Qt::CursorShape cursorShape() const { return m_cursor; } - - bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction hitTestAction, bool inside); - - DOM::HTMLFrameSetElementImpl *element() const - { return static_cast<DOM::HTMLFrameSetElementImpl*>(RenderObject::element()); } - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - -private: - Qt::CursorShape m_cursor; - int m_oldpos; - int m_gridLen[2]; - int* m_gridDelta[2]; - int* m_gridLayout[2]; - - bool *m_hSplitVar; // is this split variable? - bool *m_vSplitVar; - - int m_hSplit; // the split currently resized - int m_vSplit; - int m_hSplitPos; - int m_vSplitPos; - - bool m_resizing; - bool m_clientresizing; -}; - -class RenderPart : public khtml::RenderWidget -{ - Q_OBJECT -public: - RenderPart(DOM::HTMLElementImpl* node); - - virtual const char *renderName() const { return "RenderPart"; } - - virtual void setWidget( TQWidget *widget ); - - /** - * Called by KHTMLPart to notify the frame object that loading the - * part was not successfuly. (called either asyncroniously after a - * after the servicetype of the given url (the one passed with requestObject) - * has been determined or syncroniously from within requestObject) - * - * The default implementation does nothing. - * - * Return false in the normal case, return true if a fallback was found - * and the url was successfully opened. - */ - virtual bool partLoadingErrorNotify( khtml::ChildFrame *childFrame, const KURL& url, const TQString& serviceType ); - - virtual short intrinsicWidth() const; - virtual int intrinsicHeight() const; - -public slots: - virtual void slotViewCleared(); -}; - -class RenderFrame : public khtml::RenderPart -{ - Q_OBJECT -public: - RenderFrame( DOM::HTMLFrameElementImpl *frame ); - - virtual const char *renderName() const { return "RenderFrame"; } - virtual bool isFrame() const { return true; } - - // frames never have padding - virtual int paddingTop() const { return 0; } - virtual int paddingBottom() const { return 0; } - virtual int paddingLeft() const { return 0; } - virtual int paddingRight() const { return 0; } - - DOM::HTMLFrameElementImpl *element() const - { return static_cast<DOM::HTMLFrameElementImpl*>(RenderObject::element()); } - -public slots: - void slotViewCleared(); -}; - -// I can hardly call the class RenderObject ;-) -class RenderPartObject : public khtml::RenderPart -{ - Q_OBJECT -public: - RenderPartObject( DOM::HTMLElementImpl * ); - - virtual const char *renderName() const { return "RenderPartObject"; } - - virtual void close(); - - virtual void layout( ); - virtual void updateWidget(); - - virtual bool canHaveBorder() const { return true; } - - virtual bool partLoadingErrorNotify( khtml::ChildFrame *childFrame, const KURL& url, const TQString& serviceType ); - -public slots: - void slotViewCleared(); -private slots: - void slotPartLoadingErrorNotify(); -}; - -} - -#endif diff --git a/khtml/rendering/render_generated.cpp b/khtml/rendering/render_generated.cpp deleted file mode 100644 index 17c65fc9c..000000000 --- a/khtml/rendering/render_generated.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/** - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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 "rendering/render_generated.h" -#include "rendering/render_style.h" -#include "rendering/enumerate.h" -#include "rendering/counter_tree.h" -#include "css/css_valueimpl.h" - -using namespace khtml; -using namespace Enumerate; - -// ------------------------------------------------------------------------- - -RenderCounterBase::RenderCounterBase(DOM::NodeImpl* node) - : RenderText(node,0), m_counterNode(0) -{ -} - -void RenderCounterBase::layout() -{ - KHTMLAssert( needsLayout() ); - - if ( !minMaxKnown() ) - calcMinMaxWidth(); - - RenderText::layout(); -} - -void RenderCounterBase::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - generateContent(); - - if (str) str->deref(); - str = new DOM::DOMStringImpl(m_item.unicode(), m_item.length()); - str->ref(); - - RenderText::calcMinMaxWidth(); -} - - -void RenderCounterBase::updateContent() -{ - setMinMaxKnown(false); -} - -// ------------------------------------------------------------------------- - -RenderCounter::RenderCounter(DOM::NodeImpl* node, const DOM::CounterImpl* counter) - : RenderCounterBase(node), m_counter(counter) -{ -} - -TQString RenderCounter::toListStyleType(int value, int total, EListStyleType type) -{ - TQString item; - switch(type) - { - case LNONE: - break; -// Glyphs: (these values are not really used and instead handled by RenderGlyph) - case LDISC: - item = TQChar(0x2022); - break; - case LCIRCLE: - item = TQChar(0x25e6); - break; - case LSQUARE: - item = TQChar(0x25a0); - break; - case LBOX: - item = TQChar(0x25a1); - break; - case LDIAMOND: - item = TQChar(0x25c6); - break; -// Numeric: - case LDECIMAL: - item.setNum ( value ); - break; - case DECIMAL_LEADING_ZERO: { - int decimals = 2; - int t = total/100; - while (t>0) { - t = t/10; - decimals++; - } - decimals = kMax(decimals, 2); - TQString num = TQString::number(value); - item.fill('0',decimals-num.length()); - item.append(num); - break; - } - case ARABIC_INDIC: - item = toArabicIndic( value ); - break; - case LAO: - item = toLao( value ); - break; - case PERSIAN: - case URDU: - item = toPersianUrdu( value ); - break; - case THAI: - item = toThai( value ); - break; - case TIBETAN: - item = toTibetan( value ); - break; -// Algoritmic: - case LOWER_ROMAN: - item = toRoman( value, false ); - break; - case UPPER_ROMAN: - item = toRoman( value, true ); - break; - case HEBREW: - item = toHebrew( value ); - break; - case ARMENIAN: - item = toArmenian( value ); - break; - case GEORGIAN: - item = toGeorgian( value ); - break; -// Alphabetic: - case LOWER_ALPHA: - case LOWER_LATIN: - item = toLowerLatin( value ); - break; - case UPPER_ALPHA: - case UPPER_LATIN: - item = toUpperLatin( value ); - break; - case LOWER_GREEK: - item = toLowerGreek( value ); - break; - case UPPER_GREEK: - item = toUpperGreek( value ); - break; - case HIRAGANA: - item = toHiragana( value ); - break; - case HIRAGANA_IROHA: - item = toHiraganaIroha( value ); - break; - case KATAKANA: - item = toKatakana( value ); - break; - case KATAKANA_IROHA: - item = toKatakanaIroha( value ); - break; -// Ideographic: - case JAPANESE_FORMAL: - item = toJapaneseFormal( value ); - break; - case JAPANESE_INFORMAL: - item = toJapaneseInformal( value ); - break; - case SIMP_CHINESE_FORMAL: - item = toSimpChineseFormal( value ); - break; - case SIMP_CHINESE_INFORMAL: - item = toSimpChineseInformal( value ); - break; - case TRAD_CHINESE_FORMAL: - item = toTradChineseFormal( value ); - break; - case CJK_IDEOGRAPHIC: - // CSS 3 List says treat as trad-chinese-informal - case TRAD_CHINESE_INFORMAL: - item = toTradChineseInformal( value ); - break; - default: - item.setNum ( value ); - break; - } - return item; -} - -void RenderCounter::generateContent() -{ - bool counters; - counters = !m_counter->separator().isNull(); - - if (!m_counterNode) - m_counterNode = getCounter(m_counter->identifier().string(), true, counters); - - int value = m_counterNode->count(); - if (m_counterNode->isReset()) value = m_counterNode->value(); - int total = value; - if (m_counterNode->parent()) total = m_counterNode->parent()->total(); - m_item = toListStyleType(value, total, (EListStyleType)m_counter->listStyle()); - - if (counters) { - CounterNode *counter = m_counterNode->parent(); - // we deliberately do not render the root counter-node - while(counter->parent() && !(counter->isReset() && counter->parent()->isRoot())) { - value = counter->count(); - total = counter->parent()->total(); - m_item = toListStyleType(value, total, (EListStyleType)m_counter->listStyle()) + m_counter->separator().string() + m_item; - counter = counter->parent(); - }; - } - -} - -// ------------------------------------------------------------------------- - -RenderQuote::RenderQuote(DOM::NodeImpl* node, EQuoteContent type) - : RenderCounterBase(node), m_quoteType(type) -{ -} - - -int RenderQuote::quoteCount() const -{ - switch(m_quoteType) { - case OPEN_QUOTE: - case NO_OPEN_QUOTE: - return 1; - case CLOSE_QUOTE: - case NO_CLOSE_QUOTE: - return -1; - case NO_QUOTE: - return 0; - } - assert(false); - return 0; -} - -void RenderQuote::generateContent() -{ - bool visual; - if (m_quoteType == NO_CLOSE_QUOTE || m_quoteType == NO_OPEN_QUOTE) - visual = false; - else - visual = true; - - if (!m_counterNode) - m_counterNode = getCounter("-khtml-quotes", visual, false); - - int value = m_counterNode->count(); - if (m_counterNode->isReset()) value = m_counterNode->value(); - switch (m_quoteType) { - case OPEN_QUOTE: - m_item = style()->openQuote( value ); - break; - case CLOSE_QUOTE: - m_item = style()->closeQuote( value ); - break; - case NO_OPEN_QUOTE: - case NO_CLOSE_QUOTE: - case NO_QUOTE: - m_item = TQString(); - } -} - -// ------------------------------------------------------------------------- - -RenderGlyph::RenderGlyph(DOM::NodeImpl* node, EListStyleType type) - : RenderBox(node), m_type(type) -{ - setInline(true); -// setReplaced(true); -} - -void RenderGlyph::setStyle(RenderStyle *_style) -{ - RenderBox::setStyle(_style); - - const TQFontMetrics &fm = style()->fontMetrics(); - TQRect xSize= fm.boundingRect('x'); - m_height = xSize.height(); - m_width = xSize.width();; - - switch(m_type) { - // Glyphs: - case LDISC: - case LCIRCLE: - case LSQUARE: - case LBOX: - case LDIAMOND: - case LNONE: - break; - default: - // not a glyph ! - assert(false); - break; - } -} - -void RenderGlyph::calcMinMaxWidth() -{ - m_minWidth = m_width; - m_maxWidth = m_width; - - setMinMaxKnown(); -} - -short RenderGlyph::lineHeight(bool /*b*/) const -{ - return height(); -} - -short RenderGlyph::baselinePosition(bool /*b*/) const -{ - return height(); -} - -void RenderGlyph::paint(PaintInfo& paintInfo, int _tx, int _ty) -{ - if (paintInfo.phase != PaintActionForeground) - return; - - if (style()->visibility() != VISIBLE) return; - - _tx += m_x; - _ty += m_y; - - if((_ty > paintInfo.r.bottom()) || (_ty + m_height <= paintInfo.r.top())) - return; - - TQPainter* p = paintInfo.p; - - const TQColor color( style()->color() ); - p->setPen( color ); - - int xHeight = m_height; - int bulletWidth = (xHeight+1)/2; - int yoff = (xHeight - 1)/4; - TQRect marker(_tx, _ty + yoff, bulletWidth, bulletWidth); - - switch(m_type) { - case LDISC: - p->setBrush( color ); - p->drawEllipse( marker ); - return; - case LCIRCLE: - p->setBrush( Qt::NoBrush ); - p->drawEllipse( marker ); - return; - case LSQUARE: - p->setBrush( color ); - p->drawRect( marker ); - return; - case LBOX: - p->setBrush( Qt::NoBrush ); - p->drawRect( marker ); - return; - case LDIAMOND: { - static TQPointArray diamond(4); - int x = marker.x(); - int y = marker.y(); - int s = bulletWidth/2; - diamond[0] = TQPoint(x+s, y); - diamond[1] = TQPoint(x+2*s, y+s); - diamond[2] = TQPoint(x+s, y+2*s); - diamond[3] = TQPoint(x, y+s); - p->setBrush( color ); - p->drawConvexPolygon( diamond, 0, 4 ); - return; - } - case LNONE: - return; - default: - // not a glyph - assert(false); - } -} - diff --git a/khtml/rendering/render_generated.h b/khtml/rendering/render_generated.h deleted file mode 100644 index 6fa20e7cd..000000000 --- a/khtml/rendering/render_generated.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2004,2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ -#ifndef RENDER_GENERATED_H -#define RENDER_GENERATED_H - -#include "rendering/render_text.h" -#include "rendering/render_box.h" - -namespace DOM { - class CounterImpl; -} - -namespace khtml { - class CounterNode; - -// ----------------------------------------------------------------------------- - -class RenderCounterBase : public RenderText -{ -public: - RenderCounterBase(DOM::NodeImpl* node); - - virtual const char *renderName() const { return "RenderCounterBase"; } - - virtual void layout( ); - virtual void calcMinMaxWidth(); - virtual bool isCounter() const { return true; } - - virtual void generateContent() = 0; - void updateContent(); - -protected: - TQString m_item; - CounterNode *m_counterNode; // Cache of the counternode -}; - -// ----------------------------------------------------------------------------- - -class RenderCounter : public RenderCounterBase -{ -public: - RenderCounter(DOM::NodeImpl* node, const DOM::CounterImpl* counter); - virtual ~RenderCounter() {}; - - virtual const char *renderName() const { return "RenderCounter"; } - - virtual void generateContent(); - -protected: - TQString toListStyleType(int value, int total, EListStyleType type); - - const DOM::CounterImpl* m_counter; -}; - -// ----------------------------------------------------------------------------- - -class RenderQuote : public RenderCounterBase -{ -public: - RenderQuote(DOM::NodeImpl* node, EQuoteContent type); - virtual ~RenderQuote() {}; - - virtual const char *renderName() const { return "RenderQuote"; } - - virtual bool isQuote() const { return true; } - virtual int quoteCount() const; - - virtual void generateContent(); - -protected: - EQuoteContent m_quoteType; -}; - -// ----------------------------------------------------------------------------- - -// Is actually a special case of renderCounter for non-counted list-styles -// These have traditionally been drawn rather than use Unicode characters -class RenderGlyph : public RenderBox -{ -public: - RenderGlyph(DOM::NodeImpl* node, EListStyleType type); - virtual ~RenderGlyph() {}; - - virtual const char *renderName() const { return "RenderGlyph"; } - - virtual void paint(PaintInfo& paintInfo, int _tx, int _ty); - virtual void calcMinMaxWidth(); - - virtual void setStyle(RenderStyle *_style); - - virtual short lineHeight( bool firstLine ) const; - virtual short baselinePosition( bool firstLine ) const; - - virtual bool isGlyph() const { return true; } - - virtual void position(InlineBox* box, int /*from*/, int /*len*/, bool /*reverse*/) { - setPos( box->xPos(), box->yPos() ); - } - -protected: - EListStyleType m_type; -}; - -} //namespace - -#endif diff --git a/khtml/rendering/render_image.cpp b/khtml/rendering/render_image.cpp deleted file mode 100644 index f931e9ca5..000000000 --- a/khtml/rendering/render_image.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/** - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -//#define DEBUG_LAYOUT - -#include "render_image.h" -#include "render_canvas.h" - -#include <tqdrawutil.h> -#include <tqpainter.h> - -#include <kapplication.h> -#include <kdebug.h> -#include <kglobalsettings.h> - -#include "css/csshelper.h" -#include "misc/helper.h" -#include "misc/htmlattrs.h" -#include "misc/loader.h" -#include "misc/htmltags.h" -#include "html/html_formimpl.h" -#include "html/html_imageimpl.h" -#include "html/dtd.h" -#include "xml/dom2_eventsimpl.h" -#include "html/html_documentimpl.h" -#include "html/html_objectimpl.h" -#include "khtmlview.h" -#include "khtml_part.h" -#include <math.h> - -#include "loading_icon.cpp" - -using namespace DOM; -using namespace khtml; - -// ------------------------------------------------------------------------- - -RenderImage::RenderImage(NodeImpl *_element) - : RenderReplaced(_element) -{ - m_oldImage = m_cachedImage = 0; - - m_selectionState = SelectionNone; - berrorPic = false; - - const KHTMLSettings *settings = _element->getDocument()->view()->part()->settings(); - bUnfinishedImageFrame = settings->unfinishedImageFrame(); - - setIntrinsicWidth( 0 ); - setIntrinsicHeight( 0 ); -} - -RenderImage::~RenderImage() -{ - if(m_cachedImage) m_cachedImage->deref( this ); - if(m_oldImage) m_oldImage->deref( this ); -} - -TQPixmap RenderImage::pixmap() const -{ - return m_cachedImage ? m_cachedImage->pixmap() : TQPixmap(); -} - -void RenderImage::setStyle(RenderStyle* _style) -{ - RenderReplaced::setStyle(_style); - // init RenderObject attributes - //setOverhangingContents(style()->height().isPercent()); - setShouldPaintBackgroundOrBorder(true); -} - -void RenderImage::setContentObject(CachedObject* co ) -{ - if (co && m_cachedImage != co) - updateImage( static_cast<CachedImage*>( co ) ); -} - -void RenderImage::setPixmap( const TQPixmap &p, const TQRect& r, CachedImage *o) -{ - if ( o == m_oldImage ) - return; - - if(o != m_cachedImage) { - RenderReplaced::setPixmap(p, r, o); - return; - } - - bool iwchanged = false; - - if(o->isErrorImage()) { - int iw = p.width() + 8; - int ih = p.height() + 8; - - // we have an alt and the user meant it (its not a text we invented) - if ( element() && !alt.isEmpty() && !element()->getAttribute( ATTR_ALT ).isNull()) { - const TQFontMetrics &fm = style()->fontMetrics(); - TQRect br = fm.boundingRect ( 0, 0, 1024, 256, TQt::AlignAuto|TQt::WordBreak, alt.string() ); - if ( br.width() > iw ) - iw = br.width(); - if ( br.height() > ih ) - ih = br.height(); - } - - if ( iw != intrinsicWidth() ) { - setIntrinsicWidth( iw ); - iwchanged = true; - } - if ( ih != intrinsicHeight() ) { - setIntrinsicHeight( ih ); - iwchanged = true; - } - if ( element() && element()->id() == ID_OBJECT ) { - static_cast<HTMLObjectElementImpl*>( element() )->renderAlternative(); - return; - } - } - berrorPic = o->isErrorImage(); - - bool needlayout = false; - - // Image dimensions have been changed, see what needs to be done - if( o->pixmap_size().width() != intrinsicWidth() || - o->pixmap_size().height() != intrinsicHeight() || iwchanged ) - { -// tqDebug("image dimensions have been changed, old: %d/%d new: %d/%d", -// intrinsicWidth(), intrinsicHeight(), -// o->pixmap_size().width(), o->pixmap_size().height()); - - if(!o->isErrorImage()) { - setIntrinsicWidth( o->pixmap_size().width() ); - setIntrinsicHeight( o->pixmap_size().height() ); - } - - // lets see if we need to relayout at all.. - int oldwidth = m_width; - int oldheight = m_height; - int oldminwidth = m_minWidth; - m_minWidth = 0; - - if ( parent() ) { - calcWidth(); - calcHeight(); - } - - if(iwchanged || m_width != oldwidth || m_height != oldheight) - needlayout = true; - - m_minWidth = oldminwidth; - m_width = oldwidth; - m_height = oldheight; - } - - // we're not fully integrated in the tree yet.. we'll come back. - if ( !parent() ) - return; - - if(needlayout) - { - if (!selfNeedsLayout()) - setNeedsLayout(true); - if (minMaxKnown()) - setMinMaxKnown(false); - } - else - { - bool completeRepaint = !resizeCache.isNull(); - int cHeight = contentHeight(); - int scaledHeight = intrinsicHeight() ? ((o->valid_rect().height()*cHeight)/intrinsicHeight()) : 0; - - // don't bog down X server doing xforms - if(completeRepaint && cHeight >= 5 && o->valid_rect().height() < intrinsicHeight() && - (scaledHeight / (cHeight/5) == resizeCache.height() / (cHeight/5))) - return; - - resizeCache = TQPixmap(); // for resized animations - - if(completeRepaint) - repaintRectangle(borderLeft()+paddingLeft(), borderTop()+paddingTop(), contentWidth(), contentHeight()); - else - { - repaintRectangle(r.x() + borderLeft() + paddingLeft(), r.y() + borderTop() + paddingTop(), - r.width(), r.height()); - } - } -} - -void RenderImage::paint(PaintInfo& paintInfo, int _tx, int _ty) -{ - if (paintInfo.phase == PaintActionOutline && style()->outlineWidth() && style()->visibility() == VISIBLE) - paintOutline(paintInfo.p, _tx + m_x, _ty + m_y, width(), height(), style()); - - if (paintInfo.phase != PaintActionForeground && paintInfo.phase != PaintActionSelection) - return; - - // not visible or not even once layouted? - if (style()->visibility() != VISIBLE || m_y <= -500000) return; - - _tx += m_x; - _ty += m_y; - - if((_ty > paintInfo.r.bottom()) || (_ty + m_height <= paintInfo.r.top())) return; - - if(shouldPaintBackgroundOrBorder()) - paintBoxDecorations(paintInfo, _tx, _ty); - - int cWidth = contentWidth(); - int cHeight = contentHeight(); - int leftBorder = borderLeft(); - int topBorder = borderTop(); - int leftPad = paddingLeft(); - int topPad = paddingTop(); - - if (!canvas()->printImages()) - return; - - CachedImage* i = m_oldImage && m_oldImage->valid_rect().size() == m_oldImage->pixmap_size() && - m_oldImage->pixmap_size().width() == intrinsicWidth() && - m_oldImage->pixmap_size().height() == intrinsicHeight() - ? m_oldImage : m_cachedImage; - - // paint frame around image as long as it is not completely loaded from web. - if (bUnfinishedImageFrame && paintInfo.phase == PaintActionForeground && cWidth > 2 && cHeight > 2 && !complete()) { - static TQPixmap *loadingIcon; - TQColor bg = khtml::retrieveBackgroundColor(this); - TQColor fg = khtml::hasSufficientContrast(Qt::gray, bg) ? Qt::gray : - (hasSufficientContrast(Qt::white, bg) ? Qt::white : Qt::black); - paintInfo.p->setPen(TQPen(fg, 1)); - paintInfo.p->setBrush( Qt::NoBrush ); - paintInfo.p->drawRect(_tx, _ty, m_width, m_height); - if (!(m_width <= 5 || m_height <= 5)) { - if (!loadingIcon) { - loadingIcon = new TQPixmap(); - loadingIcon->loadFromData(loading_icon_data, loading_icon_len); - } - paintInfo.p->drawPixmap(_tx + 4, _ty + 4, *loadingIcon, 0, 0, m_width - 5, m_height - 5); - } - - } - - //kdDebug( 6040 ) << " contents (" << contentWidth << "/" << contentHeight << ") border=" << borderLeft() << " padding=" << paddingLeft() << endl; - if ( !i || berrorPic) - { - if(cWidth > 2 && cHeight > 2) - { - if ( !berrorPic ) { - //tqDebug("qDrawShadePanel %d/%d/%d/%d", _tx + leftBorder, _ty + topBorder, cWidth, cHeight); - qDrawShadePanel( paintInfo.p, _tx + leftBorder + leftPad, _ty + topBorder + topPad, cWidth, cHeight, - TDEApplication::palette().inactive(), true, 1 ); - } - TQPixmap const* pix = i ? &i->pixmap() : 0; - if(berrorPic && pix && (cWidth >= pix->width()+4) && (cHeight >= pix->height()+4) ) - { - TQRect r(pix->rect()); - r = r.intersect(TQRect(0, 0, cWidth-4, cHeight-4)); - paintInfo.p->drawPixmap( TQPoint( _tx + leftBorder + leftPad+2, _ty + topBorder + topPad+2), *pix, r ); - } - if(!alt.isEmpty()) { - TQString text = alt.string(); - paintInfo.p->setFont(style()->font()); - paintInfo.p->setPen( style()->color() ); - int ax = _tx + leftBorder + leftPad + 2; - int ay = _ty + topBorder + topPad + 2; - const TQFontMetrics &fm = style()->fontMetrics(); - if (cWidth>5 && cHeight>=fm.height()) - paintInfo.p->drawText(ax, ay+1, cWidth - 4, cHeight - 4, TQt::WordBreak, text ); - } - } - } - else if (i && !i->isTransparent()) - { - paintInfo.p->setPen( Qt::black ); // used for bitmaps - const TQPixmap& pix = i->pixmap(); - if ( (cWidth != intrinsicWidth() || cHeight != intrinsicHeight()) && - pix.width() > 0 && pix.height() > 0 && i->valid_rect().isValid()) - { - if (resizeCache.isNull() && cWidth && cHeight && intrinsicWidth() && intrinsicHeight()) - { - TQRect scaledrect(i->valid_rect()); -// kdDebug(6040) << "time elapsed: " << dt->elapsed() << endl; -// kdDebug( 6040 ) << "have to scale: " << endl; -// tqDebug("cw=%d ch=%d pw=%d ph=%d rcw=%d, rch=%d", -// cWidth, cHeight, intrinsicWidth(), intrinsicHeight(), resizeCache.width(), resizeCache.height()); - TQWMatrix matrix; - matrix.scale( (float)(cWidth)/intrinsicWidth(), - (float)(cHeight)/intrinsicHeight() ); - resizeCache = pix.xForm( matrix ); - scaledrect.setWidth( ( cWidth*scaledrect.width() ) / intrinsicWidth() ); - scaledrect.setHeight( ( cHeight*scaledrect.height() ) / intrinsicHeight() ); -// tqDebug("resizeCache size: %d/%d", resizeCache.width(), resizeCache.height()); -// tqDebug("valid: %d/%d, scaled: %d/%d", -// i->valid_rect().width(), i->valid_rect().height(), -// scaledrect.width(), scaledrect.height()); - - // sometimes scaledrect.width/height are off by one because - // of rounding errors. if the i is fully loaded, we - // make sure that we don't do unnecessary resizes during painting - TQSize s(scaledrect.size()); - if(i->valid_rect().size() == TQSize( intrinsicWidth(), intrinsicHeight() )) // fully loaded - s = TQSize(cWidth, cHeight); - if(kAbs(s.width() - cWidth) < 2) // rounding errors - s.setWidth(cWidth); - if(resizeCache.size() != s) - resizeCache.resize(s); - - paintInfo.p->drawPixmap( TQPoint( _tx + leftBorder + leftPad, _ty + topBorder + topPad), - resizeCache, scaledrect ); - } - else - paintInfo.p->drawPixmap( TQPoint( _tx + leftBorder + leftPad, _ty + topBorder + topPad), resizeCache ); - } - else - { - // we might be just about switching images - TQRect rect(i->valid_rect().isValid() ? i->valid_rect() - : TQRect(0, 0, intrinsicWidth(), intrinsicHeight())); - - TQPoint offs( _tx + leftBorder + leftPad, _ty + topBorder + topPad); -// tqDebug("normal paint rect %d/%d/%d/%d", rect.x(), rect.y(), rect.width(), rect.height()); -// rect = rect & TQRect( 0 , y - offs.y() - 10, w, 10 + y + h - offs.y()); - -// tqDebug("normal paint rect after %d/%d/%d/%d", rect.x(), rect.y(), rect.width(), rect.height()); -// tqDebug("normal paint: offs.y(): %d, y: %d, diff: %d", offs.y(), y, y - offs.y()); -// tqDebug(""); - -// p->setClipRect(TQRect(x,y,w,h)); - - -// p->drawPixmap( offs.x(), y, pix, rect.x(), rect.y(), rect.width(), rect.height() ); - paintInfo.p->drawPixmap(offs, pix, rect); - - } - } - if (m_selectionState != SelectionNone) { -// kdDebug(6040) << "_tx " << _tx << " _ty " << _ty << " _x " << _x << " _y " << _y << endl; - // Draw in any case if inside selection. For selection borders, the - // offset will decide whether to draw selection or not - bool draw = true; - if (m_selectionState != SelectionInside) { - int startPos, endPos; - selectionStartEnd(startPos, endPos); - if(selectionState() == SelectionStart) - endPos = 1; - else if(selectionState() == SelectionEnd) - startPos = 0; - draw = endPos - startPos > 0; - } - if (draw) { - // setting the brush origin is important for compatibility, - // don't touch it unless you know what you're doing - paintInfo.p->setBrushOrigin(_tx, _ty - paintInfo.r.y()); - paintInfo.p->fillRect(_tx, _ty, width(), height(), - TQBrush(style()->palette().active().highlight(), - Qt::Dense4Pattern)); - } - } -} - -void RenderImage::layout() -{ - KHTMLAssert( needsLayout()); - KHTMLAssert( minMaxKnown() ); - - short oldwidth = m_width; - int oldheight = m_height; - - // minimum height - m_height = m_cachedImage && m_cachedImage->isErrorImage() ? intrinsicHeight() : 0; - - calcWidth(); - calcHeight(); - - // if they are variable width and we calculate a huge height or width, we assume they - // actually wanted the intrinsic width. - if ( m_width > 4096 && !style()->width().isFixed() ) - m_width = intrinsicWidth() + paddingLeft() + paddingRight() + borderLeft() + borderRight(); - if ( m_height > 2048 && !style()->height().isFixed() ) - m_height = intrinsicHeight() + paddingTop() + paddingBottom() + borderTop() + borderBottom(); - - // limit total size to not run out of memory when doing the xform call. - if ( ( m_width * m_height > 4096*2048 ) && - ( contentWidth() > intrinsicWidth() || contentHeight() > intrinsicHeight() ) ) { - float scale = sqrt( m_width*m_height / ( 4096.*2048. ) ); - m_width = (int) (m_width/scale); - m_height = (int) (m_height/scale); - } - - if ( m_width != oldwidth || m_height != oldheight ) - resizeCache = TQPixmap(); - - setNeedsLayout(false); -} - -void RenderImage::notifyFinished(CachedObject *finishedObj) -{ - if ( ( m_cachedImage == finishedObj || m_oldImage == finishedObj ) && m_oldImage ) { - m_oldImage->deref( this ); - m_oldImage = 0; - repaint(); - } - - RenderReplaced::notifyFinished(finishedObj); -} - -bool RenderImage::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside) -{ - inside |= RenderReplaced::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside); - - if (inside && element()) { - int tx = _tx + m_x; - int ty = _ty + m_y; - if (isRelPositioned()) - relativePositionOffset(tx, ty); - - HTMLImageElementImpl* i = element()->id() == ID_IMG ? static_cast<HTMLImageElementImpl*>(element()) : 0; - HTMLMapElementImpl* map; - if (i && i->getDocument()->isHTMLDocument() && - (map = static_cast<HTMLDocumentImpl*>(i->getDocument())->getMap(i->imageMap()))) { - // we're a client side image map - inside = map->mapMouseEvent(_x - tx, _y - ty, contentWidth(), contentHeight(), info); - info.setInnerNonSharedNode(element()); - } - } - - return inside; -} - -void RenderImage::updateImage(CachedImage* new_image) -{ - CachedImage* tempimage = m_oldImage; - m_oldImage = m_cachedImage; - m_cachedImage = new_image; - assert( m_cachedImage != m_oldImage ); - - if ( m_cachedImage ) - m_cachedImage->ref(this); - - if ( tempimage ) - tempimage->deref(this); - - // if the loading finishes we might get an error and then the image is deleted - if ( m_cachedImage ) - berrorPic = m_cachedImage->isErrorImage(); - else - berrorPic = true; -} - -void RenderImage::updateFromElement() -{ - if (element()->id() == ID_INPUT) - alt = static_cast<HTMLInputElementImpl*>(element())->altText(); - else if (element()->id() == ID_IMG) - alt = static_cast<HTMLImageElementImpl*>(element())->altText(); - - DOMString u = element()->id() == ID_OBJECT ? - element()->getAttribute(ATTR_DATA) : element()->getAttribute(ATTR_SRC); - - if (!u.isEmpty() && - ( !m_cachedImage || m_cachedImage->url() != u ) ) { - CachedImage *new_image = element()->getDocument()->docLoader()-> - requestImage(khtml::parseURL(u)); - - if(new_image && new_image != m_cachedImage) - updateImage( new_image ); - } -} - -bool RenderImage::complete() const -{ - // "complete" means that the image has been loaded - // but also that its width/height (contentWidth(),contentHeight()) have been calculated. - return m_cachedImage && m_cachedImage->valid_rect().size() == m_cachedImage->pixmap_size() && !needsLayout(); -} - -bool RenderImage::isWidthSpecified() const -{ - switch (style()->width().type()) { - case Fixed: - case Percent: - return true; - default: - return false; - } - assert(false); - return false; -} - -bool RenderImage::isHeightSpecified() const -{ - switch (style()->height().type()) { - case Fixed: - case Percent: - return true; - default: - return false; - } - assert(false); - return false; -} - -short RenderImage::calcAspectRatioWidth() const -{ - if (intrinsicHeight() == 0) - return 0; - if (!m_cachedImage || m_cachedImage->isErrorImage()) - return intrinsicWidth(); // Don't bother scaling. - return RenderReplaced::calcReplacedHeight() * intrinsicWidth() / intrinsicHeight(); -} - -int RenderImage::calcAspectRatioHeight() const -{ - if (intrinsicWidth() == 0) - return 0; - if (!m_cachedImage || m_cachedImage->isErrorImage()) - return intrinsicHeight(); // Don't bother scaling. - return RenderReplaced::calcReplacedWidth() * intrinsicHeight() / intrinsicWidth(); -} - -short RenderImage::calcReplacedWidth() const -{ - int width; - if (isWidthSpecified()) - width = calcReplacedWidthUsing(Width); - else - width = calcAspectRatioWidth(); - int minW = calcReplacedWidthUsing(MinWidth); - int maxW = style()->maxWidth().value() == UNDEFINED ? width : calcReplacedWidthUsing(MaxWidth); - - if (width > maxW) - width = maxW; - - if (width < minW) - width = minW; - - return width; -} - -int RenderImage::calcReplacedHeight() const -{ - int height; - if (isHeightSpecified()) - height = calcReplacedHeightUsing(Height); - else - height = calcAspectRatioHeight(); - - int minH = calcReplacedHeightUsing(MinHeight); - int maxH = style()->maxHeight().value() == UNDEFINED ? height : calcReplacedHeightUsing(MaxHeight); - - if (height > maxH) - height = maxH; - - if (height < minH) - height = minH; - - return height; -} - -#if 0 -void RenderImage::caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) -{ - RenderReplaced::caretPos(offset, flags, _x, _y, width, height); - -#if 0 // doesn't work reliably - height = intrinsicHeight(); - width = override && offset == 0 ? intrinsicWidth() : 0; - _x = xPos(); - _y = yPos(); - if (offset > 0) _x += intrinsicWidth(); - - RenderObject *cb = containingBlock(); - - int absx, absy; - if (cb && cb != this && cb->absolutePosition(absx,absy)) - { - _x += absx; - _y += absy; - } else { - // we don't know our absolute position, and there is no point returning - // just a relative one - _x = _y = -1; - } -#endif -} -#endif diff --git a/khtml/rendering/render_image.h b/khtml/rendering/render_image.h deleted file mode 100644 index 8c8bb9bef..000000000 --- a/khtml/rendering/render_image.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.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. - * - */ -#ifndef RENDER_IMAGE_H -#define RENDER_IMAGE_H - -#include "html/dtd.h" -#include "html/html_elementimpl.h" -#include "rendering/render_replaced.h" -#include "dom/dom_string.h" - -#include <tqmap.h> -#include <tqpixmap.h> - -namespace khtml { - -class DocLoader; -class CachedObject; - -class RenderImage : public RenderReplaced -{ -public: - RenderImage(DOM::NodeImpl* _element); - virtual ~RenderImage(); - - virtual const char *renderName() const { return "RenderImage"; } - virtual void paint( PaintInfo& i, int tx, int ty ); - - virtual void layout(); - - virtual void setPixmap( const TQPixmap &, const TQRect&, CachedImage *); - - // don't even think about making these methods virtual! - TQPixmap pixmap() const; - DOM::HTMLElementImpl* element() const - { return static_cast<DOM::HTMLElementImpl*>(RenderObject::element()); } - - bool complete() const; - - CachedObject *contentObject() { return m_cachedImage; } - void setContentObject( CachedObject* ); - - // hook to keep RendeObject::m_inline() up to date - virtual void setStyle(RenderStyle *style); - virtual void updateFromElement(); - - virtual void notifyFinished(CachedObject *finishedObj); - virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction hitTestAction, bool inside); - - bool isWidthSpecified() const; - bool isHeightSpecified() const; - - short calcAspectRatioWidth() const; - int calcAspectRatioHeight() const; - - virtual short calcReplacedWidth() const; - virtual int calcReplacedHeight() const; - - virtual SelectionState selectionState() const {return m_selectionState;} - virtual void setSelectionState(SelectionState s) {m_selectionState = s; } -#if 0 - virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height); -#endif - -private: - void updateImage(CachedImage* new_image); - /* - * Cache for images that need resizing - */ - TQPixmap resizeCache; - - // text to display as long as the image isn't available - DOM::DOMString alt; - - CachedImage *m_cachedImage; - CachedImage *m_oldImage; - - bool berrorPic : 1; - bool bUnfinishedImageFrame :1; - SelectionState m_selectionState : 3; // FIXME: don't forget to enlarge this as the enum grows -}; - - -} //namespace - -#endif diff --git a/khtml/rendering/render_inline.cpp b/khtml/rendering/render_inline.cpp deleted file mode 100644 index c3eb08d4b..000000000 --- a/khtml/rendering/render_inline.cpp +++ /dev/null @@ -1,935 +0,0 @@ -/* - * This file is part of the render object implementation for KHTML. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include <kglobal.h> - -#include "rendering/render_arena.h" -#include "rendering/render_inline.h" -#include "rendering/render_block.h" -#include "xml/dom_docimpl.h" - -#include <tqvaluevector.h> - -using namespace khtml; - -void RenderInline::setStyle(RenderStyle* _style) -{ - RenderFlow::setStyle(_style); - setInline(true); - - // Ensure that all of the split inlines pick up the new style. We - // only do this if we're an inline, since we don't want to propagate - // a block's style to the other inlines. - // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before - // and after the block share the same style, but the block doesn't - // need to pass its style on to anyone else. - RenderFlow* currCont = continuation(); - while (currCont) { - if (currCont->isInline()) { - RenderFlow* nextCont = currCont->continuation(); - currCont->setContinuation(0); - currCont->setStyle(style()); - currCont->setContinuation(nextCont); - } - currCont = currCont->continuation(); - } - - if (attached()) { - // Update replaced content - updateReplacedContent(); - // Update pseudos for ::before and ::after - updatePseudoChildren(); - } -} - -// Attach handles initial setStyle that requires parent nodes -void RenderInline::attach() -{ - RenderFlow::attach(); - - updateReplacedContent(); - updatePseudoChildren(); -} - -bool RenderInline::isInlineContinuation() const -{ - return m_isContinuation; -} - -void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) -{ - // Make sure we don't append things after :after-generated content if we have it. - if (!beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER) - beforeChild = lastChild(); - - if (!newChild->isText() && newChild->style()->position() != STATIC) - setOverhangingContents(); - - if (!newChild->isInline() && !newChild->isFloatingOrPositioned() ) - { - // We are placing a block inside an inline. We have to perform a split of this - // inline into continuations. This involves creating an anonymous block box to hold - // |newChild|. We then make that block box a continuation of this inline. We take all of - // the children after |beforeChild| and put them in a clone of this object. - - RenderBlock *newBox = createAnonymousBlock(); - RenderFlow* oldContinuation = continuation(); - setContinuation(newBox); - - splitFlow(beforeChild, newBox, newChild, oldContinuation); - return; - } - - RenderBox::addChild(newChild,beforeChild); - - newChild->setNeedsLayoutAndMinMaxRecalc(); -} - -RenderInline* RenderInline::cloneInline(RenderFlow* src) -{ - RenderInline *o = new (src->renderArena()) RenderInline(src->element()); - o->m_isContinuation = true; - o->setStyle(src->style()); - return o; -} - -void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, - RenderBlock* middleBlock, - RenderObject* beforeChild, RenderFlow* oldCont) -{ - // Create a clone of this inline. - RenderInline* clone = cloneInline(this); - clone->setContinuation(oldCont); - - // Now take all of the children from beforeChild to the end and remove - // then from |this| and place them in the clone. - RenderObject* o = beforeChild; - while (o) { - RenderObject* tmp = o; - o = tmp->nextSibling(); - clone->addChildToFlow(removeChildNode(tmp), 0); - tmp->setNeedsLayoutAndMinMaxRecalc(); - } - - // Hook |clone| up as the continuation of the middle block. - middleBlock->setContinuation(clone); - - // We have been reparented and are now under the fromBlock. We need - // to walk up our inline parent chain until we hit the containing block. - // Once we hit the containing block we're done. - RenderFlow* curr = static_cast<RenderFlow*>(parent()); - RenderFlow* currChild = this; - while (curr && curr != fromBlock) { - // Create a new clone. - RenderInline* cloneChild = clone; - clone = cloneInline(curr); - - // Insert our child clone as the first child. - clone->addChildToFlow(cloneChild, 0); - - // Hook the clone up as a continuation of |curr|. - RenderFlow* oldCont = curr->continuation(); - curr->setContinuation(clone); - clone->setContinuation(oldCont); - - // Now we need to take all of the children starting from the first child - // *after* currChild and append them all to the clone. - o = currChild->nextSibling(); - while (o) { - RenderObject* tmp = o; - o = tmp->nextSibling(); - clone->appendChildNode(curr->removeChildNode(tmp)); - tmp->setNeedsLayoutAndMinMaxRecalc(); - } - - // Keep walking up the chain. - currChild = curr; - curr = static_cast<RenderFlow*>(curr->parent()); - } - - // Now we are at the block level. We need to put the clone into the toBlock. - toBlock->appendChildNode(clone); - - // Now take all the children after currChild and remove them from the fromBlock - // and put them in the toBlock. - o = currChild->nextSibling(); - while (o) { - RenderObject* tmp = o; - o = tmp->nextSibling(); - toBlock->appendChildNode(fromBlock->removeChildNode(tmp)); - } -} - -void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, - RenderObject* newChild, RenderFlow* oldCont) -{ - RenderBlock* pre = 0; - RenderBlock* block = containingBlock(); - bool madeNewBeforeBlock = false; - if (block->isAnonymousBlock()) { - // We can reuse this block and make it the preBlock of the next continuation. - pre = block; - block = block->containingBlock(); - } - else { - // No anonymous block available for use. Make one. - pre = block->createAnonymousBlock(); - madeNewBeforeBlock = true; - } - - RenderBlock* post = block->createAnonymousBlock(); - - RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); - if (madeNewBeforeBlock) - block->insertChildNode(pre, boxFirst); - block->insertChildNode(newBlockBox, boxFirst); - block->insertChildNode(post, boxFirst); - block->setChildrenInline(false); - - if (madeNewBeforeBlock) { - RenderObject* o = boxFirst; - while (o) - { - RenderObject* no = o; - o = no->nextSibling(); - pre->appendChildNode(block->removeChildNode(no)); - no->setNeedsLayoutAndMinMaxRecalc(); - } - } - - splitInlines(pre, post, newBlockBox, beforeChild, oldCont); - - // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting - // time in makeChildrenNonInline by just setting this explicitly up front. - newBlockBox->setChildrenInline(false); - - // We don't just call addChild, since it would pass things off to the - // continuation, so we call addChildToFlow explicitly instead. We delayed - // adding the newChild until now so that the |newBlockBox| would be fully - // connected, thus allowing newChild access to a renderArena should it need - // to wrap itself in additional boxes (e.g., table construction). - newBlockBox->addChildToFlow(newChild, 0); - - // XXXdwh is any of this even necessary? I don't think it is. - pre->close(); - pre->setPos(0, -500000); - pre->setNeedsLayout(true); - newBlockBox->close(); - newBlockBox->setPos(0, -500000); - newBlockBox->setNeedsLayout(true); - post->close(); - post->setPos(0, -500000); - post->setNeedsLayout(true); - - updatePseudoChildren(); - - block->setNeedsLayoutAndMinMaxRecalc(); -} - -void RenderInline::paint(PaintInfo& i, int _tx, int _ty) -{ - paintLines(i, _tx, _ty); -} - -/** - * Appends the given coordinate-pair to the point-array if it is not - * equal to the last element. - * @param pointArray point-array - * @param pnt point to append - * @return \c true if \c pnt has actually been appended - */ -inline static bool appendIfNew(TQValueVector<TQPoint> &pointArray, const TQPoint &pnt) -{ -// if (!pointArray.isEmpty()) kdDebug(6040) << "appifnew: " << pointArray.back() << " == " << pnt << ": " << (pointArray.back() == pnt) << endl; -// else kdDebug(6040) << "appifnew: " << pnt << " (unconditional)" << endl; - if (!pointArray.isEmpty() && pointArray.back() == pnt) return false; - pointArray.append(pnt); - return true; -} - -/** - * Does spike-reduction on the given point-array's stack-top. - * - * Spikes are path segments of which one goes forward, and the sucessor - * goes backward on the predecessor's segment: - * - * 2 0 1 - * x------x<-----x - * (0 is stack-top in point-array) - * - * This will be reduced to - * 1 0 - * x------x - * - * Preconditions: - * - No other spikes exist in the whole point-array except at most - * one at the end - * - No two succeeding points are ever equal - * - For each two succeeding points either p1.x == p2.x or p1.y == p2.y holds - * true - * - No such spike exists where 2 is situated between 0 and 1. - * - * Postcondition: - * - No spikes exist in the whole point-array - * - * If no spike is found, the point-array is left unchanged. - * @return \c true if an actual reduction was done - */ -inline static bool reduceSpike(TQValueVector<TQPoint> &pointArray) -{ - if (pointArray.size() < 3) return false; - TQValueVector<TQPoint>::Iterator it = pointArray.end(); - TQPoint p0 = *--it; - TQPoint p1 = *--it; - TQPoint p2 = *--it; - - bool elide = false; - - if (p0.x() == p1.x() && p1.x() == p2.x() - && (p1.y() < p0.y() && p0.y() < p2.y() - || p2.y() < p0.y() && p0.y() < p1.y() - || p1.y() < p2.y() && p2.y() < p0.y() - || p0.y() < p2.y() && p2.y() < p1.y() - || (elide = p2.y() == p0.y() && p0.y() < p1.y()) - || (elide = p1.y() < p0.y() && p0.y() == p2.y())) - || p0.y() == p1.y() && p1.y() == p2.y() - && (p1.x() < p0.x() && p0.x() < p2.x() - || p2.x() < p0.x() && p0.x() < p1.x() - || p1.x() < p2.x() && p2.x() < p0.x() - || p0.x() < p2.x() && p2.x() < p1.x() - || (elide = p2.x() == p0.x() && p0.x() < p1.x()) - || (elide = p1.x() < p0.x() && p0.x() == p2.x()))) - { -// kdDebug(6040) << "spikered p2" << (elide ? " (elide)" : "") << ": " << p2 << " p1: " << p1 << " p0: " << p0 << endl; - pointArray.pop_back(); pointArray.pop_back(); - if (!elide) - pointArray.push_back(p0); - return true; - } - return false; -} - -/** - * Reduces segment separators. - * - * A segment separator separates a segment into two segments, thus causing - * two adjacent segment with the same orientation. - * - * 2 1 0 - * x-------x---->x - * (0 means stack-top) - * - * Here, 1 is a segment separator. As segment separators not only make - * the line drawing algorithm inefficient, but also make the spike-reduction - * fail, they must be eliminated: - * - * 1 0 - * x------------>x - * - * Preconditions: - * - No other segment separators exist in the whole point-array except - * at most one at the end - * - No two succeeding points are ever equal - * - For each two succeeding points either p1.x == p2.x or p1.y == p2.y holds - * true - * - No such spike exists where 2 is situated between 0 and 1. - * - * Postcondition: - * - No segment separators exist in the whole point-array - * - * If no segment separator is found at the end of the point-array, it is - * left unchanged. - * @return \c true if a segment separator was actually reduced. - */ -inline static bool reduceSegmentSeparator(TQValueVector<TQPoint> &pointArray) -{ - if (pointArray.size() < 3) return false; - TQValueVector<TQPoint>::Iterator it = pointArray.end(); - TQPoint p0 = *--it; - TQPoint p1 = *--it; - TQPoint p2 = *--it; -// kdDebug(6040) << "checking p2: " << p2 << " p1: " << p1 << " p0: " << p0 << endl; - - if (p0.x() == p1.x() && p1.x() == p2.x() - && (p2.y() < p1.y() && p1.y() < p0.y() - || p0.y() < p1.y() && p1.y() < p2.y()) - || p0.y() == p1.y() && p1.y() == p2.y() - && (p2.x() < p1.x() && p1.x() < p0.x() - || p0.x() < p1.x() && p1.x() < p2.x())) - { -// kdDebug(6040) << "segred p2: " << p2 << " p1: " << p1 << " p0: " << p0 << endl; - pointArray.pop_back(); pointArray.pop_back(); - pointArray.push_back(p0); - return true; - } - return false; -} - -/** - * Appends the given point to the point-array, doing necessary reductions to - * produce a path without spikes and segment separators. - */ -static void appendPoint(TQValueVector<TQPoint> &pointArray, TQPoint &pnt) -{ - if (!appendIfNew(pointArray, pnt)) return; -// kdDebug(6040) << "appendPoint: appended " << pnt << endl; - reduceSegmentSeparator(pointArray) - || reduceSpike(pointArray); -} - -/** - * Traverses the horizontal inline boxes and appends the point coordinates to - * the given array. - * @param box inline box - * @param pointArray array collecting coordinates - * @param bottom \c true, collect bottom coordinates, \c false, collect top - * coordinates. - * @param limit lower limit that an y-coordinate must at least reach. Note - * that limit designates the highest y-coordinate for \c bottom, and - * the lowest for !\c bottom. - */ -static void collectHorizontalBoxCoordinates(InlineBox *box, - TQValueVector<TQPoint> &pointArray, - bool bottom, int offset, int limit = -500000) -{ -// kdDebug(6000) << "collectHorizontalBoxCoordinates: " << endl; - offset = bottom ? offset:-offset; - int y = box->yPos() + bottom*box->height() + offset; - if (limit != -500000 && (bottom ? y < limit : y > limit)) - y = limit; - int x = box->xPos() + bottom*box->width() + offset; - TQPoint newPnt(x, y); - // Add intersection point if point-array not empty. - if (!pointArray.isEmpty()) { - TQPoint lastPnt = pointArray.back(); - TQPoint insPnt(newPnt.x(), lastPnt.y()); - if (offset && ((bottom && lastPnt.y() > y) || (!bottom && lastPnt.y() < y))) { - insPnt.rx() = lastPnt.x(); - insPnt.ry() = y; - } -// kdDebug(6040) << "left: " << lastPnt << " == " << insPnt << ": " << (insPnt == lastPnt) << endl; - appendPoint(pointArray, insPnt); - } - // Insert starting point of box - appendPoint(pointArray, newPnt); - - newPnt.rx() += (bottom ? -box->width() : box->width()) - 2*offset; - - if (box->isInlineFlowBox()) { - InlineFlowBox *flowBox = static_cast<InlineFlowBox *>(box); - for (InlineBox *b = bottom ? flowBox->lastChild() : flowBox->firstChild(); b; b = bottom ? b->prevOnLine() : b->nextOnLine()) { - // Don't let boxes smaller than this flow box' height influence - // the vertical position of the outline if they have a different - // x-coordinate - int l2; - if (b->xPos() != box->xPos() && b->xPos() + b->width() != box->xPos() + box->width()) - l2 = y; - else - l2 = limit; - collectHorizontalBoxCoordinates(b, pointArray, bottom, kAbs(offset), l2); - } - - // Add intersection point if flow box contained any children - if (flowBox->firstChild()) { - TQPoint lastPnt = pointArray.back(); - TQPoint insPnt(lastPnt.x(), newPnt.y()); -// kdDebug(6040) << "right: " << lastPnt << " == " << insPnt << ": " << (insPnt == lastPnt) << endl; - appendPoint(pointArray, insPnt); - } - } - - // Insert ending point of box - appendPoint(pointArray, newPnt); - -// kdDebug(6000) << "collectHorizontalBoxCoordinates: " << "ende" << endl; -} - -/** - * Checks whether the given line box' extents and the following line box' - * extents are disjount (i. e. do not share the same x-coordinate range). - * @param line line box - * @param toBegin \c true, compare with preceding line box, \c false, with - * succeeding - * @return \c true if this and the next box are disjoint - */ -inline static bool lineBoxesDisjoint(InlineRunBox *line, int offset, bool toBegin) -{ - InlineRunBox *next = toBegin ? line->prevLineBox() : line->nextLineBox(); - return !next || next->xPos() + next->width() + 2*offset < line->xPos() - || next->xPos() > line->xPos() + line->width() + 2*offset; -} - -/** - * Traverses the vertical outer borders of the given render flow's line - * boxes and appends the point coordinates to the given point array. - * @param line line box to begin traversal - * @param pointArray point array - * @param left \c true, traverse the left vertical coordinates, - * \c false, traverse the right vertical coordinates. - * @param lastline if not 0, returns the pointer to the last line box traversed - */ -static void collectVerticalBoxCoordinates(InlineRunBox *line, - TQValueVector<TQPoint> &pointArray, - bool left, int offset, InlineRunBox **lastline = 0) -{ - InlineRunBox *last = 0; - offset = left ? -offset:offset; - for (InlineRunBox* curr = line; curr && !last; curr = left ? curr->prevLineBox() : curr->nextLineBox()) { - InlineBox *root = curr; - - bool isLast = lineBoxesDisjoint(curr, kAbs(offset), left); - if (isLast) last = curr; - - if (root != line && !isLast) - while (root->parent()) root = root->parent(); - TQPoint newPnt(curr->xPos() + !left*curr->width() + offset, - (left ? root->topOverflow() : root->bottomOverflow()) + offset); - if (!pointArray.isEmpty()) { - TQPoint lastPnt = pointArray.back(); - if (newPnt.x()>lastPnt.x() && !left) - pointArray.back().setY( kMin(lastPnt.y(), root->topOverflow()-offset) ); - else if (newPnt.x()<lastPnt.x() && left) - pointArray.back().setY( kMax(lastPnt.y(), root->bottomOverflow()+offset) ); - TQPoint insPnt(newPnt.x(), pointArray.back().y()); -// kdDebug(6040) << "left: " << lastPnt << " == " << insPnt << ": " << (insPnt == lastPnt) << endl; - appendPoint(pointArray, insPnt); - } - appendPoint(pointArray, newPnt); - } - if (lastline) *lastline = last; -} - -/** - * Links up the end of the given point-array such that the starting point - * is not a segment separator. - * - * To achieve this, improper points are removed from the beginning of - * the point-array (by changing the array's starting iterator), and - * proper ones appended to the point-array's back. - * - * @param pointArray point-array - * @return actual begin of point array - */ -static TQPoint *linkEndToBegin(TQValueVector<TQPoint> &pointArray) -{ - uint index = 0; - assert(pointArray.size() >= 3); - - // if first and last points match, ignore the last one. - bool linkup = false; TQPoint linkupPnt; - if (pointArray.front() == pointArray.back()) { - linkupPnt = pointArray.back(); - pointArray.pop_back(); - linkup = true; - } - - const TQPoint *it = pointArray.begin() + index; - TQPoint pfirst = *it; - TQPoint pnext = *++it; - TQPoint plast = pointArray.back(); -// kdDebug(6040) << "linkcheck plast: " << plast << " pfirst: " << pfirst << " pnext: " << pnext << endl; - - if (plast.x() == pfirst.x() && pfirst.x() == pnext.x() - || plast.y() == pfirst.y() && pfirst.y() == pnext.y()) { - - ++index; - appendPoint(pointArray, pfirst); - appendPoint(pointArray, pnext); - } else if (linkup) - pointArray.push_back(linkupPnt); - return pointArray.begin() + index; -} - -void RenderInline::paintOutlines(TQPainter *p, int _tx, int _ty) -{ - if (style()->outlineWidth() == 0 || style()->outlineStyle() <= BHIDDEN) - return; - int offset = style()->outlineOffset(); - - // We may have to draw more than one outline path as they may be - // disjoint. - for (InlineRunBox *curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - TQValueVector<TQPoint> path; - - // collect topmost outline - collectHorizontalBoxCoordinates(curr, path, false, offset); - // collect right outline - collectVerticalBoxCoordinates(curr, path, false, offset, &curr); - // collect bottommost outline - collectHorizontalBoxCoordinates(curr, path, true, offset); - // collect left outline - collectVerticalBoxCoordinates(curr, path, true, offset); - - if (path.size() < 3) continue; - - const TQPoint *begin = linkEndToBegin(path); - - // paint the outline - paintOutlinePath(p, _tx, _ty, begin, path.end(), BSLeft, -1, BSTop); - } -} - -template<class T> inline void kSwap(T &a1, T &a2) -{ - T tmp = a2; - a2 = a1; - a1 = tmp; -} - -enum BSOrientation { BSHorizontal, BSVertical }; - -/** - * Returns the orientation of the given border side. - */ -inline BSOrientation bsOrientation(RenderObject::BorderSide bs) -{ - switch (bs) { - case RenderObject::BSTop: - case RenderObject::BSBottom: - return BSHorizontal; - case RenderObject::BSLeft: - case RenderObject::BSRight: - return BSVertical; - } - return BSHorizontal; // make gcc happy (sigh) -} - -/** - * Determines the new border side by evaluating the new direction as determined - * by the given coordinates, the old border side, and the relative direction. - * - * The relative direction specifies whether the old border side meets with the - * straight given by the coordinates from below (negative), or above (positive). - */ -inline RenderObject::BorderSide newBorderSide(RenderObject::BorderSide oldBS, int direction, const TQPoint &last, const TQPoint &cur) -{ - bool below = direction < 0; - if (last.x() == cur.x()) { // new segment is vertical - bool t = oldBS == RenderObject::BSTop; - bool b = oldBS == RenderObject::BSBottom; - if ((t || b) && last.y() != cur.y()) - return (cur.y() < last.y()) ^ (t && below || b && !below) - ? RenderObject::BSLeft : RenderObject::BSRight; - } else /*if (last.y() == cur.y())*/ { // new segment is horizontal - bool l = oldBS == RenderObject::BSLeft; - bool r = oldBS == RenderObject::BSRight; - if ((l || r) && last.x() != cur.x()) - return (cur.x() < last.x()) ^ (l && below || r && !below) - ? RenderObject::BSTop : RenderObject::BSBottom; - } - return oldBS; // same direction -} - -/** - * Draws an outline segment between the given two points. - * @param o render object - * @param p painter - * @param tx absolute x-coordinate of containing block - * @param ty absolute y-coordinate of containing block - * @param p1 starting point - * @param p2 end point - * @param prevBS border side of previous segment - * @param curBS border side of this segment - * @param nextBS border side of next segment - */ -static void paintOutlineSegment(RenderObject *o, TQPainter *p, int tx, int ty, - const TQPoint &p1, const TQPoint &p2, - RenderObject::BorderSide prevBS, - RenderObject::BorderSide curBS, - RenderObject::BorderSide nextBS) -{ - int ow = o->style()->outlineWidth(); - EBorderStyle os = o->style()->outlineStyle(); - TQColor oc = o->style()->outlineColor(); - - int x1 = tx + p1.x(); - int y1 = ty + p1.y(); - int x2 = tx + p2.x(); - int y2 = ty + p2.y(); - if (x1 > x2) { - kSwap(x1, x2); - if (bsOrientation(curBS) == BSHorizontal) kSwap(prevBS, nextBS); - } - if (y1 > y2) { - kSwap(y1, y2); - if (bsOrientation(curBS) == BSVertical) kSwap(prevBS, nextBS); - } - -// kdDebug(6040) << "segment(" << x1 << "," << y1 << ") - (" << x2 << "," << y2 << ")" << endl; -/* p->setPen(Qt::gray); - p->drawLine(x1,y1,x2,y2);*/ - switch (curBS) { - case RenderObject::BSLeft: - case RenderObject::BSRight: -/* p->setPen(TQColor("#ffe4dd")); - p->drawLine( - x1 - (curBS == RenderObject::BSLeft ? ow : 0), - y1 - (prevBS == RenderObject::BSTop ? ow : 0), - x2 + (curBS == RenderObject::BSRight ? ow : 0), - y2 + (nextBS == RenderObject::BSBottom ? ow : 0) - );*/ - o->drawBorder(p, - x1 - (curBS == RenderObject::BSLeft ? ow : 0), - y1 - (prevBS == RenderObject::BSTop ? ow : 0), - x2 + (curBS == RenderObject::BSRight ? ow : 0), - y2 + (nextBS == RenderObject::BSBottom ? ow : 0), - curBS, oc, o->style()->color(), os, - prevBS == RenderObject::BSTop ? ow - : prevBS == RenderObject::BSBottom ? -ow : 0, - nextBS == RenderObject::BSTop ? -ow - : nextBS == RenderObject::BSBottom ? ow : 0, - true); - break; - case RenderObject::BSBottom: - case RenderObject::BSTop: -// kdDebug(6040) << "BSTop/BSBottom: prevBS " << prevBS << " curBS " << curBS << " nextBS " << nextBS << endl; - o->drawBorder(p, - x1 - (prevBS == RenderObject::BSLeft ? ow : 0), - y1 - (curBS == RenderObject::BSTop ? ow : 0), - x2 + (nextBS == RenderObject::BSRight ? ow : 0), - y2 + (curBS == RenderObject::BSBottom ? ow : 0), - curBS, oc, o->style()->color(), os, - prevBS == RenderObject::BSLeft ? ow - : prevBS == RenderObject::BSRight ? -ow : 0, - nextBS == RenderObject::BSLeft ? -ow - : nextBS == RenderObject::BSRight ? ow : 0, - true); - break; - } -} - -void RenderInline::paintOutlinePath(TQPainter *p, int tx, int ty, const TQPoint *begin, const TQPoint *end, BorderSide bs, int direction, BorderSide endingBS) -{ - int ow = style()->outlineWidth(); - if (ow == 0 || m_isContinuation) // Continuations get painted by the original inline. - return; - - TQPoint last = *begin; - BorderSide lastBS = bs; - Q_ASSERT(begin != end); - ++begin; - -// kdDebug(6040) << "last: " << last << endl; - - bs = newBorderSide(bs, direction, last, *begin); -// kdDebug(6040) << "newBorderSide: " << lastBS << " " << direction << "d " << last << " - " << *begin << " => " << bs << endl; - - for (const TQPoint *it = begin; it != end; ++it) { - TQPoint cur = *it; -// kdDebug(6040) << "cur: " << cur << endl; - BorderSide nextBS; - if (it + 1 != end) { - TQPoint diff = cur - last; - direction = diff.x() + diff.y(); - nextBS = newBorderSide(bs, direction, cur, *(it + 1)); -// kdDebug(6040) << "newBorderSide*: " << bs << " " << direction << "d " << cur << " - " << *(it + 1) << " => " << nextBS << endl; - } else - nextBS = endingBS; - - Q_ASSERT(bsOrientation(bs) != bsOrientation(nextBS)); - paintOutlineSegment(this, p, tx, ty, last, cur, - lastBS, bs, nextBS); - lastBS = bs; - last = cur; - bs = nextBS; - } - -} - -void RenderInline::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(RenderInline)::calcMinMaxWidth() this=" << this << endl; -#endif - - // Irrelevant, since some enclosing block will actually measure us and our children. - m_minWidth = 0; - m_maxWidth = 0; - - setMinMaxKnown(); -} - -short RenderInline::width() const -{ - // Return the width of the minimal left side and the maximal right side. - short leftSide = 0; - short rightSide = 0; - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - if (curr == firstLineBox() || curr->xPos() < leftSide) - leftSide = curr->xPos(); - if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide) - rightSide = curr->xPos() + curr->width(); - } - - return rightSide - leftSide; -} - -int RenderInline::height() const -{ - int h = 0; - if (firstLineBox()) - h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos(); - return h; -} - -int RenderInline::offsetLeft() const -{ - int x = RenderFlow::offsetLeft(); - if (firstLineBox()) - x += firstLineBox()->xPos(); - return x; -} - -int RenderInline::offsetTop() const -{ - int y = RenderFlow::offsetTop(); - if (firstLineBox()) - y += firstLineBox()->yPos(); - return y; -} - -const char *RenderInline::renderName() const -{ - if (isRelPositioned()) - return "RenderInline (relative positioned)"; - if (isAnonymous()) - return "RenderInline (anonymous)"; - return "RenderInline"; -} - -bool RenderInline::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside) -{ -/* - if ( hitTestAction != HitTestSelfOnly ) { - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) - if (!child->layer() && !child->isFloating() && child->nodeAtPoint(info, _x, _y, _tx, _ty, HitTestAll)) - inside = true; - } -*/ - // Check our line boxes if we're still not inside. - if (/*hitTestAction != HitTestChildrenOnly &&*/ !inside && style()->visibility() != HIDDEN) { - // See if we're inside one of our line boxes. - inside = hitTestLines(info, _x, _y, _tx, _ty, hitTestAction); - } - - if (inside && element()) { - if (info.innerNode() && info.innerNode()->renderer() && - !info.innerNode()->renderer()->isInline()) { - // Within the same layer, inlines are ALWAYS fully above blocks. Change inner node. - info.setInnerNode(element()); - - // Clear everything else. - info.setInnerNonSharedNode(0); - info.setURLElement(0); - } - - if (!info.innerNode()) - info.setInnerNode(element()); - - if(!info.innerNonSharedNode()) - info.setInnerNonSharedNode(element()); - } - - return inside; -} - -void RenderInline::caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) -{ - _x = -1; - - RenderBlock *cb = containingBlock(); - bool rtl = cb->style()->direction() == RTL; - bool outsideEnd = flags & CFOutsideEnd; - // I need to explain that: outsideEnd contains a meaningful value if - // and only if flags & CFOutside is set. If it is not, then randomly - // either the first or the last line box is returned. - // This doesn't matter because the only case this can happen is on an - // empty inline element, whose first and last line boxes are actually - // the same. - InlineFlowBox *line = !outsideEnd ^ rtl ? firstLineBox() : lastLineBox(); - - if (!line) { // umpf, handle "gracefully" - RenderFlow::caretPos(offset, flags, _x, _y, width, height); - return; - } - - _x = line->xPos(); - width = 1; // ### regard CFOverride - - // Place caret outside the border - if (flags & CFOutside) { - RenderStyle *s = element() && element()->parent() - && element()->parent()->renderer() - ? element()->parent()->renderer()->style() - : style(); - const TQFontMetrics &fm = s->fontMetrics(); - _y = line->yPos() + line->baseline() - fm.ascent(); - height = fm.height(); - - if (!outsideEnd ^ rtl) { - _x -= line->marginBorderPaddingLeft(); - } else { - _x += line->width() + line->marginBorderPaddingRight(); - } - - } else { - const TQFontMetrics &fm = style()->fontMetrics(); - _y = line->yPos() + line->baseline() - fm.ascent(); - height = fm.height(); - } - - int absx, absy; - if (cb && cb->absolutePosition(absx,absy)) { - //kdDebug(6040) << "absx=" << absx << " absy=" << absy << endl; - _x += absx; - _y += absy; - } else { - // we don't know our absolute position, and there is no point returning - // just a relative one - _x = _y = -1; - } -} - -inline int minXPos(const RenderInline *o) -{ - int retval=6666666; - if (!o->firstLineBox()) return 0; - for (InlineRunBox* curr = o->firstLineBox(); curr; curr = curr->nextLineBox()) - retval = kMin( retval, int( curr->m_x )); - return retval; -} - -int RenderInline::inlineXPos() const -{ - return minXPos(this); -} - -int RenderInline::inlineYPos() const -{ - return firstLineBox() ? firstLineBox()->yPos() : 0; -} - diff --git a/khtml/rendering/render_inline.h b/khtml/rendering/render_inline.h deleted file mode 100644 index 5f4bf7b29..000000000 --- a/khtml/rendering/render_inline.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of the render object implementation for KHTML. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef RENDER_INLINE_H -#define RENDER_INLINE_H - -#include "render_flow.h" - -namespace khtml { - -class RenderInline : public RenderFlow -{ -public: - RenderInline(DOM::NodeImpl* node) : RenderFlow( node ), m_isContinuation( false ) {} - - virtual const char *renderName() const; - - virtual bool isRenderInline() const { return true; } - virtual bool isInlineFlow() const { return true; } - virtual bool childrenInline() const { return true; } - - virtual bool isInlineContinuation() const; - - virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild); - - void splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, - RenderObject* beforeChild, RenderFlow* oldCont); - - void splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, - RenderObject* newChild, RenderFlow* oldCont); - - virtual void setStyle(RenderStyle* _style); - virtual void attach(); - - virtual void layout() {} // Do nothing for layout() - - virtual void paint(PaintInfo&, int tx, int ty); - - virtual bool nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside); - - virtual void calcMinMaxWidth(); - - // overrides RenderObject - virtual bool requiresLayer() const { return isRelPositioned(); } - - virtual short width() const; - virtual int height() const; - - virtual int inlineXPos() const; - virtual int inlineYPos() const; - - // used to calculate offsetWidth/Height. Overridden by inlines (render_flow) to return - // the remaining width on a given line (and the height of a single line). - virtual int offsetLeft() const; - virtual int offsetTop() const; - - virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height); - void paintOutlines(TQPainter *p, int tx, int ty); - -protected: - static RenderInline* cloneInline(RenderFlow* src); - void paintOutlinePath(TQPainter *p, int tx, int ty, const TQPoint *begin, const TQPoint *end, BorderSide startingBS, int initialDirection, BorderSide endingBS); - -private: - bool m_isContinuation : 1; // Whether or not we're a continuation of an inline. - -}; - -} // namespace - -#endif // RENDER_BLOCK_H - diff --git a/khtml/rendering/render_layer.cpp b/khtml/rendering/render_layer.cpp deleted file mode 100644 index 2b7e93f1f..000000000 --- a/khtml/rendering/render_layer.cpp +++ /dev/null @@ -1,1830 +0,0 @@ -/* - * Copyright (C) 2003 Apple Computer, Inc. - * (C) 2006 Germain Garand <germain@ebooksfrance.org> - * (C) 2006 Allan Sandfeld Jense <kde@carewolf.com> - * - * Portions are Copyright (C) 1998 Netscape Communications Corporation. - * - * Other contributors: - * Robert O'Callahan <roc+@cs.cmu.edu> - * David Baron <dbaron@fas.harvard.edu> - * Christian Biesinger <cbiesinger@web.de> - * Randall Jesup <rjesup@wgate.com> - * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> - * Josh Soref <timeless@mac.com> - * Boris Zbarsky <bzbarsky@mit.edu> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Alternatively, the contents of this file may be used under the terms - * of either the Mozilla Public License Version 1.1, found at - * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public - * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html - * (the "GPL"), in which case the provisions of the MPL or the GPL are - * applicable instead of those above. If you wish to allow use of your - * version of this file only under the terms of one of those two - * licenses (the MPL or the GPL) and not to allow others to use your - * version of this file under the LGPL, indicate your decision by - * deletingthe provisions above and replace them with the notice and - * other provisions required by the MPL or the GPL, as the case may be. - * If you do not delete the provisions above, a recipient may use your - * version of this file under any of the LGPL, the MPL or the GPL. - */ - -//#define BOX_DEBUG - -#include "render_layer.h" -#include <kdebug.h> -#include <assert.h> -#include "khtmlview.h" -#include "render_canvas.h" -#include "render_arena.h" -#include "render_replaced.h" -#include "xml/dom_docimpl.h" -#include "xml/dom2_eventsimpl.h" -#include "misc/htmltags.h" -#include "html/html_blockimpl.h" -#include "xml/dom_restyler.h" - -#include <tqscrollbar.h> -#include <tqptrvector.h> -#include <tqstyle.h> - -using namespace DOM; -using namespace khtml; - -#ifdef APPLE_CHANGES -TQScrollBar* RenderLayer::gScrollBar = 0; -#endif - -#ifndef NDEBUG -static bool inRenderLayerDetach; -#endif - -void -RenderScrollMediator::slotValueChanged() -{ - m_layer->updateScrollPositionFromScrollbars(); -} - -RenderLayer::RenderLayer(RenderObject* object) -: m_object( object ), -m_parent( 0 ), -m_previous( 0 ), -m_next( 0 ), -m_first( 0 ), -m_last( 0 ), -m_x( 0 ), -m_y( 0 ), -m_scrollX( 0 ), -m_scrollY( 0 ), -m_scrollWidth( 0 ), -m_scrollHeight( 0 ), -m_hBar( 0 ), -m_vBar( 0 ), -m_scrollMediator( 0 ), -m_posZOrderList( 0 ), -m_negZOrderList( 0 ), -m_overflowList(0), -m_zOrderListsDirty( true ), -m_overflowListDirty(true), -m_isOverflowOnly( shouldBeOverflowOnly() ), -m_markedForRepaint( false ), -m_hasOverlaidWidgets( false ), -m_marquee( 0 ) -{ -} - -RenderLayer::~RenderLayer() -{ - // Child layers will be deleted by their corresponding render objects, so - // our destructor doesn't have to do anything. - delete m_hBar; - delete m_vBar; - delete m_scrollMediator; - delete m_posZOrderList; - delete m_negZOrderList; - delete m_overflowList; - delete m_marquee; -} - -void RenderLayer::updateLayerPosition() -{ - - // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we - // don't need to ever update our layer position here. - if (renderer()->isCanvas()) - return; - - int x = m_object->xPos(); - int y = m_object->yPos() - m_object->borderTopExtra(); - - if (!m_object->isPositioned()) { - // We must adjust our position by walking up the render tree looking for the - // nearest enclosing object with a layer. - RenderObject* curr = m_object->parent(); - while (curr && !curr->layer()) { - x += curr->xPos(); - y += curr->yPos(); - curr = curr->parent(); - } - if (curr) - y += curr->borderTopExtra(); - } - - if (m_object->isRelPositioned()) - static_cast<RenderBox*>(m_object)->relativePositionOffset(x, y); - - // Subtract our parent's scroll offset. - if (m_object->isPositioned() && enclosingPositionedAncestor()) { - RenderLayer* positionedParent = enclosingPositionedAncestor(); - - // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. - positionedParent->subtractScrollOffset(x, y); - positionedParent->checkInlineRelOffset(m_object, x, y); - } - else if (parent()) - parent()->subtractScrollOffset(x, y); - - setPos(x,y); -} - -TQRegion RenderLayer::paintedRegion(RenderLayer* rootLayer) -{ - updateZOrderLists(); - TQRegion r; - if (m_negZOrderList) { - uint count = m_negZOrderList->count(); - for (uint i = 0; i < count; i++) { - RenderLayer* child = m_negZOrderList->at(i); - r += child->paintedRegion(rootLayer); - } - } - const RenderStyle *s= renderer()->style(); - if (s->visibility() == VISIBLE) { - int x = 0; int y = 0; - convertToLayerCoords(rootLayer,x,y); - TQRect cr(x,y,width(),height()); - if ( s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() || - renderer()->scrollsOverflow() || renderer()->isReplaced() ) { - r += cr; - } else { - r += renderer()->visibleFlowRegion(x, y); - } - } - - if (m_posZOrderList) { - uint count = m_posZOrderList->count(); - for (uint i = 0; i < count; i++) { - RenderLayer* child = m_posZOrderList->at(i); - r += child->paintedRegion(rootLayer); - } - } - return r; -} - -void RenderLayer::repaint( Priority p, bool markForRepaint ) -{ - if (markForRepaint && m_markedForRepaint) - return; - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->repaint( p, markForRepaint ); - TQRect layerBounds, damageRect, fgrect; - calculateRects(renderer()->canvas()->layer(), renderer()->viewRect(), layerBounds, damageRect, fgrect); - m_visibleRect = damageRect.intersect( layerBounds ); - if (m_visibleRect.isValid()) - renderer()->canvas()->repaintViewRectangle( m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(), (p > NormalPriority) ); - if (markForRepaint) - m_markedForRepaint = true; -} - -void RenderLayer::updateLayerPositions(RenderLayer* rootLayer, bool doFullRepaint, bool checkForRepaint) -{ - if (doFullRepaint) { - m_object->repaint(); - checkForRepaint = doFullRepaint = false; - } - - updateLayerPosition(); // For relpositioned layers or non-positioned layers, - // we need to keep in sync, since we may have shifted relative - // to our parent layer. - - if (m_hBar || m_vBar) { - // Need to position the scrollbars. - int x = 0; - int y = 0; - convertToLayerCoords(rootLayer, x, y); - TQRect layerBounds = TQRect(x,y,width(),height()); - positionScrollbars(layerBounds); - } - -#ifdef APPLE_CHANGES - // FIXME: Child object could override visibility. - if (checkForRepaint && (m_object->style()->visibility() == VISIBLE)) - m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_fullRepaintRect); -#else - if (checkForRepaint && m_markedForRepaint) { - TQRect layerBounds, damageRect, fgrect; - calculateRects(rootLayer, renderer()->viewRect(), layerBounds, damageRect, fgrect); - TQRect vr = damageRect.intersect( layerBounds ); - if (vr != m_visibleRect && vr.isValid()) { - renderer()->canvas()->repaintViewRectangle( vr.x(), vr.y(), vr.width(), vr.height() ); - m_visibleRect = vr; - } - } - m_markedForRepaint = false; -#endif - - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(rootLayer, doFullRepaint, checkForRepaint); - - // With all our children positioned, now update our marquee if we need to. - if (m_marquee) - m_marquee->updateMarqueePosition(); -} - -void RenderLayer::updateWidgetMasks(RenderLayer* rootLayer) -{ - if (hasOverlaidWidgets() && !renderer()->canvas()->pagedMode()) { - updateZOrderLists(); - uint count = m_posZOrderList ? m_posZOrderList->count() : 0; - bool needUpdate = (count || !m_region.isNull()); - if (count) { - TQScrollView* sv = m_object->document()->view(); - m_region = TQRect(0,0,sv->contentsWidth(),sv->contentsHeight()); - - for (uint i = 0; i < count; i++) { - RenderLayer* child = m_posZOrderList->at(i); - if (child->zIndex() == 0 && child->renderer()->style()->position() == STATIC) - continue; // we don't know the widget's exact stacking position within flow - m_region -= child->paintedRegion(rootLayer); - } - } else { - m_region = TQRegion(); - } - if (needUpdate) - renderer()->updateWidgetMasks(); - } - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateWidgetMasks(rootLayer); -} - -short RenderLayer::width() const -{ - int w = m_object->width(); - if (!m_object->hasOverflowClip()) - w = kMax(m_object->overflowWidth(), w); - return w; -} - -int RenderLayer::height() const -{ - int h = m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra(); - if (!m_object->hasOverflowClip()) - h = kMax(m_object->overflowHeight(), h); - return h; -} - - -RenderLayer *RenderLayer::stackingContext() const -{ - RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isCanvas() && - curr->m_object->style()->hasAutoZIndex(); - curr = curr->parent()); - return curr; -} - -RenderLayer* RenderLayer::enclosingPositionedAncestor() const -{ - RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isCanvas() && - !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned(); - curr = curr->parent()); - - return curr; -} - -#ifdef APPLE_CHANGES -bool RenderLayer::isTransparent() -{ - return m_object->style()->opacity() < 1.0f; -} - -RenderLayer* RenderLayer::transparentAncestor() -{ - RenderLayer* curr = parent(); - for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent()); - return curr; -} -#endif - -void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw() -{ - return renderArena->allocate(sz); -} - -void RenderLayer::operator delete(void* ptr, size_t sz) -{ - assert(inRenderLayerDetach); - - // Stash size where detach can find it. - *(size_t *)ptr = sz; -} - -void RenderLayer::detach(RenderArena* renderArena) -{ -#ifndef NDEBUG - inRenderLayerDetach = true; -#endif - delete this; -#ifndef NDEBUG - inRenderLayerDetach = false; -#endif - - // Recover the size left there for us by operator delete and free the memory. - renderArena->free(*(size_t *)this, this); -} - -void RenderLayer::addChild(RenderLayer *child, RenderLayer* beforeChild) -{ - RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild(); - if (prevSibling) { - child->setPreviousSibling(prevSibling); - prevSibling->setNextSibling(child); - } - else - setFirstChild(child); - - if (beforeChild) { - beforeChild->setPreviousSibling(child); - child->setNextSibling(beforeChild); - } - else - setLastChild(child); - - child->setParent(this); - - if (child->isOverflowOnly()) - dirtyOverflowList(); - else { - // Dirty the z-order list in which we are contained. The stackingContext() can be null in the - // case where we're building up generated content layers. This is ok, since the lists will start - // off dirty in that case anyway. - RenderLayer* stackingContext = child->stackingContext(); - if (stackingContext) - stackingContext->dirtyZOrderLists(); - } -} - -RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) -{ - // remove the child - if (oldChild->previousSibling()) - oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); - if (oldChild->nextSibling()) - oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); - - if (m_first == oldChild) - m_first = oldChild->nextSibling(); - if (m_last == oldChild) - m_last = oldChild->previousSibling(); - - if (oldChild->isOverflowOnly()) - dirtyOverflowList(); - else { - // Dirty the z-order list in which we are contained. When called via the - // reattachment process in removeOnlyThisLayer, the layer may already be disconnected - // from the main layer tree, so we need to null-check the |stackingContext| value. - RenderLayer* stackingContext = oldChild->stackingContext(); - if (stackingContext) - stackingContext->dirtyZOrderLists(); - } - - oldChild->setPreviousSibling(0); - oldChild->setNextSibling(0); - oldChild->setParent(0); - - return oldChild; -} - -void RenderLayer::removeOnlyThisLayer() -{ - if (!m_parent) - return; - - // Remove us from the parent. - RenderLayer* parent = m_parent; - RenderLayer* nextSib = nextSibling(); - parent->removeChild(this); - - // Now walk our kids and reattach them to our parent. - RenderLayer* current = m_first; - while (current) { - RenderLayer* next = current->nextSibling(); - removeChild(current); - parent->addChild(current, nextSib); - current = next; - } - - detach(renderer()->renderArena()); -} - -void RenderLayer::insertOnlyThisLayer() -{ - if (!m_parent && renderer()->parent()) { - // We need to connect ourselves when our renderer() has a parent. - // Find our enclosingLayer and add ourselves. - RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); - if (parentLayer) - parentLayer->addChild(this, - renderer()->parent()->findNextLayer(parentLayer, renderer())); - } - - // Remove all descendant layers from the hierarchy and add them to the new position. - for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) - curr->moveLayers(m_parent, this); -} - -void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const -{ - if (ancestorLayer == this) - return; - - if (m_object->style()->position() == FIXED) { - // Add in the offset of the view. We can obtain this by calling - // absolutePosition() on the RenderCanvas. - int xOff, yOff; - m_object->absolutePosition(xOff, yOff, true); - x += xOff; - y += yOff; - return; - } - - RenderLayer* parentLayer; - if (m_object->style()->position() == ABSOLUTE) - parentLayer = enclosingPositionedAncestor(); - else - parentLayer = parent(); - - if (!parentLayer) return; - - parentLayer->convertToLayerCoords(ancestorLayer, x, y); - - x += xPos(); - y += yPos(); -} - -void RenderLayer::scrollOffset(int& x, int& y) -{ - x += scrollXOffset(); - y += scrollYOffset(); -} - -void RenderLayer::subtractScrollOffset(int& x, int& y) -{ - x -= scrollXOffset(); - y -= scrollYOffset(); -} - -void RenderLayer::checkInlineRelOffset(const RenderObject* o, int& x, int& y) -{ - if(o->style()->position() != ABSOLUTE || !renderer()->isRelPositioned() || !renderer()->isInlineFlow()) - return; - - // Our renderer is an enclosing relpositioned inline, we need to add in the offset of the first line - // box from the rest of the content, but only in the cases where we know our descendant is positioned - // relative to the inline itself. - assert( o->container() == m_object ); - - RenderFlow* flow = static_cast<RenderFlow*>(m_object); - int sx = 0, sy = 0; - if (flow->firstLineBox()) { - if (flow->style()->direction() == LTR) - sx = flow->firstLineBox()->xPos(); - else - sx = flow->lastLineBox()->xPos(); - sy = flow->firstLineBox()->yPos(); - } else { - sx = flow->staticX(); // ### - sy = flow->staticY(); - } - bool isInlineType = o->style()->isOriginalDisplayInlineType(); - - if (!o->hasStaticX()) - x += sx; - - // Despite the positioned child being a block display type inside an inline, we still keep - // its x locked to our left. Arguably the correct behavior would be to go flush left to - // the block that contains us, but that isn't what other browsers do. - if (o->hasStaticX() && !isInlineType) - // Avoid adding in the left border/padding of the containing block twice. Subtract it out. - x += sx - (o->containingBlock()->borderLeft() + o->containingBlock()->paddingLeft()); - - if (!o->hasStaticY()) - y += sy; -} - -void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint) -{ - if (renderer()->style()->overflowX() != OMARQUEE || !renderer()->hasOverflowClip()) { - if (x < 0) x = 0; - if (y < 0) y = 0; - - // Call the scrollWidth/Height functions so that the dimensions will be computed if they need - // to be (for overflow:hidden blocks). - // ### merge the scrollWidth()/scrollHeight() methods - int maxX = m_scrollWidth - m_object->clientWidth(); - int maxY = m_scrollHeight - m_object->clientHeight(); - - if (x > maxX) x = maxX; - if (y > maxY) y = maxY; - } - - // FIXME: Eventually, we will want to perform a blit. For now never - // blit, since the check for blitting is going to be very - // complicated (since it will involve testing whether our layer - // is either occluded by another layer or clipped by an enclosing - // layer or contains fixed backgrounds, etc.). - m_scrollX = x; - m_scrollY = y; - - // Update the positions of our child layers. - RenderLayer* rootLayer = root(); - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(rootLayer); - - // Fire the scroll DOM event. - m_object->element()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false); - - // Just schedule a full repaint of our object. - if (repaint) - m_object->repaint(RealtimePriority); - - if (updateScrollbars) { - if (m_hBar) - m_hBar->setValue(m_scrollX); - if (m_vBar) - m_vBar->setValue(m_scrollY); - } -} - -void RenderLayer::updateScrollPositionFromScrollbars() -{ - bool needUpdate = false; - int newX = m_scrollX; - int newY = m_scrollY; - - if (m_hBar) { - newX = m_hBar->value(); - if (newX != m_scrollX) - needUpdate = true; - } - - if (m_vBar) { - newY = m_vBar->value(); - if (newY != m_scrollY) - needUpdate = true; - } - - if (needUpdate) - scrollToOffset(newX, newY, false); -} - -void -RenderLayer::showScrollbar(Qt::Orientation o, bool show) -{ - TQScrollBar *sb = (o == Qt::Horizontal) ? m_hBar : m_vBar; - - if (show && !sb) { - TQScrollView* scrollView = m_object->document()->view(); - sb = new TQScrollBar(o, scrollView, "__khtml"); - scrollView->addChild(sb, 0, -50000); - sb->setBackgroundMode(TQWidget::NoBackground); - sb->show(); - if (!m_scrollMediator) - m_scrollMediator = new RenderScrollMediator(this); - m_scrollMediator->connect(sb, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotValueChanged())); - } - else if (!show && sb) { - delete sb; - sb = 0; - } - - if (o == Qt::Horizontal) - m_hBar = sb; - else - m_vBar = sb; -} - -int RenderLayer::verticalScrollbarWidth() -{ - if (!m_vBar) - return 0; - -#ifdef APPLE_CHANGES - return m_vBar->width(); -#else - return m_vBar->style().pixelMetric(TQStyle::PM_ScrollBarExtent); -#endif - -} - -int RenderLayer::horizontalScrollbarHeight() -{ - if (!m_hBar) - return 0; - -#ifdef APPLE_CHANGES - return m_hBar->height(); -#else - return m_hBar->style().pixelMetric(TQStyle::PM_ScrollBarExtent); -#endif - -} - -void RenderLayer::positionScrollbars(const TQRect& absBounds) -{ -#ifdef APPLE_CHANGES - if (m_vBar) { - scrollView->addChild(m_vBar, absBounds.x()+absBounds.width()-m_object->borderRight()-m_vBar->width(), - absBounds.y()+m_object->borderTop()); - m_vBar->resize(m_vBar->width(), absBounds.height() - - (m_object->borderTop()+m_object->borderBottom()) - - (m_hBar ? m_hBar->height()-1 : 0)); - } - - if (m_hBar) { - scrollView->addChild(m_hBar, absBounds.x()+m_object->borderLeft(), - absBounds.y()+absBounds.height()-m_object->borderBottom()-m_hBar->height()); - m_hBar->resize(absBounds.width() - (m_object->borderLeft()+m_object->borderRight()) - - (m_vBar ? m_vBar->width()-1 : 0), m_hBar->height()); - } -#else - int tx = absBounds.x(); - int ty = absBounds.y(); - int bl = m_object->borderLeft(); - int bt = m_object->borderTop(); - int w = width() - bl - m_object->borderRight(); - int h = height() - bt - m_object->borderBottom(); - - if (w <= 0 || h <= 0 || (!m_vBar && !m_hBar)) - return; - - TQScrollView* scrollView = m_object->document()->view(); - - tx += bl; - ty += bt; - - TQScrollBar *b = m_hBar; - if (!m_hBar) - b = m_vBar; - int sw = b->style().pixelMetric(TQStyle::PM_ScrollBarExtent); - - if (m_vBar) { - TQRect vBarRect = TQRect(tx + w - sw + 1, ty, sw, h - (m_hBar ? sw : 0) + 1); - m_vBar->resize(vBarRect.width(), vBarRect.height()); - scrollView->addChild(m_vBar, vBarRect.x(), vBarRect.y()); - } - - if (m_hBar) { - TQRect hBarRect = TQRect(tx, ty + h - sw + 1, w - (m_vBar ? sw : 0) + 1, sw); - m_hBar->resize(hBarRect.width(), hBarRect.height()); - scrollView->addChild(m_hBar, hBarRect.x(), hBarRect.y()); - } -#endif -} - -#define LINE_STEP 10 -#define PAGE_KEEP 40 - -void RenderLayer::checkScrollbarsAfterLayout() -{ - int rightPos = m_object->rightmostPosition(true); - int bottomPos = m_object->lowestPosition(true); - -/* TODO - m_scrollLeft = m_object->leftmostPosition(true); - m_scrollTop = m_object->highestPosition(true); -*/ - - int clientWidth = m_object->clientWidth(); - int clientHeight = m_object->clientHeight(); - m_scrollWidth = clientWidth; - m_scrollHeight = clientHeight; - - if (rightPos - m_object->borderLeft() > m_scrollWidth) - m_scrollWidth = rightPos - m_object->borderLeft(); - if (bottomPos - m_object->borderTop() > m_scrollHeight) - m_scrollHeight = bottomPos - m_object->borderTop(); - - bool needHorizontalBar = rightPos > width(); - bool needVerticalBar = bottomPos > height(); - - bool haveHorizontalBar = m_hBar && m_hBar->isEnabled(); - bool haveVerticalBar = m_vBar && m_vBar->isEnabled(); - - bool hasOvf = m_object->hasOverflowClip(); - - // overflow:scroll should just enable/disable. - if (hasOvf && m_object->style()->overflowX() == OSCROLL) - m_hBar->setEnabled(needHorizontalBar); - if (hasOvf && m_object->style()->overflowY() == OSCROLL) - m_vBar->setEnabled(needVerticalBar); - - // overflow:auto may need to lay out again if scrollbars got added/removed. - bool scrollbarsChanged = (hasOvf && m_object->style()->overflowX() == OAUTO && haveHorizontalBar != needHorizontalBar) - || (hasOvf && m_object->style()->overflowY() == OAUTO && haveVerticalBar != needVerticalBar); - if (scrollbarsChanged) { - if (m_object->style()->overflowX() == OAUTO) { - showScrollbar(Qt::Horizontal, needHorizontalBar); - if (m_hBar) - m_hBar->setEnabled(true); - } - if (m_object->style()->overflowY() == OAUTO) { - showScrollbar(Qt::Vertical, needVerticalBar); - if (m_vBar) - m_vBar->setEnabled(true); - } - - m_object->setNeedsLayout(true); - if (m_object->isRenderBlock()) - static_cast<RenderBlock*>(m_object)->layoutBlock(true); - else - m_object->layout(); - return; - } - - // Set up the range (and page step/line step). - if (m_hBar) { - int pageStep = (clientWidth-PAGE_KEEP); - if (pageStep < 0) pageStep = clientWidth; - m_hBar->setSteps(LINE_STEP, pageStep); -#ifdef APPLE_CHANGES - m_hBar->setKnobProportion(clientWidth, m_scrollWidth); -#else - m_hBar->setRange(0, needHorizontalBar ? m_scrollWidth-clientWidth : 0); -#endif - } - if (m_vBar) { - int pageStep = (clientHeight-PAGE_KEEP); - if (pageStep < 0) pageStep = clientHeight; - m_vBar->setSteps(LINE_STEP, pageStep); -#ifdef APPLE_CHANGES - m_vBar->setKnobProportion(clientHeight, m_scrollHeight); -#else - m_vBar->setRange(0, needVerticalBar ? m_scrollHeight-clientHeight : 0); -#endif - } -} - -void RenderLayer::paintScrollbars(RenderObject::PaintInfo& pI) -{ -#ifdef APPLE_CHANGES - if (m_hBar) - m_hBar->paint(p, damageRect); - if (m_vBar) - m_vBar->paint(p, damageRect); -#else - if (!m_object->element()) - return; - - TQScrollView* scrollView = m_object->document()->view(); - if (m_hBar) { - int x = m_hBar->x(); - int y = m_hBar->y(); - scrollView->viewportToContents(x, y, x, y); - RenderWidget::paintWidget(pI, m_hBar, x, y); - } - if (m_vBar) { - int x = m_vBar->x(); - int y = m_vBar->y(); - scrollView->viewportToContents(x, y, x, y); - RenderWidget::paintWidget(pI, m_vBar, x, y); - } -#endif -} - -void RenderLayer::paint(TQPainter *p, const TQRect& damageRect, bool selectionOnly) -{ - paintLayer(this, p, damageRect, selectionOnly); -} - -static void setClip(TQPainter* p, const TQRect& paintDirtyRect, const TQRect& clipRect) -{ - if (paintDirtyRect == clipRect) - return; - p->save(); - -#ifdef APPLE_CHANGES - p->addClip(clipRect); -#else - - TQRect clippedRect = p->xForm(clipRect); - TQRegion creg(clippedRect); - TQRegion old = p->clipRegion(); - if (!old.isNull()) - creg = old.intersect(creg); - p->setClipRegion(creg); -#endif - -} - -static void restoreClip(TQPainter* p, const TQRect& paintDirtyRect, const TQRect& clipRect) -{ - if (paintDirtyRect == clipRect) - return; - p->restore(); -} - -void RenderLayer::paintLayer(RenderLayer* rootLayer, TQPainter *p, - const TQRect& paintDirtyRect, bool selectionOnly) -{ - // Calculate the clip rects we should use. - TQRect layerBounds, damageRect, clipRectToApply; - calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply); - int x = layerBounds.x(); - int y = layerBounds.y(); - - // Ensure our lists are up-to-date. - updateZOrderLists(); - updateOverflowList(); - -#ifdef APPLE_CHANGES - // Set our transparency if we need to. - if (isTransparent()) - p->beginTransparencyLayer(renderer()->style()->opacity()); -#endif - - // We want to paint our layer, but only if we intersect the damage rect. - bool shouldPaint = intersectsDamageRect(layerBounds, damageRect); - if (shouldPaint && !selectionOnly) { - // Paint our background first, before painting any child layers. - if (!damageRect.isEmpty()) { - // Establish the clip used to paint our background. - setClip(p, paintDirtyRect, damageRect); - - // Paint the background. - RenderObject::PaintInfo paintInfo(p, damageRect, PaintActionElementBackground); - renderer()->paint(paintInfo, - x - renderer()->xPos(), y - renderer()->yPos() + renderer()->borderTopExtra()); - - // Position our scrollbars. - positionScrollbars(layerBounds); - - // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with - // z-index. We paint after we painted the background/border, so that the scrollbars will - // sit above the background/border. - paintScrollbars(paintInfo); - - // Restore the clip. - restoreClip(p, paintDirtyRect, damageRect); - } - } - - // Now walk the sorted list of children with negative z-indices. - if (m_negZOrderList) { - uint count = m_negZOrderList->count(); - for (uint i = 0; i < count; i++) { - RenderLayer* child = m_negZOrderList->at(i); - child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly); - } - } - - // Now establish the appropriate clip and paint our child RenderObjects. - if (shouldPaint && !clipRectToApply.isEmpty()) { - // Set up the clip used when painting our children. - setClip(p, paintDirtyRect, clipRectToApply); - - RenderObject::PaintInfo paintInfo(p, clipRectToApply, PaintActionSelection); - - int tx = x - renderer()->xPos(); - int ty = y - renderer()->yPos() + renderer()->borderTopExtra(); - - if (selectionOnly) - renderer()->paint(paintInfo, tx, ty); - else { - paintInfo.phase = PaintActionChildBackgrounds; - renderer()->paint(paintInfo, tx, ty); - paintInfo.phase = PaintActionFloat; - renderer()->paint(paintInfo, tx, ty); - paintInfo.phase = PaintActionForeground; - renderer()->paint(paintInfo, tx, ty); - RenderCanvas *rc = static_cast<RenderCanvas*>(renderer()->document()->renderer()); - if (rc->maximalOutlineSize()) { - paintInfo.phase = PaintActionOutline; - renderer()->paint(paintInfo, tx, ty); - } - if (rc->selectionStart() && rc->selectionEnd()) { - paintInfo.phase = PaintActionSelection; - renderer()->paint(paintInfo, tx, ty); - } - } - - // Now restore our clip. - restoreClip(p, paintDirtyRect, clipRectToApply); - } - - // Paint any child layers that have overflow. - if (m_overflowList) - for (TQValueList<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it) - (*it)->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly); - - // Now walk the sorted list of children with positive z-indices. - if (m_posZOrderList) { - uint count = m_posZOrderList->count(); - for (uint i = 0; i < count; i++) { - RenderLayer* child = m_posZOrderList->at(i); - child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly); - } - } - -#ifdef BOX_DEBUG - { - int ax=0; - int ay=0; - renderer()->absolutePosition( ax, ay ); - p->setPen(TQPen(TQColor("yellow"), 1, Qt::DotLine)); - p->setBrush( Qt::NoBrush ); - p->drawRect(ax, ay, width(), height()); - } -#endif - -#ifdef APPLE_CHANGES - // End our transparency layer - if (isTransparent()) - p->endTransparencyLayer(); -#endif -} - -bool RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y) -{ -#ifdef APPLE_CHANGES - // Clear our our scrollbar variable - RenderLayer::gScrollBar = 0; -#endif - - int stx = m_x; - int sty = m_y; - -#ifdef __GNUC__ -#warning HACK -#endif - if (renderer()->isCanvas()) { - stx += static_cast<RenderCanvas*>(renderer())->view()->contentsX(); - sty += static_cast<RenderCanvas*>(renderer())->view()->contentsY(); - } - - TQRect damageRect(stx,sty, width(), height()); - RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect); - - // Now determine if the result is inside an anchor. - DOM::NodeImpl* node = info.innerNode(); - while (node) { - if (node->hasAnchor() && !info.URLElement()) - info.setURLElement(node); - node = node->parentNode(); - } - - // Next set up the correct :hover/:active state along the new chain. - updateHoverActiveState(info); - - // Now return whether we were inside this layer (this will always be true for the root - // layer). - return insideLayer; -} - -RenderLayer* RenderLayer::nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info, - int xMousePos, int yMousePos, const TQRect& hitTestRect) -{ - // Calculate the clip rects we should use. - TQRect layerBounds, bgRect, fgRect; - calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect); - - // Ensure our lists are up-to-date. - updateZOrderLists(); - updateOverflowList(); - - // This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer, - // we are done and can return it. - RenderLayer* insideLayer = 0; - - // Begin by walking our list of positive layers from highest z-index down to the lowest - // z-index. - if (m_posZOrderList) { - uint count = m_posZOrderList->count(); - for (int i = count-1; i >= 0; i--) { - RenderLayer* child = m_posZOrderList->at(i); - insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect); - if (insideLayer) - return insideLayer; - } - } - - // Now check our overflow objects. - if (m_overflowList) { - TQValueList<RenderLayer*>::iterator it = m_overflowList->end(); - for (--it; it != m_overflowList->end(); --it) { - insideLayer = (*it)->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect); - if (insideLayer) - return insideLayer; - } - } - - // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. - if (containsPoint(xMousePos, yMousePos, fgRect) && - renderer()->nodeAtPoint(info, xMousePos, yMousePos, - layerBounds.x() - renderer()->xPos(), - layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), - HitTestChildrenOnly)) { - if (info.innerNode() != m_object->element()) - return this; - } - - // Now check our negative z-index children. - if (m_negZOrderList) { - uint count = m_negZOrderList->count(); - for (int i = count-1; i >= 0; i--) { - RenderLayer* child = m_negZOrderList->at(i); - insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect); - if (insideLayer) - return insideLayer; - } - } - - // Next we want to see if the mouse pos is inside this layer but not any of its children. - if (containsPoint(xMousePos, yMousePos, bgRect) && - renderer()->nodeAtPoint(info, xMousePos, yMousePos, - layerBounds.x() - renderer()->xPos(), - layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), - HitTestSelfOnly)) - return this; - - // No luck. - return 0; -} - -void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, TQRect& overflowClipRect, - TQRect& posClipRect, TQRect& fixedClipRect) -{ - if (parent()) - parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect); - - switch (m_object->style()->position()) { - // A fixed object is essentially the root of its containing block hierarchy, so when - // we encounter such an object, we reset our clip rects to the fixedClipRect. - case FIXED: - posClipRect = fixedClipRect; - overflowClipRect = fixedClipRect; - break; - case ABSOLUTE: - overflowClipRect = posClipRect; - break; - case RELATIVE: - posClipRect = overflowClipRect; - break; - default: - break; - } - - // Update the clip rects that will be passed to child layers. - if (m_object->hasOverflowClip() || m_object->hasClip()) { - // This layer establishes a clip of some kind. - int x = 0; - int y = 0; - convertToLayerCoords(rootLayer, x, y); - - if (m_object->hasOverflowClip()) { - TQRect newOverflowClip = m_object->getOverflowClipRect(x,y); - overflowClipRect = newOverflowClip.intersect(overflowClipRect); - if (m_object->isPositioned() || m_object->isRelPositioned()) - posClipRect = newOverflowClip.intersect(posClipRect); - } - if (m_object->hasClip()) { - TQRect newPosClip = m_object->getClipRect(x,y); - posClipRect = posClipRect.intersect(newPosClip); - overflowClipRect = overflowClipRect.intersect(newPosClip); - fixedClipRect = fixedClipRect.intersect(newPosClip); - } - } -} - -void RenderLayer::calculateRects(const RenderLayer* rootLayer, const TQRect& paintDirtyRect, TQRect& layerBounds, - TQRect& backgroundRect, TQRect& foregroundRect) -{ - TQRect overflowClipRect = paintDirtyRect; - TQRect posClipRect = paintDirtyRect; - TQRect fixedClipRect = paintDirtyRect; - if (parent()) - parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect); - - int x = 0; - int y = 0; - convertToLayerCoords(rootLayer, x, y); - layerBounds = TQRect(x,y,width(),height()); - - backgroundRect = m_object->style()->position() == FIXED ? fixedClipRect : - (m_object->isPositioned() ? posClipRect : overflowClipRect); - foregroundRect = backgroundRect; - - // Update the clip rects that will be passed to child layers. - if (m_object->hasOverflowClip() || m_object->hasClip()) { - // This layer establishes a clip of some kind. - if (m_object->hasOverflowClip()) - foregroundRect = foregroundRect.intersect(m_object->getOverflowClipRect(x,y)); - - if (m_object->hasClip()) { - // Clip applies to *us* as well, so go ahead and update the damageRect. - TQRect newPosClip = m_object->getClipRect(x,y); - backgroundRect = backgroundRect.intersect(newPosClip); - foregroundRect = foregroundRect.intersect(newPosClip); - } - - // If we establish a clip at all, then go ahead and make sure our background - // rect is intersected with our layer's bounds. - backgroundRect = backgroundRect.intersect(layerBounds); - } -} - -bool RenderLayer::intersectsDamageRect(const TQRect& layerBounds, const TQRect& damageRect) const -{ - return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() || - (renderer()->hasOverhangingFloats() && !renderer()->hasOverflowClip()) || - (renderer()->isInline() && !renderer()->isReplaced()) || - layerBounds.intersects(damageRect)); -} - -bool RenderLayer::containsPoint(int x, int y, const TQRect& damageRect) const -{ - return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() || - renderer()->hasOverhangingFloats() || - (renderer()->isInline() && !renderer()->isReplaced()) || - damageRect.contains(x, y)); -} - -// This code has been written to anticipate the addition of CSS3-::outside and ::inside generated -// content (and perhaps XBL). That's why it uses the render tree and not the DOM tree. -static RenderObject* hoverAncestor(RenderObject* obj) -{ - return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent(); -} - -static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2) -{ - if (!obj1 || !obj2) - return 0; - - for (RenderObject* currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1)) - for (RenderObject* currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2)) - if (currObj1 == currObj2) - return currObj1; - - return 0; -} - - -void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo& info) -{ - // We don't update :hover/:active state when the info is marked as readonly. - if (info.readonly()) - return; - - DOM::NodeImpl *e = m_object->element(); - DOM::DocumentImpl *doc = e ? e->getDocument() : 0; - if (!doc) return; - - // Check to see if the hovered node has changed. If not, then we don't need to - // do anything. - DOM::NodeImpl* oldHoverNode = doc->hoverNode(); - DOM::NodeImpl* newHoverNode = info.innerNode(); - - if (oldHoverNode == newHoverNode && (!oldHoverNode || oldHoverNode->active() == info.active())) - return; - - // Update our current hover node. - doc->setHoverNode(newHoverNode); - if (info.active()) - doc->setActiveNode(newHoverNode); - else - doc->setActiveNode(0); - - // We have two different objects. Fetch their renderers. - RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0; - RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0; - - // Locate the common ancestor render object for the two renderers. - RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj); - - // The old hover path only needs to be cleared up to (and not including) the common ancestor; - for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) { - curr->setMouseInside(false); - if (curr->element()) { - curr->element()->setActive(false); - curr->element()->setHovered(false); - } - } - - // Now set the hover state for our new object up to the root. - for (RenderObject* curr = newHoverObj; curr; curr = hoverAncestor(curr)) { - curr->setMouseInside(true); - if (curr->element()) { - curr->element()->setActive(info.active()); - curr->element()->setHovered(true); - } - } -} - -// Sort the buffer from lowest z-index to highest. The common scenario will have -// most z-indices equal, so we optimize for that case (i.e., the list will be mostly -// sorted already). -static void sortByZOrder(TQPtrVector<RenderLayer>* buffer, - TQPtrVector<RenderLayer>* mergeBuffer, - uint start, uint end) -{ - if (start >= end) - return; // Sanity check. - - if (end - start <= 6) { - // Apply a bubble sort for smaller lists. - for (uint i = end-1; i > start; i--) { - bool sorted = true; - for (uint j = start; j < i; j++) { - RenderLayer* elt = buffer->at(j); - RenderLayer* elt2 = buffer->at(j+1); - if (elt->zIndex() > elt2->zIndex()) { - sorted = false; - buffer->insert(j, elt2); - buffer->insert(j+1, elt); - } - } - if (sorted) - return; - } - } - else { - // Peform a merge sort for larger lists. - uint mid = (start+end)/2; - sortByZOrder(buffer, mergeBuffer, start, mid); - sortByZOrder(buffer, mergeBuffer, mid, end); - - RenderLayer* elt = buffer->at(mid-1); - RenderLayer* elt2 = buffer->at(mid); - - // Handle the fast common case (of equal z-indices). The list may already - // be completely sorted. - if (elt->zIndex() <= elt2->zIndex()) - return; - - // We have to merge sort. Ensure our merge buffer is big enough to hold - // all the items. - mergeBuffer->resize(end - start); - uint i1 = start; - uint i2 = mid; - - elt = buffer->at(i1); - elt2 = buffer->at(i2); - - while (i1 < mid || i2 < end) { - if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) { - mergeBuffer->insert(mergeBuffer->count(), elt); - i1++; - if (i1 < mid) - elt = buffer->at(i1); - } - else { - mergeBuffer->insert(mergeBuffer->count(), elt2); - i2++; - if (i2 < end) - elt2 = buffer->at(i2); - } - } - - for (uint i = start; i < end; i++) - buffer->insert(i, mergeBuffer->at(i-start)); - - mergeBuffer->clear(); - } -} - -void RenderLayer::dirtyZOrderLists() -{ - if (m_posZOrderList) - m_posZOrderList->clear(); - if (m_negZOrderList) - m_negZOrderList->clear(); - m_zOrderListsDirty = true; -} - -void RenderLayer::dirtyOverflowList() -{ - if (m_overflowList) - m_overflowList->clear(); - m_overflowListDirty = true; -} - -void RenderLayer::updateZOrderLists() -{ - if (!isStackingContext() || !m_zOrderListsDirty) - return; - - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->collectLayers(m_posZOrderList, m_negZOrderList); - - // Sort the two lists. - if (m_posZOrderList) { - TQPtrVector<RenderLayer> mergeBuffer; - sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count()); - } - if (m_negZOrderList) { - TQPtrVector<RenderLayer> mergeBuffer; - sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count()); - } - - m_zOrderListsDirty = false; -} - -void RenderLayer::updateOverflowList() -{ - if (!m_overflowListDirty) - return; - - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { - if (child->isOverflowOnly()) { - if (!m_overflowList) - m_overflowList = new TQValueList<RenderLayer*>; - m_overflowList->append(child); - } - } - - m_overflowListDirty = false; -} - -void RenderLayer::collectLayers(TQPtrVector<RenderLayer>*& posBuffer, TQPtrVector<RenderLayer>*& negBuffer) -{ - // FIXME: A child render object or layer could override visibility. Don't remove this - // optimization though until RenderObject's nodeAtPoint is patched to understand what to do - // when visibility is overridden by a child. - if (renderer()->style()->visibility() != VISIBLE) - return; - - // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. - if (!isOverflowOnly()) { - - // Determine which buffer the child should be in. - TQPtrVector<RenderLayer>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; - - // Create the buffer if it doesn't exist yet. - if (!buffer) - buffer = new TQPtrVector<RenderLayer>(); - - // Resize by a power of 2 when our buffer fills up. - if (buffer->count() == buffer->size()) - buffer->resize(2*(buffer->size()+1)); - - // Append ourselves at the end of the appropriate buffer. - buffer->insert(buffer->count(), this); - } - - // Recur into our children to collect more layers, but only if we don't establish - // a stacking context. - if (!isStackingContext()) { - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->collectLayers(posBuffer, negBuffer); - } -} - -#ifdef ENABLE_DUMP -#ifndef KDE_USE_FINAL -static TQTextStream &operator<<(TQTextStream &ts, const TQRect &r) -{ - return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height(); -} -#endif - -static void write(TQTextStream &ts, RenderObject& o, const TQString& indent ) -{ - o.dump(ts, indent); - - for (RenderObject *child = o.firstChild(); child; child = child->nextSibling()) { - if (child->layer()) continue; - write( ts, *child, indent + " " ); - } -} - -static void write(TQTextStream &ts, const RenderLayer &l, - const TQRect& layerBounds, const TQRect& backgroundClipRect, const TQRect& clipRect, - int layerType = 0, const TQString& indent = TQString::null) - -{ - ts << indent << "layer"; - - ts << " at (" << l.xPos() << "," << l.yPos() << ") size " << l.width() << "x" << l.height(); - - if (layerBounds != layerBounds.intersect(backgroundClipRect)) { - ts << " backgroundClip " << backgroundClipRect; - } - if (layerBounds != layerBounds.intersect(clipRect)) { - ts << " clip " << clipRect; - } - - if (layerType == -1) - ts << " layerType: background only"; - else if (layerType == 1) - ts << " layerType: foreground only"; - - ts << "\n"; - - if (layerType != -1) - write( ts, *l.renderer(), indent + " " ); - - ts << "\n"; -} - -static void writeLayers(TQTextStream &ts, const RenderLayer* rootLayer, RenderLayer* l, - const TQRect& paintDirtyRect, const TQString& indent) -{ - // Calculate the clip rects we should use. - TQRect layerBounds, damageRect, clipRectToApply; - l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply); - - // Ensure our lists are up-to-date. - l->updateZOrderLists(); - l->updateOverflowList(); - - bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect); - TQPtrVector<RenderLayer>* negList = l->negZOrderList(); - TQValueList<RenderLayer*>* ovfList = l->overflowList(); - if (shouldPaint && negList && negList->count() > 0) - write(ts, *l, layerBounds, damageRect, clipRectToApply, -1, indent); - - if (negList) { - for (unsigned i = 0; i != negList->count(); ++i) - writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent ); - } - - if (shouldPaint) - write(ts, *l, layerBounds, damageRect, clipRectToApply, negList && negList->count() > 0, indent); - - if (ovfList) { - for (TQValueList<RenderLayer*>::iterator it = ovfList->begin(); it != ovfList->end(); ++it) - writeLayers(ts, rootLayer, *it, paintDirtyRect, indent); - } - - TQPtrVector<RenderLayer>* posList = l->posZOrderList(); - if (posList) { - for (unsigned i = 0; i != posList->count(); ++i) - writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent); - } -} - - -void RenderLayer::dump(TQTextStream &ts, const TQString &ind) -{ - assert( renderer()->isCanvas() ); - - writeLayers(ts, this, this, TQRect(xPos(), yPos(), width(), height()), ind); -} - - -#endif - -bool RenderLayer::shouldBeOverflowOnly() const -{ - return renderer()->style() && renderer()->hasOverflowClip() && - !renderer()->isPositioned() && !renderer()->isRelPositioned(); - /* && !isTransparent(); */ -} - -void RenderLayer::styleChanged() -{ - bool isOverflowOnly = shouldBeOverflowOnly(); - if (isOverflowOnly != m_isOverflowOnly) { - m_isOverflowOnly = isOverflowOnly; - RenderLayer* p = parent(); - RenderLayer* sc = stackingContext(); - if (p) - p->dirtyOverflowList(); - if (sc) - sc->dirtyZOrderLists(); - } - - if (m_object->hasOverflowClip() && - m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) { - if (!m_marquee) - m_marquee = new Marquee(this); - m_marquee->updateMarqueeStyle(); - } - else if (m_marquee) { - delete m_marquee; - m_marquee = 0; - } -} - -void RenderLayer::suspendMarquees() -{ - if (m_marquee) - m_marquee->suspend(); - - for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) - curr->suspendMarquees(); -} - -// -------------------------------------------------------------------------- -// Marquee implementation - -Marquee::Marquee(RenderLayer* l) -:m_layer(l), m_currentLoop(0), m_totalLoops(0), m_timerId(0), m_start(0), m_end(0), m_speed(0), m_unfurlPos(0), m_reset(false), - m_suspended(false), m_stopped(false), m_whiteSpace(NORMAL), m_direction(MAUTO) -{ -} - -int Marquee::marqueeSpeed() const -{ - int result = m_layer->renderer()->style()->marqueeSpeed(); - DOM::NodeImpl* elt = m_layer->renderer()->element(); - if (elt && elt->id() == ID_MARQUEE) { - HTMLMarqueeElementImpl* marqueeElt = static_cast<HTMLMarqueeElementImpl*>(elt); - result = kMax(result, marqueeElt->minimumDelay()); - } - return result; -} - -EMarqueeDirection Marquee::direction() const -{ - // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee. - // For now just map MAUTO to MBACKWARD - EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection(); - EDirection dir = m_layer->renderer()->style()->direction(); - if (result == MAUTO) - result = MBACKWARD; - if (result == MFORWARD) - result = (dir == LTR) ? MRIGHT : MLEFT; - if (result == MBACKWARD) - result = (dir == LTR) ? MLEFT : MRIGHT; - - // Now we have the real direction. Next we check to see if the increment is negative. - // If so, then we reverse the direction. - Length increment = m_layer->renderer()->style()->marqueeIncrement(); - if (increment.value() < 0) - result = static_cast<EMarqueeDirection>(-result); - - return result; -} - -bool Marquee::isHorizontal() const -{ - return direction() == MLEFT || direction() == MRIGHT; -} - -bool Marquee::isUnfurlMarquee() const -{ - EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior(); - return (behavior == MUNFURL); -} - -int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge) -{ - RenderObject* o = m_layer->renderer(); - RenderStyle* s = o->style(); - if (isHorizontal()) { - bool ltr = s->direction() == LTR; - int clientWidth = o->clientWidth(); - int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false); - if (ltr) - contentWidth += (o->paddingRight() - o->borderLeft()); - else { - contentWidth = o->width() - contentWidth; - contentWidth += (o->paddingLeft() - o->borderRight()); - } - if (dir == MRIGHT) { - if (stopAtContentEdge) - return kMax(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); - else - return ltr ? contentWidth : clientWidth; - } - else { - if (stopAtContentEdge) - return kMin(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); - else - return ltr ? -clientWidth : -contentWidth; - } - } - else { - int contentHeight = m_layer->renderer()->lowestPosition(true, false) - - m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom(); - int clientHeight = m_layer->renderer()->clientHeight(); - if (dir == MUP) { - if (stopAtContentEdge) - return kMin(contentHeight - clientHeight, 0); - else - return -clientHeight; - } - else { - if (stopAtContentEdge) - return kMax(contentHeight - clientHeight, 0); - else - return contentHeight; - } - } -} - -void Marquee::start() -{ - if (m_timerId || m_layer->renderer()->style()->marqueeIncrement().value() == 0) - return; - - if (!m_suspended && !m_stopped) { - if (isUnfurlMarquee()) { - bool forward = direction() == MDOWN || direction() == MRIGHT; - bool isReversed = (forward && m_currentLoop % 2) || (!forward && !(m_currentLoop % 2)); - m_unfurlPos = isReversed ? m_end : m_start; - m_layer->renderer()->setChildNeedsLayout(true); - } - else { - if (isHorizontal()) - m_layer->scrollToOffset(m_start, 0, false, false); - else - m_layer->scrollToOffset(0, m_start, false, false); - } - } - else - m_suspended = false; - - m_stopped = false; - m_timerId = startTimer(speed()); -} - -void Marquee::suspend() -{ - if (m_timerId) { - killTimer(m_timerId); - m_timerId = 0; - } - - m_suspended = true; -} - -void Marquee::stop() -{ - if (m_timerId) { - killTimer(m_timerId); - m_timerId = 0; - } - - m_stopped = true; -} - -void Marquee::updateMarqueePosition() -{ - bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); - if (activate) { - if (isUnfurlMarquee()) { - if (m_unfurlPos < m_start) { - m_unfurlPos = m_start; - m_layer->renderer()->setChildNeedsLayout(true); - } - else if (m_unfurlPos > m_end) { - m_unfurlPos = m_end; - m_layer->renderer()->setChildNeedsLayout(true); - } - } - else { - EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior(); - m_start = computePosition(direction(), behavior == MALTERNATE); - m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE); - } - if (!m_stopped) start(); - } -} - -void Marquee::updateMarqueeStyle() -{ - RenderStyle* s = m_layer->renderer()->style(); - - if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops)) - m_currentLoop = 0; // When direction changes or our loopCount is a smaller number than our current loop, reset our loop. - - m_totalLoops = s->marqueeLoopCount(); - m_direction = s->marqueeDirection(); - m_whiteSpace = s->whiteSpace(); - - if (m_layer->renderer()->isHTMLMarquee()) { - // Hack for WinIE. In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do - // one loop. - if (m_totalLoops <= 0 && (s->marqueeBehavior() == MSLIDE || s->marqueeBehavior() == MUNFURL)) - m_totalLoops = 1; - - // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring - // all the text ends up on one line by default. Limit this hack to the <marquee> element to emulate - // WinIE's behavior. Someone using CSS3 can use white-space: nowrap on their own to get this effect. - // Second hack alert: Set the text-align back to auto. WinIE completely ignores text-align on the - // marquee element. - // FIXME: Bring these up with the CSS WG. - if (isHorizontal() && m_layer->renderer()->childrenInline()) { - s->setWhiteSpace(NOWRAP); - s->setTextAlign(TAAUTO); - } - } - - if (speed() != marqueeSpeed()) { - m_speed = marqueeSpeed(); - if (m_timerId) { - killTimer(m_timerId); - m_timerId = startTimer(speed()); - } - } - - // Check the loop count to see if we should now stop. - bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); - if (activate && !m_timerId) - m_layer->renderer()->setNeedsLayout(true); - else if (!activate && m_timerId) { - // Destroy the timer. - killTimer(m_timerId); - m_timerId = 0; - } -} - -void Marquee::timerEvent(TQTimerEvent* /*evt*/) -{ - if (m_layer->renderer()->needsLayout()) - return; - - if (m_reset) { - m_reset = false; - if (isHorizontal()) - m_layer->scrollToXOffset(m_start); - else - m_layer->scrollToYOffset(m_start); - return; - } - - RenderStyle* s = m_layer->renderer()->style(); - - int endPoint = m_end; - int range = m_end - m_start; - int newPos; - if (range == 0) - newPos = m_end; - else { - bool addIncrement = direction() == MUP || direction() == MLEFT; - bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2; - if (isUnfurlMarquee()) { - isReversed = (!addIncrement && m_currentLoop % 2) || (addIncrement && !(m_currentLoop % 2)); - addIncrement = !isReversed; - } - if (isReversed) { - // We're going in the reverse direction. - endPoint = m_start; - range = -range; - if (!isUnfurlMarquee()) - addIncrement = !addIncrement; - } - bool positive = range > 0; - int clientSize = isUnfurlMarquee() ? abs(range) : - (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight()); - int increment = kMax(1, abs(m_layer->renderer()->style()->marqueeIncrement().width(clientSize))); - int currentPos = isUnfurlMarquee() ? m_unfurlPos : - (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset()); - newPos = currentPos + (addIncrement ? increment : -increment); - if (positive) - newPos = kMin(newPos, endPoint); - else - newPos = kMax(newPos, endPoint); - } - - if (newPos == endPoint) { - m_currentLoop++; - if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) { - killTimer(m_timerId); - m_timerId = 0; - } - else if (s->marqueeBehavior() != MALTERNATE && s->marqueeBehavior() != MUNFURL) - m_reset = true; - } - - if (isUnfurlMarquee()) { - m_unfurlPos = newPos; - m_layer->renderer()->setChildNeedsLayout(true); - } - else { - if (isHorizontal()) - m_layer->scrollToXOffset(newPos); - else - m_layer->scrollToYOffset(newPos); - } -} - -#include "render_layer.moc" diff --git a/khtml/rendering/render_layer.h b/khtml/rendering/render_layer.h deleted file mode 100644 index a8f1e5adc..000000000 --- a/khtml/rendering/render_layer.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (C) 2003 Apple Computer, Inc. - * - * Portions are Copyright (C) 1998 Netscape Communications Corporation. - * - * Other contributors: - * Robert O'Callahan <roc+@cs.cmu.edu> - * David Baron <dbaron@fas.harvard.edu> - * Christian Biesinger <cbiesinger@web.de> - * Randall Jesup <rjesup@wgate.com> - * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> - * Josh Soref <timeless@mac.com> - * Boris Zbarsky <bzbarsky@mit.edu> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Alternatively, the contents of this file may be used under the terms - * of either the Mozilla Public License Version 1.1, found at - * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public - * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html - * (the "GPL"), in which case the provisions of the MPL or the GPL are - * applicable instead of those above. If you wish to allow use of your - * version of this file only under the terms of one of those two - * licenses (the MPL or the GPL) and not to allow others to use your - * version of this file under the LGPL, indicate your decision by - * deletingthe provisions above and replace them with the notice and - * other provisions required by the MPL or the GPL, as the case may be. - * If you do not delete the provisions above, a recipient may use your - * version of this file under any of the LGPL, the MPL or the GPL. - */ - -#ifndef render_layer_h -#define render_layer_h - -#include <tqcolor.h> -#include <tqrect.h> -#include <assert.h> - -#include "render_object.h" - -class TQScrollBar; -template <class T> class TQPtrVector; - -namespace khtml { - class RenderStyle; - class RenderTable; - class CachedObject; - class RenderCanvas; - class RenderText; - class RenderFrameSet; - class RenderObject; - class RenderScrollMediator; - -class RenderScrollMediator: public TQObject -{ - Q_OBJECT -public: - RenderScrollMediator(RenderLayer* layer) - :m_layer(layer) {} - -public slots: - void slotValueChanged(); - -private: - RenderLayer* m_layer; -}; - -// This class handles the auto-scrolling of layers with overflow: marquee. -class Marquee: public TQObject -{ - Q_OBJECT - -public: - Marquee(RenderLayer* l); - - void timerEvent(TQTimerEvent*); - - int speed() const { return m_speed; } - int marqueeSpeed() const; - EMarqueeDirection direction() const; - EMarqueeDirection reverseDirection() const { return static_cast<EMarqueeDirection>(-direction()); } - bool isHorizontal() const; - bool isUnfurlMarquee() const; - int unfurlPos() const { return m_unfurlPos; } - - EWhiteSpace whiteSpace() { return m_whiteSpace; } - - int computePosition(EMarqueeDirection dir, bool stopAtClientEdge); - - void setEnd(int end) { m_end = end; } - - void start(); - void suspend(); - void stop(); - - void updateMarqueeStyle(); - void updateMarqueePosition(); - -private: - RenderLayer* m_layer; - int m_currentLoop; - int m_totalLoops; - int m_timerId; - int m_start; - int m_end; - int m_speed; - int m_unfurlPos; - bool m_reset:1; - bool m_suspended:1; - bool m_stopped:1; - EWhiteSpace m_whiteSpace : 3; - EMarqueeDirection m_direction : 4; -}; - -class RenderLayer -{ -public: -#ifdef APPLE_CHANGES - static TQScrollBar* gScrollBar; -#endif - - RenderLayer(RenderObject* object); - ~RenderLayer(); - - RenderObject* renderer() const { return m_object; } - RenderLayer *parent() const { return m_parent; } - RenderLayer *previousSibling() const { return m_previous; } - RenderLayer *nextSibling() const { return m_next; } - - RenderLayer *firstChild() const { return m_first; } - RenderLayer *lastChild() const { return m_last; } - - void addChild(RenderLayer *newChild, RenderLayer* beforeChild = 0); - RenderLayer* removeChild(RenderLayer *oldChild); - - void removeOnlyThisLayer(); - void insertOnlyThisLayer(); - - void styleChanged(); - - Marquee* marquee() const { return m_marquee; } - void suspendMarquees(); - - bool isOverflowOnly() const { return m_isOverflowOnly; } - -#ifdef APPLE_CHANGES - bool isTransparent(); - RenderLayer* transparentAncestor(); -#endif - - RenderLayer* root() { - RenderLayer* curr = this; - while (curr->parent()) curr = curr->parent(); - return curr; - } - - int xPos() const { return m_x; } - int yPos() const { return m_y; } - - short width() const; - int height() const; - - short scrollWidth() const { return m_scrollWidth; } - int scrollHeight() const { return m_scrollHeight; } - - void resize( int w, int h ) { - m_scrollWidth = w; m_scrollHeight = h; - } - - void setPos( int xPos, int yPos ) { - m_x = xPos; - m_y = yPos; - } - - // Scrolling methods for layers that can scroll their overflow. - void scrollOffset(int& x, int& y); - void subtractScrollOffset(int& x, int& y); - void checkInlineRelOffset(const RenderObject* o, int& x, int& y); - short scrollXOffset() { return m_scrollX; } - int scrollYOffset() { return m_scrollY; } - void scrollToOffset(int x, int y, bool updateScrollbars = true, bool repaint = true); - void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); } - void scrollToYOffset(int y) { scrollToOffset(m_scrollX, y); } - void showScrollbar(Qt::Orientation, bool); - TQScrollBar* horizontalScrollbar() { return m_hBar; } - TQScrollBar* verticalScrollbar() { return m_vBar; } - int verticalScrollbarWidth(); - int horizontalScrollbarHeight(); - void positionScrollbars(const TQRect &damageRect); - void paintScrollbars(RenderObject::PaintInfo& pI); - void checkScrollbarsAfterLayout(); - void slotValueChanged(int); - void repaint(Priority p=NormalPriority, bool markForRepaint = false); - void updateScrollPositionFromScrollbars(); - - void updateLayerPosition(); - void updateLayerPositions( RenderLayer* rootLayer, bool doFullRepaint = false, bool checkForRepaint = false); - - // Get the enclosing stacking context for this layer. A stacking context is a layer - // that has a non-auto z-index. - RenderLayer* stackingContext() const; - bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isCanvas(); } - - void dirtyZOrderLists(); - void updateZOrderLists(); - TQPtrVector<RenderLayer>* posZOrderList() const { return m_posZOrderList; } - TQPtrVector<RenderLayer>* negZOrderList() const { return m_negZOrderList; } - - void dirtyOverflowList(); - void updateOverflowList(); - TQValueList<RenderLayer*>* overflowList() const { return m_overflowList; } - - void setHasOverlaidWidgets(bool b=true) { m_hasOverlaidWidgets = b; } - bool hasOverlaidWidgets() const { return m_hasOverlaidWidgets; } - TQRegion getMask() const { return m_region; } - TQRegion paintedRegion(RenderLayer* rootLayer); - void updateWidgetMasks(RenderLayer* rootLayer); - - // Gets the nearest enclosing positioned ancestor layer (also includes - // the <html> layer and the root layer). - RenderLayer* enclosingPositionedAncestor() const; - - void convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const; - - bool hasAutoZIndex() const { return renderer()->style()->hasAutoZIndex(); } - int zIndex() const { return renderer()->style()->zIndex(); } - - // The two main functions that use the layer system. The paint method - // paints the layers that intersect the damage rect from back to - // front. The nodeAtPoint method looks for mouse events by walking - // layers that intersect the point from front to back. - KDE_EXPORT void paint(TQPainter *p, const TQRect& damageRect, bool selectionOnly=false); - bool nodeAtPoint(RenderObject::NodeInfo& info, int x, int y); - - // This method figures out our layerBounds in coordinates relative to - // |rootLayer}. It also computes our background and foreground clip rects - // for painting/event handling. - void calculateRects(const RenderLayer* rootLayer, const TQRect& paintDirtyRect, TQRect& layerBounds, - TQRect& backgroundRect, TQRect& foregroundRect); - void calculateClipRects(const RenderLayer* rootLayer, TQRect& overflowClipRect, - TQRect& posClipRect, TQRect& fixedClipRect); - - bool intersectsDamageRect(const TQRect& layerBounds, const TQRect& damageRect) const; - bool containsPoint(int x, int y, const TQRect& damageRect) const; - - void updateHoverActiveState(RenderObject::NodeInfo& info); - - void detach(RenderArena* renderArena); - -#ifdef ENABLE_DUMP - KDE_EXPORT void dump(TQTextStream &stream, const TQString &ind = TQString::null); -#endif - - // Overloaded new operator. Derived classes must override operator new - // in order to allocate out of the RenderArena. - void* operator new(size_t sz, RenderArena* renderArena) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* ptr, size_t sz); - -private: - // The normal operator new is disallowed on all render objects. - void* operator new(size_t sz) throw(); - -private: - void setNextSibling(RenderLayer* next) { m_next = next; } - void setPreviousSibling(RenderLayer* prev) { m_previous = prev; } - void setParent(RenderLayer* parent) { m_parent = parent; } - void setFirstChild(RenderLayer* first) { m_first = first; } - void setLastChild(RenderLayer* last) { m_last = last; } - - void collectLayers(TQPtrVector<RenderLayer>*&, TQPtrVector<RenderLayer>*&); - - KDE_EXPORT void paintLayer(RenderLayer* rootLayer, TQPainter *p, const TQRect& paintDirtyRect, bool selectionOnly=false); - RenderLayer* nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info, - int x, int y, const TQRect& hitTestRect); - bool shouldBeOverflowOnly() const; - -protected: - RenderObject* m_object; - - RenderLayer* m_parent; - RenderLayer* m_previous; - RenderLayer* m_next; - - RenderLayer* m_first; - RenderLayer* m_last; - - // Our (x,y) coordinates are in our parent layer's coordinate space. - short m_x; - int m_y; - - // Our scroll offsets if the view is scrolled. - short m_scrollX; - int m_scrollY; - - // The width/height of our scrolled area. - short m_scrollWidth; - int m_scrollHeight; - - // For layers with overflow, we have a pair of scrollbars. - TQScrollBar* m_hBar; - TQScrollBar* m_vBar; - RenderScrollMediator* m_scrollMediator; - - // For layers that establish stacking contexts, m_posZOrderList holds a sorted list of all the - // descendant layers within the stacking context that have z-indices of 0 or greater - // (auto will count as 0). m_negZOrderList holds descendants within our stacking context with negative - // z-indices. - TQPtrVector<RenderLayer>* m_posZOrderList; - TQPtrVector<RenderLayer>* m_negZOrderList; - - // This list contains our overflow child layers. - TQValueList<RenderLayer*>* m_overflowList; - - bool m_zOrderListsDirty: 1; - bool m_overflowListDirty: 1; - bool m_isOverflowOnly: 1; - bool m_markedForRepaint: 1; - bool m_hasOverlaidWidgets: 1; - - TQRect m_visibleRect; - - TQRegion m_region; // used by overlaid (non z-order aware) widgets - - Marquee* m_marquee; // Used by layers with overflow:marquee -}; - -} // namespace -#endif diff --git a/khtml/rendering/render_line.cpp b/khtml/rendering/render_line.cpp deleted file mode 100644 index 2bcbe366e..000000000 --- a/khtml/rendering/render_line.cpp +++ /dev/null @@ -1,996 +0,0 @@ -/** -* This file is part of the html renderer for KDE. - * - * Copyright (C) 2003-2006 Apple Computer, Inc. - * (C) 2006 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 <kdebug.h> -#include <assert.h> -#include <tqpainter.h> -#include <kglobal.h> - -#include "rendering/render_flow.h" -#include "rendering/render_text.h" -#include "rendering/render_table.h" -#include "rendering/render_inline.h" -#include "rendering/render_block.h" -#include "rendering/render_arena.h" -#include "rendering/render_line.h" -#include "xml/dom_nodeimpl.h" -#include "xml/dom_docimpl.h" -#include "html/html_formimpl.h" -#include "misc/htmltags.h" -#include "khtmlview.h" - -using namespace DOM; -using namespace khtml; - -#ifndef NDEBUG -static bool inInlineBoxDetach; -#endif - -class khtml::EllipsisBox : public InlineBox -{ -public: - EllipsisBox(RenderObject* obj, const DOM::DOMString& ellipsisStr, InlineFlowBox* p, - int w, int y, int h, int b, bool firstLine, InlineBox* markupBox) - :InlineBox(obj), m_str(ellipsisStr) { - m_parent = p; - m_width = w; - m_y = y; - m_height = h; - m_baseline = b; - m_firstLine = firstLine; - m_constructed = true; - m_markupBox = markupBox; - } - - void paint(RenderObject::PaintInfo& i, int _tx, int _ty); - bool nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty); - -private: - DOM::DOMString m_str; - InlineBox* m_markupBox; -}; - -void InlineBox::detach(RenderArena* renderArena) -{ - if (m_parent) - m_parent->removeFromLine(this); -#ifndef NDEBUG - inInlineBoxDetach = true; -#endif - delete this; -#ifndef NDEBUG - inInlineBoxDetach = false; -#endif - - // Recover the size left there for us by operator delete and free the memory. - renderArena->free(*(size_t *)this, this); -} - -void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw() -{ - return renderArena->allocate(sz); -} - -void InlineBox::operator delete(void* ptr, size_t sz) -{ - assert(inInlineBoxDetach); - - // Stash size where detach can find it. - *(size_t *)ptr = sz; -} - -static bool needsOutlinePhaseRepaint(RenderObject* o, RenderObject::PaintInfo& i, int tx, int ty) { - if (o->style()->outlineWidth() <= 0) - return false; - TQRect r(tx+o->xPos(),ty+o->yPos(),o->width(),o->height()); - if (r.intersects(i.r)) - return false; - r.addCoords(-o->style()->outlineSize(), - -o->style()->outlineSize(), - o->style()->outlineSize(), - o->style()->outlineSize()); - if (!r.intersects(i.r)) - return false; - return true; -} - -void InlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - if ( i.phase == PaintActionOutline && !needsOutlinePhaseRepaint(object(), i, tx, ty) ) - return; - - // Paint all phases of replaced elements atomically, as though the replaced element established its - // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 - // specification.) - bool paintSelectionOnly = i.phase == PaintActionSelection; - RenderObject::PaintInfo info(i.p, i.r, paintSelectionOnly ? i.phase : PaintActionElementBackground); - object()->paint(info, tx, ty); - if (!paintSelectionOnly) { - info.phase = PaintActionChildBackgrounds; - object()->paint(info, tx, ty); - info.phase = PaintActionFloat; - object()->paint(info, tx, ty); - info.phase = PaintActionForeground; - object()->paint(info, tx, ty); - info.phase = PaintActionOutline; - object()->paint(info, tx, ty); - } -} - -bool InlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty) -{ - // Hit test all phases of replaced elements atomically, as though the replaced element established its - // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 - // specification.) - bool inside = false; - return object()->nodeAtPoint(i, x, y, tx, ty, HitTestAll, inside); // ### port hitTest -} - -RootInlineBox* InlineBox::root() -{ - if (m_parent) - return m_parent->root(); - return static_cast<RootInlineBox*>(this); -} - -InlineFlowBox::~InlineFlowBox() -{ - /* If we're destroyed, set the children free, and break their links */ - while (m_firstChild) - removeFromLine(m_firstChild); -} - -void InlineFlowBox::removeFromLine(InlineBox *child) -{ - if (child == m_firstChild) { - m_firstChild = child->nextOnLine(); - } - if (child == m_lastChild) { - m_lastChild = child->prevOnLine(); - } - if (child->nextOnLine()) { - child->nextOnLine()->m_prev = child->prevOnLine(); - } - if (child->prevOnLine()) { - child->prevOnLine()->m_next = child->nextOnLine(); - } - - child->setParent(0); -} - -bool InlineBox::canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth) -{ - // Non-replaced elements can always accommodate an ellipsis. - if (!m_object || !m_object->isReplaced()) - return true; - - TQRect boxRect(m_x, 0, m_width, 10); - TQRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10); - return !(boxRect.intersects(ellipsisRect)); -} - -int InlineBox::placeEllipsisBox(bool /*ltr*/, int /*blockEdge*/, int /*ellipsisWidth*/, bool&) -{ - // Use -1 to mean "we didn't set the position." - return -1; -} - -int InlineFlowBox::marginLeft() const -{ - if (!includeLeftEdge()) - return 0; - - RenderStyle* cstyle = object()->style(); - Length margin = cstyle->marginLeft(); - if (!margin.isVariable()) - return (margin.isFixed() ? margin.value() : object()->marginLeft()); - return 0; -} - -int InlineFlowBox::marginRight() const -{ - if (!includeRightEdge()) - return 0; - - RenderStyle* cstyle = object()->style(); - Length margin = cstyle->marginRight(); - if (!margin.isVariable()) - return (margin.isFixed() ? margin.value() : object()->marginRight()); - return 0; -} - -int InlineFlowBox::marginBorderPaddingLeft() const -{ - return marginLeft() + borderLeft() + paddingLeft(); -} - -int InlineFlowBox::marginBorderPaddingRight() const -{ - return marginRight() + borderRight() + paddingRight(); -} - -int InlineFlowBox::getFlowSpacingWidth() const -{ - int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight(); - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->isInlineFlowBox()) - totWidth += static_cast<InlineFlowBox*>(curr)->getFlowSpacingWidth(); - } - return totWidth; -} - -bool InlineFlowBox::nextOnLineExists() -{ - if (!parent()) - return false; - - if (nextOnLine()) - return true; - - return parent()->nextOnLineExists(); -} - -bool InlineFlowBox::prevOnLineExists() -{ - if (!parent()) - return false; - - if (prevOnLine()) - return true; - - return parent()->prevOnLineExists(); -} - -bool InlineFlowBox::onEndChain(RenderObject* endObject) -{ - if (!endObject) - return false; - - if (endObject == object()) - return true; - - RenderObject* curr = endObject; - RenderObject* parent = curr->parent(); - while (parent && !parent->isRenderBlock()) { - if (parent->lastChild() != curr || parent == object()) - return false; - - curr = parent; - parent = curr->parent(); - } - - return true; -} - -void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject) -{ - // All boxes start off open. They will not apply any margins/border/padding on - // any side. - bool includeLeftEdge = false; - bool includeRightEdge = false; - - RenderFlow* flow = static_cast<RenderFlow*>(object()); - - if (!flow->firstChild()) - includeLeftEdge = includeRightEdge = true; // Empty inlines never split across lines. - else if (parent()) { // The root inline box never has borders/margins/padding. - bool ltr = flow->style()->direction() == LTR; - - // Check to see if all initial lines are unconstructed. If so, then - // we know the inline began on this line. - if (!flow->firstLineBox()->isConstructed()) { - if (ltr && flow->firstLineBox() == this) - includeLeftEdge = true; - else if (!ltr && flow->lastLineBox() == this) - includeRightEdge = true; - } - - // In order to determine if the inline ends on this line, we check three things: - // (1) If we are the last line and we don't have a continuation(), then we can - // close up. - // (2) If the last line box for the flow has an object following it on the line (ltr, - // reverse for rtl), then the inline has closed. - // (3) The line may end on the inline. If we are the last child (climbing up - // the end object's chain), then we just closed as well. - if (!flow->lastLineBox()->isConstructed()) { - if (ltr) { - if (!nextLineBox() && - ((lastLine && !object()->continuation()) || nextOnLineExists() - || onEndChain(endObject))) - includeRightEdge = true; - } - else { - if ((!prevLineBox() || !prevLineBox()->isConstructed()) && - ((lastLine && !object()->continuation()) || - prevOnLineExists() || onEndChain(endObject))) - includeLeftEdge = true; - } - - } - } - - setEdges(includeLeftEdge, includeRightEdge); - - // Recur into our children. - for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) { - if (currChild->isInlineFlowBox()) { - InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild); - currFlow->determineSpacingForFlowBoxes(lastLine, endObject); - } - } -} - -int InlineFlowBox::placeBoxesHorizontally(int x) -{ - // Set our x position. - setXPos(x); - - int startX = x; - x += borderLeft() + paddingLeft(); - - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isText()) { - InlineTextBox* text = static_cast<InlineTextBox*>(curr); - text->setXPos(x); - x += curr->width(); - } - else { - if (curr->object()->isPositioned()) { - if (curr->object()->parent()->style()->direction() == LTR) - curr->setXPos(x); - else { - // Our offset that we cache needs to be from the edge of the right border box and - // not the left border box. We have to subtract |x| from the width of the block - // (which can be obtained by walking up to the root line box). - InlineBox* root = this; - while (!root->isRootInlineBox()) - root = root->parent(); - curr->setXPos(root->object()->width()-x); - } - continue; // The positioned object has no effect on the width. - } - if (curr->object()->isInlineFlow()) { - InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); - x += flow->marginLeft(); - x = flow->placeBoxesHorizontally(x); - x += flow->marginRight(); - } - else { - x += curr->object()->marginLeft(); - curr->setXPos(x); - x += curr->width() + curr->object()->marginRight(); - } - } - } - - x += borderRight() + paddingRight(); - setWidth(x-startX); - return x; -} - -void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) -{ - int maxPositionTop = 0; - int maxPositionBottom = 0; - int maxAscent = 0; - int maxDescent = 0; - - // Figure out if we're in strict mode. - RenderObject* curr = object(); - while (curr && !curr->element()) - curr = curr->container(); - bool strictMode = (curr && curr->element()->getDocument()->inStrictMode()); - - computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); - - if (maxAscent + maxDescent < kMax(maxPositionTop, maxPositionBottom)) - adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); - - int maxHeight = maxAscent + maxDescent; - int topPosition = heightOfBlock; - int bottomPosition = heightOfBlock; - placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition); - - setOverflowPositions(topPosition, bottomPosition); - - // Shrink boxes with no text children in quirks and almost strict mode. - if (!strictMode) - shrinkBoxesWithNoTextChildren(topPosition, bottomPosition); - - heightOfBlock += maxHeight; -} - -void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, - int maxPositionTop, int maxPositionBottom) -{ - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - // The computed lineheight needs to be extended for the - // positioned elements - // see khtmltests/rendering/html_align.html - - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - if (curr->yPos() == PositionTop || curr->yPos() == PositionBottom) { - if (curr->yPos() == PositionTop) { - if (maxAscent + maxDescent < curr->height()) - maxDescent = curr->height() - maxAscent; - } - else { - if (maxAscent + maxDescent < curr->height()) - maxAscent = curr->height() - maxDescent; - } - - if ( maxAscent + maxDescent >= kMax( maxPositionTop, maxPositionBottom ) ) - break; - } - - if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); - } -} - -void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, - int& maxAscent, int& maxDescent, bool strictMode) -{ - if (isRootInlineBox()) { - // Examine our root box. - setHeight(object()->lineHeight(m_firstLine)); - bool isTableCell = object()->isTableCell(); - if (isTableCell) { - RenderTableCell* tableCell = static_cast<RenderTableCell*>(object()); - setBaseline(tableCell->RenderBlock::baselinePosition(m_firstLine)); - } - else - setBaseline(object()->baselinePosition(m_firstLine)); - if (hasTextChildren() || strictMode) { - int ascent = baseline(); - int descent = height() - ascent; - if (maxAscent < ascent) - maxAscent = ascent; - if (maxDescent < descent) - maxDescent = descent; - } - } - - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - curr->setHeight(curr->object()->lineHeight(m_firstLine)); - curr->setBaseline(curr->object()->baselinePosition(m_firstLine)); - curr->setYPos(curr->object()->verticalPositionHint(m_firstLine)); - if (curr->yPos() == PositionTop) { - if (maxPositionTop < curr->height()) - maxPositionTop = curr->height(); - } - else if (curr->yPos() == PositionBottom) { - if (maxPositionBottom < curr->height()) - maxPositionBottom = curr->height(); - } - else if (curr->hasTextChildren() || strictMode) { - int ascent = curr->baseline() - curr->yPos(); - int descent = curr->height() - ascent; - if (maxAscent < ascent) - maxAscent = ascent; - if (maxDescent < descent) - maxDescent = descent; - } - - if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); - } -} - -void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, - int& topPosition, int& bottomPosition) -{ - if (isRootInlineBox()) { - setYPos(y + maxAscent - baseline());// Place our root box. - // CSS2: 10.8.1 - line-height on the block level element specifies the *minimum* - // height of the generated line box - if (hasTextChildren() && maxHeight < object()->lineHeight(m_firstLine)) - maxHeight = object()->lineHeight(m_firstLine); - } - - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - // Adjust boxes to use their real box y/height and not the logical height (as dictated by - // line-height). - if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(y, maxHeight, maxAscent, strictMode, - topPosition, bottomPosition); - - bool childAffectsTopBottomPos = true; - - if (curr->yPos() == PositionTop) - curr->setYPos(y); - else if (curr->yPos() == PositionBottom) - curr->setYPos(y + maxHeight - curr->height()); - else { - if (!strictMode && !curr->hasTextDescendant()) - childAffectsTopBottomPos = false; - curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline()); - } - int newY = curr->yPos(); - int newHeight = curr->height(); - int newBaseline = curr->baseline(); - int overflowTop = 0; - int overflowBottom = 0; - if (curr->isInlineTextBox() || curr->isInlineFlowBox()) { - const TQFontMetrics &fm = curr->object()->fontMetrics( m_firstLine ); -#ifdef APPLE_CHANGES - newBaseline = fm.ascent(); - newY += curr->baseline() - newBaseline; - newHeight = newBaseline+fm.descent(); -#else - // only adjust if the leading delta is superior to the font's natural leading - if ( kAbs(fm.ascent() - curr->baseline()) > fm.leading()/2 ) { - int ascent = fm.ascent()+fm.leading()/2; - newBaseline = ascent; - newY += curr->baseline() - newBaseline; - newHeight = fm.lineSpacing(); - } -#endif - for (ShadowData* shadow = curr->object()->style()->textShadow(); shadow; shadow = shadow->next) { - overflowTop = kMin(overflowTop, shadow->y - shadow->blur); - overflowBottom = kMax(overflowBottom, shadow->y + shadow->blur); - } - if (curr->isInlineFlowBox()) { - newHeight += curr->object()->borderTop() + curr->object()->paddingTop() + - curr->object()->borderBottom() + curr->object()->paddingBottom(); - newY -= curr->object()->borderTop() + curr->object()->paddingTop(); - newBaseline += curr->object()->borderTop() + curr->object()->paddingTop(); - } - } else { - newY += curr->object()->marginTop(); - newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom()); - overflowTop = curr->object()->overflowTop(); - overflowBottom = curr->object()->overflowHeight() - newHeight; - } - curr->setYPos(newY); - curr->setHeight(newHeight); - curr->setBaseline(newBaseline); - - if (childAffectsTopBottomPos) { - topPosition = kMin(topPosition, newY + overflowTop); - bottomPosition = kMax(bottomPosition, newY + newHeight + overflowBottom); - } - } - - if (isRootInlineBox()) { - const TQFontMetrics &fm = object()->fontMetrics( m_firstLine ); -#ifdef APPLE_CHANGES - setHeight(fm.ascent()+fm.descent()); - setYPos(yPos() + baseline() - fm.ascent()); - setBaseline(fm.ascent()); -#else - if ( kAbs(fm.ascent() - baseline()) > fm.leading()/2 ) { - int ascent = fm.ascent()+fm.leading()/2; - setHeight(fm.lineSpacing()); - setYPos(yPos() + baseline() - ascent); - setBaseline(ascent); - } -#endif - if (hasTextDescendant() || strictMode) { - if (yPos() < topPosition) - topPosition = yPos(); - if (yPos() + height() > bottomPosition) - bottomPosition = yPos() + height(); - } - } -} - -void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos) -{ - // First shrink our kids. - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos); - } - - // See if we have text children. If not, then we need to shrink ourselves to fit on the line. - if (!hasTextDescendant()) { - if (yPos() < topPos) - setYPos(topPos); - if (yPos() + height() > bottomPos) - setHeight(bottomPos - yPos()); - if (baseline() > height()) - setBaseline(height()); - } -} - -bool InlineFlowBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty) -{ - // Check children first. - for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if (!curr->object()->layer() && curr->nodeAtPoint(i, x, y, tx, ty)) { - object()->setInnerNode(i); - return true; - } - } - - // Now check ourselves. - TQRect rect(tx + m_x, ty + m_y, m_width, m_height); - if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) { - object()->setInnerNode(i); - return true; - } - - return false; -} - - -void InlineFlowBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - bool intersectsDamageRect = true; - int xPos = tx + m_x - object()->maximalOutlineSize(i.phase); - int w = width() + 2 * object()->maximalOutlineSize(i.phase); - if ((xPos >= i.r.x() + i.r.width()) || (xPos + w <= i.r.x())) - intersectsDamageRect = false; - - if (intersectsDamageRect) { - if (i.phase == PaintActionOutline) { - // Add ourselves to the paint info struct's list of inlines that need to paint their - // outlines. - if (object()->style()->visibility() == VISIBLE && object()->style()->outlineWidth() > 0 && - !object()->isInlineContinuation() && !isRootInlineBox()) { - if (!i.outlineObjects) - i.outlineObjects = new TQValueList<RenderFlow*>; - i.outlineObjects->append(static_cast<RenderFlow*>(object())); - } - } - else { - // 1. Paint our background and border. - paintBackgroundAndBorder(i, tx, ty); - - // 2. Paint our underline and overline. - paintDecorations(i, tx, ty, false); - } - } - - // 3. Paint our children. - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (!curr->object()->layer()) - curr->paint(i, tx, ty); - } - - // 4. Paint our strike-through - if (intersectsDamageRect && i.phase != PaintActionOutline) - paintDecorations(i, tx, ty, true); -} - - -void InlineFlowBox::paintBackgrounds(TQPainter* p, const TQColor& c, const BackgroundLayer* bgLayer, - int my, int mh, int _tx, int _ty, int w, int h) -{ - if (!bgLayer) - return; - paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h); - paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h); -} - -void InlineFlowBox::paintBackground(TQPainter* p, const TQColor& c, const BackgroundLayer* bgLayer, - int my, int mh, int _tx, int _ty, int w, int h) -{ - CachedImage* bg = bgLayer->backgroundImage(); - bool hasBackgroundImage = bg && (bg->pixmap_size() == bg->valid_rect().size()) && - !bg->isTransparent() && !bg->isErrorImage(); - if (!hasBackgroundImage || (!prevLineBox() && !nextLineBox()) || !parent()) - object()->paintBackgroundExtended(p, c, bgLayer, my, mh, _tx, _ty, w, h, borderLeft(), borderRight(), paddingLeft(), paddingRight()); - else { - // We have a background image that spans multiple lines. - // We need to adjust _tx and _ty by the width of all previous lines. - // Think of background painting on inlines as though you had one long line, a single continuous - // strip. Even though that strip has been broken up across multiple lines, you still paint it - // as though you had one single line. This means each line has to pick up the background where - // the previous line left off. - // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, - // but it isn't even clear how this should work at all. - int xOffsetOnLine = 0; - for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) - xOffsetOnLine += curr->width(); - int startX = _tx - xOffsetOnLine; - int totalWidth = xOffsetOnLine; - for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) - totalWidth += curr->width(); - p->save(); - p->setClipRect(TQRect(_tx, _ty, width(), height()), TQPainter::CoordPainter); - object()->paintBackgroundExtended(p, c, bgLayer, my, mh, startX, _ty, - totalWidth, h, borderLeft(), borderRight(), paddingLeft(), paddingRight()); - p->restore(); - } -} - -void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& pI, int _tx, int _ty) -{ - if (object()->style()->visibility() != VISIBLE || pI.phase != PaintActionForeground) - return; - - // Move x/y to our coordinates. - _tx += m_x; - _ty += m_y; - - int w = width(); - int h = height(); - - int my = kMax(_ty, pI.r.y()); - int mh; - if (_ty<pI.r.y()) - mh= kMax(0,h-(pI.r.y()-_ty)); - else - mh = kMin(pI.r.height(),h); - - // You can use p::first-line to specify a background. If so, the root line boxes for - // a line may actually have to paint a background. - RenderStyle* styleToUse = object()->style(m_firstLine); - if ((!parent() && m_firstLine && styleToUse != object()->style()) || - (parent() && object()->shouldPaintBackgroundOrBorder())) { - TQColor c = styleToUse->backgroundColor(); - paintBackgrounds(pI.p, c, styleToUse->backgroundLayers(), my, mh, _tx, _ty, w, h); - - // :first-line cannot be used to put borders on a line. Always paint borders with our - // non-first-line style. - if (parent() && object()->style()->hasBorder()) - object()->paintBorder(pI.p, _tx, _ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge()); - } -} - -static bool shouldDrawDecoration(RenderObject* obj) -{ - bool shouldDraw = false; - for (RenderObject* curr = obj->firstChild(); - curr; curr = curr->nextSibling()) { - if (curr->isInlineFlow()) { - shouldDraw = true; - break; - } - else if (curr->isText() && !curr->isBR() && (curr->style()->preserveWS() || - !curr->element() || !curr->element()->containsOnlyWhitespace())) { - shouldDraw = true; - break; - } - } - return shouldDraw; -} - -void InlineFlowBox::paintDecorations(RenderObject::PaintInfo& pI, int _tx, int _ty, bool paintedChildren) -{ - // Now paint our text decorations. We only do this if we aren't in quirks mode (i.e., in - // almost-strict mode or strict mode). - if (object()->style()->htmlHacks() || object()->style()->visibility() != VISIBLE) - return; - - _tx += m_x; - _ty += m_y; - RenderStyle* styleToUse = object()->style(m_firstLine); - int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect(); - if (deco != TDNONE && - ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) && - shouldDrawDecoration(object())) { - // We must have child boxes and have decorations defined. - _tx += borderLeft() + paddingLeft(); - int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight()); - if ( !w ) - return; - const TQFontMetrics &fm = object()->fontMetrics( m_firstLine ); - // thick lines on small fonts look ugly - int thickness = fm.height() > 20 ? fm.lineWidth() : 1; - TQColor underline, overline, linethrough; - underline = overline = linethrough = styleToUse->color(); - if (!parent()) - object()->getTextDecorationColors(deco, underline, overline, linethrough); - - if (styleToUse->font() != pI.p->font()) - pI.p->setFont(styleToUse->font()); - - if (deco & UNDERLINE && !paintedChildren) { - int underlineOffset = ( fm.height() + m_baseline ) / 2; - if (underlineOffset <= m_baseline) underlineOffset = m_baseline+1; - - pI.p->fillRect(_tx, _ty + underlineOffset, w, thickness, underline ); - } - if (deco & OVERLINE && !paintedChildren) { - pI.p->fillRect(_tx, _ty, w, thickness, overline ); - } - if (deco & LINE_THROUGH && paintedChildren) { - pI.p->fillRect(_tx, _ty + 2*m_baseline/3, w, thickness, linethrough ); - } - } -} - -bool InlineFlowBox::canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth) -{ - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { - if (!box->canAccommodateEllipsisBox(ltr, blockEdge, ellipsisWidth)) - return false; - } - return true; -} - -int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) -{ - int result = -1; - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { - int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); - if (currResult != -1 && result == -1) - result = currResult; - } - return result; -} - -void InlineFlowBox::clearTruncation() -{ - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) - box->clearTruncation(); -} - -void EllipsisBox::paint(RenderObject::PaintInfo& i, int _tx, int _ty) -{ - TQPainter* p = i.p; - RenderStyle* _style = m_firstLine ? m_object->style(true) : m_object->style(); - if (_style->font() != p->font()) - p->setFont(_style->font()); - - const Font* font = &_style->htmlFont(); - TQColor textColor = _style->color(); - if (textColor != p->pen().color()) - p->setPen(textColor); - /* - bool setShadow = false; - if (_style->textShadow()) { - p->setShadow(_style->textShadow()->x, _style->textShadow()->y, - _style->textShadow()->blur, _style->textShadow()->color); - setShadow = true; - }*/ - - const DOMString& str = m_str.string(); - font->drawText(p, m_x + _tx, - m_y + _ty + m_baseline, - (str.implementation())->s, - str.length(), 0, str.length(), - 0, - TQPainter::LTR, _style->visuallyOrdered()); - - /* - if (setShadow) - p->clearShadow(); - */ - - if (m_markupBox) { - // Paint the markup box - _tx += m_x + m_width - m_markupBox->xPos(); - _ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline()); - m_markupBox->object()->paint(i, _tx, _ty); - } -} - -bool EllipsisBox::nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty) -{ - // Hit test the markup box. - if (m_markupBox) { - _tx += m_x + m_width - m_markupBox->xPos(); - _ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline()); - if (m_markupBox->nodeAtPoint(info, _x, _y, _tx, _ty)) { - object()->setInnerNode(info); - return true; - } - } - - TQRect rect(_tx + m_x, _ty + m_y, m_width, m_height); - if (object()->style()->visibility() == VISIBLE && rect.contains(_x, _y)) { - object()->setInnerNode(info); - return true; - } - return false; -} - -void RootInlineBox::detach(RenderArena* arena) -{ - detachEllipsisBox(arena); - InlineFlowBox::detach(arena); -} - -void RootInlineBox::detachEllipsisBox(RenderArena* arena) -{ - if (m_ellipsisBox) { - m_ellipsisBox->detach(arena); - m_ellipsisBox = 0; - } -} - -void RootInlineBox::clearTruncation() -{ - if (m_ellipsisBox) { - detachEllipsisBox(m_object->renderArena()); - InlineFlowBox::clearTruncation(); - } -} - -bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth) -{ - // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room. - int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge; - if (width() - delta < ellipsisWidth) - return false; - - // Next iterate over all the line boxes on the line. If we find a replaced element that intersects - // then we refuse to accommodate the ellipsis. Otherwise we're ok. - return InlineFlowBox::canAccommodateEllipsisBox(ltr, blockEdge, ellipsisWidth); -} - -void RootInlineBox::placeEllipsis(const DOMString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, InlineBox* markupBox) -{ - // Create an ellipsis box. - m_ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this, - ellipsisWidth - (markupBox ? markupBox->width() : 0), - yPos(), height(), baseline(), !prevRootBox(), - markupBox); - - if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) { - m_ellipsisBox->m_x = xPos() + width(); - return; - } - - // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL) - // of that glyph. Mark all of the objects that intersect the ellipsis box as not painting (as being - // truncated). - bool foundBox = false; - m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); -} - -int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) -{ - int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); - if (result == -1) - result = ltr ? blockEdge - ellipsisWidth : blockEdge; - return result; -} - -void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& i, int _tx, int _ty) const -{ - if (m_ellipsisBox) - m_ellipsisBox->paint(i, _tx, _ty); -} - -void RootInlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - InlineFlowBox::paint(i, tx, ty); - paintEllipsisBox(i, tx, ty); -} - -bool RootInlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty) -{ - if (m_ellipsisBox && object()->style()->visibility() == VISIBLE) { - if (m_ellipsisBox->nodeAtPoint(i, x, y, tx, ty)) { - object()->setInnerNode(i); - return true; - } - } - return InlineFlowBox::nodeAtPoint(i, x, y, tx, ty); -} - diff --git a/khtml/rendering/render_line.h b/khtml/rendering/render_line.h deleted file mode 100644 index d42f2acb8..000000000 --- a/khtml/rendering/render_line.h +++ /dev/null @@ -1,310 +0,0 @@ -/* - * This file is part of the line box implementation for KDE. - * - * Copyright (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -#ifndef RENDER_LINE_H -#define RENDER_LINE_H - -namespace khtml { - -class EllipsisBox; -class InlineFlowBox; -class RootInlineBox; - -// InlineBox represents a rectangle that occurs on a line. It corresponds to -// some RenderObject (i.e., it represents a portion of that RenderObject). -class InlineBox -{ -public: - InlineBox(RenderObject* obj) - :m_object(obj), m_x(0), m_width(0), m_y(0), m_height(0), m_baseline(0), - m_firstLine(false), m_constructed(false) - { - m_next = 0; - m_prev = 0; - m_parent = 0; - } - - virtual ~InlineBox() {} - - void detach(RenderArena* renderArena); - - virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty); - virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty); - - // Overloaded new operator. - void* operator new(size_t sz, RenderArena* renderArena) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* ptr, size_t sz); - -private: - // The normal operator new is disallowed. - void* operator new(size_t sz) throw(); - -public: - virtual bool isInlineBox() const { return false; } - virtual bool isInlineFlowBox() const { return false; } - virtual bool isContainer() const { return false; } - virtual bool isInlineTextBox() const { return false; } - virtual bool isRootInlineBox() const { return false; } - - bool isConstructed() const { return m_constructed; } - virtual void setConstructed() { - m_constructed = true; - if (m_next) - m_next->setConstructed(); - } - - void setFirstLineStyleBit(bool f) { m_firstLine = f; } - - InlineBox* nextOnLine() { return m_next; } - InlineBox* prevOnLine() { return m_prev; } - RenderObject* object() const { return m_object; } - - InlineFlowBox* parent() { return m_parent; } - void setParent(InlineFlowBox* par) { m_parent = par; } - - RootInlineBox* root(); - - void setWidth(short w) { m_width = w; } - short width() const { return m_width; } - - void setXPos(short x) { m_x = x; } - short xPos() const { return m_x; } - - void setYPos(int y) { m_y = y; } - int yPos() const { return m_y; } - - void setHeight(int h) { m_height = h; } - int height() const { return m_height; } - - void setBaseline(int b) { m_baseline = b; } - int baseline() const { return m_baseline; } - - virtual bool hasTextChildren() const { return true; } - virtual bool hasTextDescendant() const { return true; } - - virtual int topOverflow() const { return yPos(); } - virtual int bottomOverflow() const { return yPos()+height(); } - - virtual long minOffset() const { return 0; } - virtual long maxOffset() const { return 0; } - - virtual void clearTruncation() {}; - - virtual bool canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth); - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&); - -public: // FIXME: Would like to make this protected, but methods are accessing these - // members over in the part. - RenderObject* m_object; - - short m_x; - short m_width; - int m_y; - int m_height; - int m_baseline; - - bool m_firstLine : 1; - bool m_constructed : 1; - - InlineBox* m_next; // The next element on the same line as us. - InlineBox* m_prev; // The previous element on the same line as us. - - InlineFlowBox* m_parent; // The box that contains us. -}; - -class InlineRunBox : public InlineBox -{ -public: - InlineRunBox(RenderObject* obj) - :InlineBox(obj) - { - m_prevLine = 0; - m_nextLine = 0; - } - - InlineRunBox* prevLineBox() { return m_prevLine; } - InlineRunBox* nextLineBox() { return m_nextLine; } - void setNextLineBox(InlineRunBox* n) { m_nextLine = n; } - void setPreviousLineBox(InlineRunBox* p) { m_prevLine = p; } - - virtual void paintBackgroundAndBorder(RenderObject::PaintInfo&, int /*_tx*/, int /*_ty*/) {} - virtual void paintDecorations(RenderObject::PaintInfo&, int /*_tx*/, int /*_ty*/, bool /*paintedChildren*/ = false) {} - -protected: - InlineRunBox* m_prevLine; // The previous box that also uses our RenderObject - InlineRunBox* m_nextLine; // The next box that also uses our RenderObject -}; - -class InlineFlowBox : public InlineRunBox -{ -public: - InlineFlowBox(RenderObject* obj) - :InlineRunBox(obj) - { - m_firstChild = 0; - m_lastChild = 0; - m_includeLeftEdge = m_includeRightEdge = false; - m_hasTextChildren = false; - m_hasTextDescendant = false; - m_afterPageBreak = false; - } - - ~InlineFlowBox(); - - virtual bool isInlineFlowBox() const { return true; } - - InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); } - InlineFlowBox* nextFlowBox() const { return static_cast<InlineFlowBox*>(m_nextLine); } - - InlineBox* firstChild() const { return m_firstChild; } - InlineBox* lastChild() const { return m_lastChild; } - - virtual void setConstructed() { - InlineBox::setConstructed(); - if (m_firstChild) - m_firstChild->setConstructed(); - } - void addToLine(InlineBox* child) { - if (!m_firstChild) - m_firstChild = m_lastChild = child; - else { - m_lastChild->m_next = child; - child->m_prev = m_lastChild; - m_lastChild = child; - } - child->setFirstLineStyleBit(m_firstLine); - child->setParent(this); - if (!m_hasTextChildren && child->isInlineTextBox()) { - m_hasTextDescendant = m_hasTextChildren = true; - for (InlineFlowBox* p = m_parent; p && !p->hasTextDescendant(); p = p->parent()) - p->m_hasTextDescendant = true; - } - } - - virtual void clearTruncation(); - - void removeFromLine(InlineBox* child); - virtual void paintBackgroundAndBorder(RenderObject::PaintInfo&, int _tx, int _ty); - void paintBackgrounds(TQPainter* p, const TQColor& c, const BackgroundLayer* bgLayer, - int my, int mh, int _tx, int _ty, int w, int h); - void paintBackground(TQPainter* p, const TQColor& c, const BackgroundLayer* bgLayer, - int my, int mh, int _tx, int _ty, int w, int h); - virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty); - virtual void paintDecorations(RenderObject::PaintInfo&, int _tx, int _ty, bool paintedChildren = false); - virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty); - - int marginBorderPaddingLeft() const; - int marginBorderPaddingRight() const; - int marginLeft() const; - int marginRight( )const; - int borderLeft() const { if (includeLeftEdge()) return object()->borderLeft(); return 0; } - int borderRight() const { if (includeRightEdge()) return object()->borderRight(); return 0; } - int paddingLeft() const { if (includeLeftEdge()) return object()->paddingLeft(); return 0; } - int paddingRight() const { if (includeRightEdge()) return object()->paddingRight(); return 0; } - - bool includeLeftEdge() const { return m_includeLeftEdge; } - bool includeRightEdge() const { return m_includeRightEdge; } - void setEdges(bool includeLeft, bool includeRight) { - m_includeLeftEdge = includeLeft; - m_includeRightEdge = includeRight; - } - virtual bool hasTextChildren() const { return m_hasTextChildren; } - bool hasTextDescendant() const { return m_hasTextDescendant; } - - // Helper functions used during line construction and placement. - void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject); - int getFlowSpacingWidth() const; - bool nextOnLineExists(); - bool prevOnLineExists(); - bool onEndChain(RenderObject* endObject); - int placeBoxesHorizontally(int x); - void verticallyAlignBoxes(int& heightOfBlock); - void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, - int& maxAscent, int& maxDescent, bool strictMode); - void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, - int maxPositionTop, int maxPositionBottom); - void placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, - int& topPosition, int& bottomPosition); - void shrinkBoxesWithNoTextChildren(int topPosition, int bottomPosition); - - virtual void setOverflowPositions(int /*top*/, int /*bottom*/) {} - - void setAfterPageBreak(bool b = true) { m_afterPageBreak = b; } - bool afterPageBreak() const { return m_afterPageBreak; } - - virtual bool canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth); - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&); - -protected: - InlineBox* m_firstChild; - InlineBox* m_lastChild; - bool m_includeLeftEdge : 1; - bool m_includeRightEdge : 1; - bool m_hasTextChildren : 1; - bool m_hasTextDescendant : 1; - bool m_afterPageBreak : 1; -}; - -class RootInlineBox : public InlineFlowBox -{ -public: - RootInlineBox(RenderObject* obj) : InlineFlowBox(obj), m_ellipsisBox(0) - { - m_topOverflow = m_bottomOverflow = 0; - } - - virtual void detach(RenderArena* renderArena); - void detachEllipsisBox(RenderArena* renderArena); - - RootInlineBox* nextRootBox() { return static_cast<RootInlineBox*>(m_nextLine); } - RootInlineBox* prevRootBox() { return static_cast<RootInlineBox*>(m_prevLine); } - - virtual bool isRootInlineBox() const { return true; } - virtual int topOverflow() const { return m_topOverflow; } - virtual int bottomOverflow() const { return m_bottomOverflow; } - virtual void setOverflowPositions(int top, int bottom) { m_topOverflow = top; m_bottomOverflow = bottom; } - - bool canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth); - void placeEllipsis(const DOM::DOMString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, InlineBox* markupBox = 0); - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&); - - EllipsisBox* ellipsisBox() const { return m_ellipsisBox; } - void paintEllipsisBox(RenderObject::PaintInfo& i, int _tx, int _ty) const; - bool hitTestEllipsisBox(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty); - - virtual void clearTruncation(); - - virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty); - virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty); - -protected: - int m_topOverflow; - int m_bottomOverflow; - - // An inline text box that represents our text truncation string. - EllipsisBox* m_ellipsisBox; -}; - -} //namespace - -#endif diff --git a/khtml/rendering/render_list.cpp b/khtml/rendering/render_list.cpp deleted file mode 100644 index 769b79670..000000000 --- a/khtml/rendering/render_list.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/** - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2002 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, Inc. - * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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 "rendering/render_list.h" -#include "rendering/render_canvas.h" -#include "rendering/enumerate.h" -#include "rendering/counter_tree.h" -#include "html/html_listimpl.h" -#include "misc/helper.h" -#include "misc/htmltags.h" -#include "misc/loader.h" -#include "xml/dom_docimpl.h" - -#include <kdebug.h> -#include <kglobal.h> -#include <tqvaluelist.h> - -//#define BOX_DEBUG - -using namespace khtml; -using namespace Enumerate; - -const int cMarkerPadding = 7; - -// ------------------------------------------------------------------------- - -RenderListItem::RenderListItem(DOM::NodeImpl* node) - : RenderBlock(node) -{ - // init RenderObject attributes - setInline(false); // our object is not Inline - - predefVal = -1; - m_marker = 0; - m_counter = 0; - m_insideList = false; - m_deleteMarker = false; -} - -void RenderListItem::setStyle(RenderStyle *_style) -{ - RenderBlock::setStyle(_style); - - RenderStyle *newStyle = new RenderStyle(); - newStyle->ref(); - - newStyle->inheritFrom(style()); - - if(!m_marker && style()->listStyleType() != LNONE) { - m_marker = new (renderArena()) RenderListMarker(element()); - m_marker->setIsAnonymous( true ); - m_marker->setStyle(newStyle); - m_marker->setListItem( this ); - m_deleteMarker = true; - } else if ( m_marker && style()->listStyleType() == LNONE) { - m_marker->detach(); - m_marker = 0; - } - else if ( m_marker ) { - m_marker->setStyle(newStyle); - } - - newStyle->deref(); -} - -void RenderListItem::detach() -{ - if ( m_marker && m_deleteMarker ) - m_marker->detach(); - RenderBlock::detach(); -} - -static RenderObject* getParentOfFirstLineBox(RenderObject* curr, RenderObject* marker) -{ - RenderObject* firstChild = curr->firstChild(); - if (!firstChild) - return 0; - - for (RenderObject* currChild = firstChild; - currChild; currChild = currChild->nextSibling()) { - if (currChild == marker) - continue; - - if (currChild->isInline()) - return curr; - - if (currChild->isFloating() || currChild->isPositioned()) - continue; - - if (currChild->isTable() || !currChild->isRenderBlock()) - break; - - if (currChild->style()->htmlHacks() && currChild->element() && - (currChild->element()->id() == ID_UL || currChild->element()->id() == ID_OL)) - break; - - RenderObject* lineBox = getParentOfFirstLineBox(currChild, marker); - if (lineBox) - return lineBox; - } - - return 0; -} - - -void RenderListItem::updateMarkerLocation() -{ - // Sanity check the location of our marker. - if (m_marker) { - RenderObject* markerPar = m_marker->parent(); - RenderObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); - if (!lineBoxParent) { - // If the marker is currently contained inside an anonymous box, - // then we are the only item in that anonymous box (since no line box - // parent was found). It's ok to just leave the marker where it is - // in this case. - if (markerPar && markerPar->isAnonymousBlock()) - lineBoxParent = markerPar; - else - lineBoxParent = this; - } - if (markerPar != lineBoxParent) - { - if (markerPar) - markerPar->removeChild(m_marker); - if (!lineBoxParent) - lineBoxParent = this; - lineBoxParent->addChild(m_marker, lineBoxParent->firstChild()); - m_deleteMarker = false; - if (!m_marker->minMaxKnown()) - m_marker->calcMinMaxWidth(); - recalcMinMaxWidths(); - } - } -} - -void RenderListItem::calcMinMaxWidth() -{ - // Make sure our marker is in the correct location. - updateMarkerLocation(); - if (!minMaxKnown()) - RenderBlock::calcMinMaxWidth(); -} -/* -short RenderListItem::marginLeft() const -{ - if (m_insideList) - return RenderBlock::marginLeft(); - else - return kMax(m_marker->markerWidth(), RenderBlock::marginLeft()); -} - -short RenderListItem::marginRight() const -{ - return RenderBlock::marginRight(); -}*/ - -void RenderListItem::layout( ) -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - updateMarkerLocation(); - RenderBlock::layout(); -} - -// ----------------------------------------------------------- - -RenderListMarker::RenderListMarker(DOM::NodeImpl* node) - : RenderBox(node), m_listImage(0), m_markerWidth(0) -{ - // init RenderObject attributes - setInline(true); // our object is Inline - setReplaced(true); // pretend to be replaced - // val = -1; - // m_listImage = 0; -} - -RenderListMarker::~RenderListMarker() -{ - if(m_listImage) - m_listImage->deref(this); - if (m_listItem) - m_listItem->resetListMarker(); -} - -void RenderListMarker::setStyle(RenderStyle *s) -{ - if ( s && style() && s->listStylePosition() != style()->listStylePosition() ) - setNeedsLayoutAndMinMaxRecalc(); - - RenderBox::setStyle(s); - - if ( m_listImage != style()->listStyleImage() ) { - if(m_listImage) m_listImage->deref(this); - m_listImage = style()->listStyleImage(); - if(m_listImage) m_listImage->ref(this); - } -} - - -void RenderListMarker::paint(PaintInfo& paintInfo, int _tx, int _ty) -{ - if (paintInfo.phase != PaintActionForeground) - return; - - if (style()->visibility() != VISIBLE) return; - - _tx += m_x; - _ty += m_y; - - if((_ty > paintInfo.r.bottom()) || (_ty + m_height <= paintInfo.r.top())) - return; - - if(shouldPaintBackgroundOrBorder()) - paintBoxDecorations(paintInfo, _tx, _ty); - - TQPainter* p = paintInfo.p; -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << nodeName().string() << "(ListMarker)::paintObject(" << _tx << ", " << _ty << ")" << endl; -#endif - p->setFont(style()->font()); - const TQFontMetrics fm = p->fontMetrics(); - - - // The marker needs to adjust its tx, for the case where it's an outside marker. - RenderObject* listItem = 0; - int leftLineOffset = 0; - int rightLineOffset = 0; - if (!listPositionInside()) { - listItem = this; - int yOffset = 0; - int xOffset = 0; - while (listItem && listItem != m_listItem) { - yOffset += listItem->yPos(); - xOffset += listItem->xPos(); - listItem = listItem->parent(); - } - - // Now that we have our xoffset within the listbox, we need to adjust ourselves by the delta - // between our current xoffset and our desired position (which is just outside the border box - // of the list item). - if (style()->direction() == LTR) { - leftLineOffset = m_listItem->leftRelOffset(yOffset, m_listItem->leftOffset(yOffset)); - _tx -= (xOffset - leftLineOffset) + m_listItem->paddingLeft() + m_listItem->borderLeft(); - } - else { - rightLineOffset = m_listItem->rightRelOffset(yOffset, m_listItem->rightOffset(yOffset)); - _tx += (rightLineOffset-xOffset) + m_listItem->paddingRight() + m_listItem->borderRight(); - } - } - - int offset = fm.ascent()*2/3; - bool haveImage = m_listImage && !m_listImage->isErrorImage(); - if (haveImage) - offset = m_listImage->pixmap().width(); - - int xoff = 0; - int yoff = fm.ascent() - offset; - - int bulletWidth = offset/2; - if (offset%2) - bulletWidth++; - if (!listPositionInside()) { - if (listItem && listItem->style()->direction() == LTR) - xoff = -cMarkerPadding - offset; - else - xoff = cMarkerPadding + (haveImage ? 0 : (offset - bulletWidth)); - } - else if (style()->direction() == RTL) - xoff += haveImage ? cMarkerPadding : (m_width - bulletWidth); - - if ( m_listImage && !m_listImage->isErrorImage()) { - p->drawPixmap( TQPoint( _tx + xoff, _ty ), m_listImage->pixmap()); - return; - } - -#ifdef BOX_DEBUG - p->setPen( Qt::red ); - p->drawRect( _tx + xoff, _ty + yoff, offset, offset ); -#endif - - const TQColor color( style()->color() ); - p->setPen( color ); - - switch(style()->listStyleType()) { - case LDISC: - p->setBrush( color ); - p->drawEllipse( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 ); - return; - case LCIRCLE: - p->setBrush( Qt::NoBrush ); - p->drawEllipse( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 ); - return; - case LSQUARE: - p->setBrush( color ); - p->drawRect( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 ); - return; - case LBOX: - p->setBrush( Qt::NoBrush ); - p->drawRect( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 ); - return; - case LDIAMOND: { - static TQPointArray diamond(4); - int x = _tx + xoff; - int y = _ty + (3 * yoff)/2 - 1; - int s = (offset>>2)+1; - diamond[0] = TQPoint(x+s, y); - diamond[1] = TQPoint(x+2*s, y+s); - diamond[2] = TQPoint(x+s, y+2*s); - diamond[3] = TQPoint(x, y+s); - p->setBrush( color ); - p->drawConvexPolygon( diamond, 0, 4 ); - return; - } - case LNONE: - return; - default: - if (!m_item.isEmpty()) { - if(listPositionInside()) { - if( style()->direction() == LTR) { - p->drawText(_tx, _ty, 0, 0, Qt::AlignLeft|TQt::DontClip, m_item); - p->drawText(_tx + fm.width(m_item), _ty, 0, 0, Qt::AlignLeft|TQt::DontClip, - TQString::fromLatin1(". ")); - } - else { - const TQString& punct(TQString::fromLatin1(" .")); - p->drawText(_tx, _ty, 0, 0, Qt::AlignLeft|TQt::DontClip, punct); - p->drawText(_tx + fm.width(punct), _ty, 0, 0, Qt::AlignLeft|TQt::DontClip, m_item); - } - } else { - if (style()->direction() == LTR) { - const TQString& punct(TQString::fromLatin1(". ")); - p->drawText(_tx-offset/2, _ty, 0, 0, Qt::AlignRight|TQt::DontClip, punct); - p->drawText(_tx-offset/2-fm.width(punct), _ty, 0, 0, Qt::AlignRight|TQt::DontClip, m_item); - } - else { - const TQString& punct(TQString::fromLatin1(" .")); - p->drawText(_tx+offset/2, _ty, 0, 0, Qt::AlignLeft|TQt::DontClip, punct); - p->drawText(_tx+offset/2+fm.width(punct), _ty, 0, 0, Qt::AlignLeft|TQt::DontClip, m_item); - } - } - } - } -} - -void RenderListMarker::layout() -{ - KHTMLAssert( needsLayout() ); - - if ( !minMaxKnown() ) - calcMinMaxWidth(); - - setNeedsLayout(false); -} - -void RenderListMarker::setPixmap( const TQPixmap &p, const TQRect& r, CachedImage *o) -{ - if(o != m_listImage) { - RenderBox::setPixmap(p, r, o); - return; - } - - if(m_width != m_listImage->pixmap_size().width() || m_height != m_listImage->pixmap_size().height()) - setNeedsLayoutAndMinMaxRecalc(); - else - repaintRectangle(0, 0, m_width, m_height); -} - -void RenderListMarker::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - m_markerWidth = m_width = 0; - - if(m_listImage && !m_listImage->isErrorImage()) { - m_markerWidth = m_listImage->pixmap().width() + cMarkerPadding; - if (listPositionInside()) - m_width = m_markerWidth; - m_height = m_listImage->pixmap().height(); - m_minWidth = m_maxWidth = m_width; - setMinMaxKnown(); - return; - } - - const TQFontMetrics &fm = style()->fontMetrics(); - m_height = fm.ascent(); - - // Skip uncounted elements - switch(style()->listStyleType()) { - // Glyphs: - case LDISC: - case LCIRCLE: - case LSQUARE: - case LBOX: - case LDIAMOND: - m_markerWidth = fm.ascent(); - goto end; - default: - break; - } - - { // variable scope - CounterNode *counter = m_listItem->m_counter; - if (!counter) { - counter = m_listItem->getCounter("list-item", true); - counter->setRenderer(this); - m_listItem->m_counter = counter; - } - - - assert(counter); - int value = counter->count(); - if (counter->isReset()) value = counter->value(); - int total = value; - if (counter->parent()) total = counter->parent()->total(); - - switch(style()->listStyleType()) - { -// Numeric: - case LDECIMAL: - m_item.setNum ( value ); - break; - case DECIMAL_LEADING_ZERO: { - int decimals = 2; - int t = total/100; - while (t>0) { - t = t/10; - decimals++; - } - decimals = kMax(decimals, 2); - TQString num = TQString::number(value); - m_item.fill('0',decimals-num.length()); - m_item.append(num); - break; - } - case ARABIC_INDIC: - m_item = toArabicIndic( value ); - break; - case LAO: - m_item = toLao( value ); - break; - case PERSIAN: - case URDU: - m_item = toPersianUrdu( value ); - break; - case THAI: - m_item = toThai( value ); - break; - case TIBETAN: - m_item = toTibetan( value ); - break; -// Algoritmic: - case LOWER_ROMAN: - m_item = toRoman( value, false ); - break; - case UPPER_ROMAN: - m_item = toRoman( value, true ); - break; - case HEBREW: - m_item = toHebrew( value ); - break; - case ARMENIAN: - m_item = toArmenian( value ); - break; - case GEORGIAN: - m_item = toGeorgian( value ); - break; -// Alphabetic: - case LOWER_ALPHA: - case LOWER_LATIN: - m_item = toLowerLatin( value ); - break; - case UPPER_ALPHA: - case UPPER_LATIN: - m_item = toUpperLatin( value ); - break; - case LOWER_GREEK: - m_item = toLowerGreek( value ); - break; - case UPPER_GREEK: - m_item = toUpperGreek( value ); - break; - case HIRAGANA: - m_item = toHiragana( value ); - break; - case HIRAGANA_IROHA: - m_item = toHiraganaIroha( value ); - break; - case KATAKANA: - m_item = toKatakana( value ); - break; - case KATAKANA_IROHA: - m_item = toKatakanaIroha( value ); - break; -// Ideographic: - case JAPANESE_FORMAL: - m_item = toJapaneseFormal( value ); - break; - case JAPANESE_INFORMAL: - m_item = toJapaneseInformal( value ); - break; - case SIMP_CHINESE_FORMAL: - m_item = toSimpChineseFormal( value ); - break; - case SIMP_CHINESE_INFORMAL: - m_item = toSimpChineseInformal( value ); - break; - case TRAD_CHINESE_FORMAL: - m_item = toTradChineseFormal( value ); - break; - case CJK_IDEOGRAPHIC: - // CSS 3 List says treat as trad-chinese-informal - case TRAD_CHINESE_INFORMAL: - m_item = toTradChineseInformal( value ); - break; -// special: - case LNONE: - break; - default: - KHTMLAssert(false); - } - m_markerWidth = fm.width(m_item) + fm.width(TQString::fromLatin1(". ")); - } - -end: - if(listPositionInside()) - m_width = m_markerWidth; - - m_minWidth = m_width; - m_maxWidth = m_width; - - setMinMaxKnown(); -} - -short RenderListMarker::lineHeight(bool /*b*/) const -{ - return height(); -} - -short RenderListMarker::baselinePosition(bool /*b*/) const -{ - return height(); -} - -void RenderListMarker::calcWidth() -{ - RenderBox::calcWidth(); -} - -/* -int CounterListItem::recount() const -{ - static_cast<RenderListItem*>(m_renderer)->m_marker->setNeedsLayoutAndMinMaxRecalc(); -} - -void CounterListItem::setSelfDirty() -{ - -}*/ - - -#undef BOX_DEBUG diff --git a/khtml/rendering/render_list.h b/khtml/rendering/render_list.h deleted file mode 100644 index b70132671..000000000 --- a/khtml/rendering/render_list.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ -#ifndef RENDER_LIST_H -#define RENDER_LIST_H - -#include "rendering/render_block.h" - -// ### list-style-position, list-style-image is still missing - -namespace DOM -{ - class DocumentImpl; -} - -namespace khtml -{ - -class RenderListItem; -class RenderListMarker; -class CounterNode; - -// ----------------------------------------------------------------------------- - -class RenderListItem : public RenderBlock -{ - friend class RenderListMarker; -// friend class CounterListItem; - -public: - RenderListItem(DOM::NodeImpl*); - - virtual const char *renderName() const { return "RenderListItem"; } - - virtual void setStyle(RenderStyle *style); - - virtual bool isListItem() const { return true; } - - void setValue( long v ) { predefVal = v; } - - virtual void layout( ); - virtual void detach( ); - virtual void calcMinMaxWidth(); - //virtual short marginLeft() const; - //virtual short marginRight() const; - - void setInsideList(bool b ) { m_insideList = b; } - -protected: - - void updateMarkerLocation(); - void resetListMarker() { m_marker = 0; } - - RenderListMarker *m_marker; - CounterNode *m_counter; - signed long predefVal : 30; - bool m_insideList : 1; - bool m_deleteMarker: 1; -}; - -// ----------------------------------------------------------------------------- - -class RenderListMarker : public RenderBox -{ -public: - RenderListMarker(DOM::NodeImpl* node); - ~RenderListMarker(); - - virtual void setStyle(RenderStyle *style); - - virtual const char *renderName() const { return "RenderListMarker"; } - // so the marker gets to layout itself. Only needed for - // list-style-position: inside - - virtual void paint(PaintInfo& i, int xoff, int yoff); - virtual void layout( ); - virtual void calcMinMaxWidth(); - - virtual short lineHeight( bool firstLine ) const; - virtual short baselinePosition( bool firstLine ) const; - - virtual void setPixmap( const TQPixmap &, const TQRect&, CachedImage *); - - virtual void calcWidth(); - - virtual bool isListMarker() const { return true; } - - virtual short markerWidth() const { return m_markerWidth; } - - RenderListItem* listItem() const { return m_listItem; } - void setListItem(RenderListItem* listItem) { m_listItem = listItem; } - - bool listPositionInside() const - { return !m_listItem->m_insideList || style()->listStylePosition() == INSIDE; } - -protected: - friend class RenderListItem; - - TQString m_item; - CachedImage *m_listImage; - short m_markerWidth; - RenderListItem* m_listItem; -}; - -// Implementation of list-item counter -// ### should replace most list-item specific code in renderObject::getCounter -/* -class CounterListItem : public CounterNode -{ -public: - int count() const; - - virtual void recount( bool first = false ); - virtual void setSelfDirty(); - -}; */ - -} //namespace - -#endif diff --git a/khtml/rendering/render_object.cpp b/khtml/rendering/render_object.cpp deleted file mode 100644 index f03039759..000000000 --- a/khtml/rendering/render_object.cpp +++ /dev/null @@ -1,2330 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2002-2006 Apple Computer, Inc. - * (C) 2006 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 "rendering/render_object.h" -#include "rendering/render_table.h" -#include "rendering/render_list.h" -#include "rendering/render_canvas.h" -#include "rendering/render_block.h" -#include "rendering/render_arena.h" -#include "rendering/render_layer.h" -#include "rendering/render_line.h" -#include "rendering/render_inline.h" -#include "rendering/render_text.h" -#include "rendering/render_replaced.h" -#include "rendering/render_generated.h" -#include "rendering/counter_tree.h" - -#include "xml/dom_elementimpl.h" -#include "xml/dom_docimpl.h" -#include "dom/dom_doc.h" -#include "misc/htmlhashes.h" -#include "misc/loader.h" - -#include <kdebug.h> -#include <kglobal.h> -#include <tqpainter.h> -#include "khtmlview.h" -#include <khtml_part.h> - -#include <assert.h> -using namespace DOM; -using namespace khtml; - -#define RED_LUMINOSITY 30 -#define GREEN_LUMINOSITY 59 -#define BLUE_LUMINOSITY 11 -#define INTENSITY_FACTOR 25 -#define LIGHT_FACTOR 0 -#define LUMINOSITY_FACTOR 75 - -#define MAX_COLOR 255 -#define COLOR_DARK_THRESHOLD 51 -#define COLOR_LIGHT_THRESHOLD 204 - -#define COLOR_LITE_BS_FACTOR 45 -#define COLOR_LITE_TS_FACTOR 70 - -#define COLOR_DARK_BS_FACTOR 30 -#define COLOR_DARK_TS_FACTOR 50 - -#define LIGHT_GRAY tqRgb(192, 192, 192) -#define DARK_GRAY tqRgb(96, 96, 96) - -#ifndef NDEBUG -static void *baseOfRenderObjectBeingDeleted; -#endif - -//#define MASK_DEBUG - -void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw() -{ - return renderArena->allocate(sz); -} - -void RenderObject::operator delete(void* ptr, size_t sz) -{ - assert(baseOfRenderObjectBeingDeleted == ptr); - - // Stash size where detach can find it. - *(size_t *)ptr = sz; -} - -RenderObject *RenderObject::createObject(DOM::NodeImpl* node, RenderStyle* style) -{ - RenderObject *o = 0; - khtml::RenderArena* arena = node->getDocument()->renderArena(); - switch(style->display()) - { - case NONE: - break; - case INLINE: - o = new (arena) RenderInline(node); - break; - case BLOCK: - o = new (arena) RenderBlock(node); - break; - case INLINE_BLOCK: - o = new (arena) RenderBlock(node); - break; - case LIST_ITEM: - o = new (arena) RenderListItem(node); - break; - case RUN_IN: - case COMPACT: - o = new (arena) RenderBlock(node); - break; - case TABLE: - case INLINE_TABLE: - style->setFlowAroundFloats(true); - o = new (arena) RenderTable(node); - break; - case TABLE_ROW_GROUP: - case TABLE_HEADER_GROUP: - case TABLE_FOOTER_GROUP: - o = new (arena) RenderTableSection(node); - break; - case TABLE_ROW: - o = new (arena) RenderTableRow(node); - break; - case TABLE_COLUMN_GROUP: - case TABLE_COLUMN: - o = new (arena) RenderTableCol(node); - break; - case TABLE_CELL: - o = new (arena) RenderTableCell(node); - break; - case TABLE_CAPTION: - o = new (arena) RenderBlock(node); - break; - } - return o; -} - - -RenderObject::RenderObject(DOM::NodeImpl* node) - : CachedObjectClient(), - m_style( 0 ), - m_node( node ), - m_parent( 0 ), - m_previous( 0 ), - m_next( 0 ), - m_verticalPosition( PositionUndefined ), - m_needsLayout( false ), - m_normalChildNeedsLayout( false ), - m_markedForRepaint( false ), - m_posChildNeedsLayout( false ), - m_minMaxKnown( false ), - m_floating( false ), - - m_positioned( false ), - m_overhangingContents( false ), - m_relPositioned( false ), - m_paintBackground( false ), - - m_isAnonymous( node->isDocumentNode() ), - m_recalcMinMax( false ), - m_isText( false ), - m_inline( true ), - m_attached( false ), - - m_replaced( false ), - m_mouseInside( false ), - m_hasFirstLine( false ), - m_isSelectionBorder( false ), - m_isRoot( false ), - m_afterPageBreak( false ), - m_needsPageClear( false ), - m_containsPageBreak( false ), - m_hasOverflowClip( false ), - m_doNotDelete( false ) -{ - assert( node ); - if (node->getDocument()->documentElement() == node) setIsRoot(true); -} - -RenderObject::~RenderObject() -{ - const BackgroundLayer* bgLayer = m_style->backgroundLayers(); - while (bgLayer) { - if(bgLayer->backgroundImage()) - bgLayer->backgroundImage()->deref(this); - bgLayer = bgLayer->next(); - } - - if (m_style) - m_style->deref(); -} - - - -RenderObject* RenderObject::objectBelow() const -{ - RenderObject* obj = firstChild(); - if ( !obj ) { - obj = nextSibling(); - if ( !obj ) - { - obj = parent(); - while (obj && !obj->nextSibling()) - obj = obj->parent(); - if (obj) - obj = obj->nextSibling(); - } - } - return obj; -} - -RenderObject* RenderObject::objectAbove() const -{ - RenderObject* obj = previousSibling(); - if ( !obj ) - return parent(); - - RenderObject* last = obj->lastChild(); - while ( last ) - { - obj = last; - last = last->lastChild(); - } - return obj; -} -/* -bool RenderObject::isRoot() const -{ - return !isAnonymous() && - element()->getDocument()->documentElement() == element(); -}*/ - -bool RenderObject::isHR() const -{ - return element() && element()->id() == ID_HR; -} - -bool RenderObject::isWordBreak() const -{ - return element() && element()->id() == ID_WBR; -} - -bool RenderObject::isHTMLMarquee() const -{ - return element() && element()->renderer() == this && element()->id() == ID_MARQUEE; -} - -void RenderObject::addChild(RenderObject* , RenderObject *) -{ - KHTMLAssert(0); -} - -RenderObject* RenderObject::removeChildNode(RenderObject* ) -{ - KHTMLAssert(0); - return 0; -} - -void RenderObject::removeChild(RenderObject *o ) -{ - setNeedsLayout(true); - removeChildNode( o ); -} - -void RenderObject::appendChildNode(RenderObject*) -{ - KHTMLAssert(0); -} - -void RenderObject::insertChildNode(RenderObject*, RenderObject*) -{ - KHTMLAssert(0); -} - -RenderObject *RenderObject::nextRenderer() const -{ - if (firstChild()) - return firstChild(); - else if (nextSibling()) - return nextSibling(); - else { - const RenderObject *r = this; - while (r && !r->nextSibling()) - r = r->parent(); - if (r) - return r->nextSibling(); - } - return 0; -} - -RenderObject *RenderObject::previousRenderer() const -{ - if (previousSibling()) { - RenderObject *r = previousSibling(); - while (r->lastChild()) - r = r->lastChild(); - return r; - } - else if (parent()) { - return parent(); - } - else { - return 0; - } -} - -static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject, - RenderLayer*& beforeChild) -{ - if (obj->layer()) { - if (!beforeChild && newObject) { - // We need to figure out the layer that follows newObject. We only do - // this the first time we find a child layer, and then we update the - // pointer values for newObject and beforeChild used by everyone else. - beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject); - newObject = 0; - } - parentLayer->addChild(obj->layer(), beforeChild); - return; - } - - for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) - addLayers(curr, parentLayer, newObject, beforeChild); -} - -void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject) -{ - if (!parentLayer) - return; - - RenderObject* object = newObject; - RenderLayer* beforeChild = 0; - ::addLayers(this, parentLayer, object, beforeChild); -} - -void RenderObject::removeLayers(RenderLayer* parentLayer) -{ - if (!parentLayer) - return; - - if (layer()) { - parentLayer->removeChild(layer()); - return; - } - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) - curr->removeLayers(parentLayer); -} - -void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent) -{ - if (!newParent) - return; - - if (layer()) { - if (oldParent) - oldParent->removeChild(layer()); - newParent->addChild(layer()); - return; - } - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) - curr->moveLayers(oldParent, newParent); -} - -RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, - bool checkParent) -{ - // Error check the parent layer passed in. If it's null, we can't find anything. - if (!parentLayer) - return 0; - - // Step 1: If our layer is a child of the desired parent, then return our layer. - RenderLayer* ourLayer = layer(); - if (ourLayer && ourLayer->parent() == parentLayer) - return ourLayer; - - // Step 2: If we don't have a layer, or our layer is the desired parent, then descend - // into our siblings trying to find the next layer whose parent is the desired parent. - if (!ourLayer || ourLayer == parentLayer) { - for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild(); - curr; curr = curr->nextSibling()) { - RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false); - if (nextLayer) - return nextLayer; - } - } - - // Step 3: If our layer is the desired parent layer, then we're finished. We didn't - // find anything. - if (parentLayer == ourLayer) - return 0; - - // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that - // follow us to see if we can locate a layer. - if (checkParent && parent()) - return parent()->findNextLayer(parentLayer, this, true); - - return 0; -} - -RenderLayer* RenderObject::enclosingLayer() const -{ - const RenderObject* curr = this; - while (curr) { - RenderLayer *layer = curr->layer(); - if (layer) - return layer; - curr = curr->parent(); - } - return 0; -} - -RenderLayer* RenderObject::enclosingStackingContext() const -{ - RenderLayer* l = enclosingLayer(); - while (l && !l->isStackingContext()) - l = l->parent(); - return l; -} - -int RenderObject::offsetLeft() const -{ - if ( isPositioned() ) - return xPos(); - - if ( isBody() && style()->htmlHacks() ) - return 0; - - int x = xPos(); - if (isRelPositioned()) { - int y = 0; - static_cast<const RenderBox*>(this)->relativePositionOffset(x, y); - } - - RenderObject* offsetPar = offsetParent(); - for( RenderObject* curr = parent(); - curr && curr != offsetPar; - curr = curr->parent() ) - x += curr->xPos(); - - if ( offsetPar && offsetPar->isBody() && style()->htmlHacks() ) - x += offsetPar->xPos(); - - return x; -} - -int RenderObject::offsetTop() const -{ - if ( isPositioned() ) - return yPos(); - - if ( isBody() && style()->htmlHacks() ) - return 0; - - int y = yPos(); - if (isRelPositioned()) { - int x = 0; - static_cast<const RenderBox*>(this)->relativePositionOffset(x, y); - } - RenderObject* offsetPar = offsetParent(); - for( RenderObject* curr = parent(); - curr && curr != offsetPar; - curr = curr->parent() ) - y += curr->yPos(); - - if ( offsetPar && offsetPar->isBody() && style()->htmlHacks() ) - y += offsetPar->yPos(); - - return y; -} - -RenderObject* RenderObject::offsetParent() const -{ - if (isBody()) - return 0; - - // can't really use containing blocks here (#113280) - bool skipTables = isPositioned() || isRelPositioned(); - bool strict = !style()->htmlHacks(); - RenderObject* curr = parent(); - while (curr && (!curr->element() || - (!curr->isPositioned() && !curr->isRelPositioned() && - !(strict && skipTables ? curr->isRoot() : curr->isBody())))) { - if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable())) - break; - curr = curr->parent(); - } - return curr; -} - -// IE extensions. -// clientWidth and clientHeight represent the interior of an object -short RenderObject::clientWidth() const -{ - return width() - borderLeft() - borderRight() - - (layer() ? layer()->verticalScrollbarWidth() : 0); -} - -int RenderObject::clientHeight() const -{ - return height() - borderTop() - borderBottom() - - (layer() ? layer()->horizontalScrollbarHeight() : 0); -} - -// scrollWidth/scrollHeight is the size including the overflow area -short RenderObject::scrollWidth() const -{ - return (hasOverflowClip() && layer()) ? layer()->scrollWidth() : overflowWidth() - overflowLeft(); -} - -int RenderObject::scrollHeight() const -{ - return (hasOverflowClip() && layer()) ? layer()->scrollHeight() : overflowHeight() - overflowTop(); -} - -bool RenderObject::hasStaticX() const -{ - return (style()->left().isVariable() && style()->right().isVariable()); -} - -bool RenderObject::hasStaticY() const -{ - return (style()->top().isVariable() && style()->bottom().isVariable()); -} - -void RenderObject::setPixmap(const TQPixmap&, const TQRect& /*r*/, CachedImage* image) -{ - //repaint bg when it finished loading - if(image && parent() && style() && style()->backgroundLayers()->containsImage(image)) { - isBody() ? canvas()->repaint() : repaint(); - } -} - -void RenderObject::setNeedsLayout(bool b, bool markParents) -{ - bool alreadyNeededLayout = m_needsLayout; - m_needsLayout = b; - if (b) { - if (!alreadyNeededLayout && markParents && m_parent) { - dirtyFormattingContext( false ); - markContainingBlocksForLayout(); - } - } - else { - m_posChildNeedsLayout = false; - m_normalChildNeedsLayout = false; - } -} - -void RenderObject::setChildNeedsLayout(bool b, bool markParents) -{ - bool alreadyNeededLayout = m_normalChildNeedsLayout; - m_normalChildNeedsLayout = b; - if (b) { - if (!alreadyNeededLayout && markParents) - markContainingBlocksForLayout(); - } - else { - m_posChildNeedsLayout = false; - m_normalChildNeedsLayout = false; - } -} - -void RenderObject::markContainingBlocksForLayout() -{ - RenderObject *o = container(); - RenderObject *last = this; - - while (o) { - if (!last->isText() && (last->style()->position() == FIXED || last->style()->position() == ABSOLUTE)) { - if (o->m_posChildNeedsLayout) - return; - o->m_posChildNeedsLayout = true; - } - else { - if (o->m_normalChildNeedsLayout) - return; - o->m_normalChildNeedsLayout = true; - } - - last = o; - o = o->container(); - } - - last->scheduleRelayout(); -} - -RenderBlock *RenderObject::containingBlock() const -{ - if(isTableCell()) - return static_cast<RenderBlock*>( parent()->parent()->parent() ); - if (isCanvas()) - return const_cast<RenderBlock*>( static_cast<const RenderBlock*>(this) ); - - RenderObject *o = parent(); - if(m_style->position() == FIXED) { - while ( o && !o->isCanvas() ) - o = o->parent(); - } - else if(m_style->position() == ABSOLUTE) { - while (o && - ( o->style()->position() == STATIC || ( o->isInline() && !o->isReplaced() ) ) && !o->isCanvas()) { - // for relpos inlines, return the nearest block - it will host the positioned objects list - if (o->isInline() && !o->isReplaced() && o->style()->position() == RELATIVE) - return o->containingBlock(); - o = o->parent(); - } - } else { - while(o && ( ( o->isInline() && !o->isReplaced() ) || o->isTableRow() || o->isTableSection() || - o->isTableCol() || o->isFrameSet() ) ) - o = o->parent(); - } - // this is just to make sure we return a valid element. - // the case below should never happen... - if(!o || !o->isRenderBlock()) { - if(!isCanvas()) { -#ifndef NDEBUG - kdDebug( 6040 ) << this << ": " << renderName() << "(RenderObject): No containingBlock!" << endl; - kdDebug( 6040 ) << kdBacktrace() << endl; - const RenderObject* p = this; - while (p->parent()) p = p->parent(); - p->printTree(); -#endif - } - return 0L; - } - - return static_cast<RenderBlock*>( o ); -} - -short RenderObject::containingBlockWidth() const -{ - // ### - return containingBlock()->contentWidth(); -} - -int RenderObject::containingBlockHeight() const -{ - // ### - return containingBlock()->contentHeight(); -} - -bool RenderObject::sizesToMaxWidth() const -{ - // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks, - // but they allow text to sit on the same line as the marquee. - if (isFloating() || isCompact() || - (isInlineBlockOrInlineTable() && !isHTMLMarquee()) || - (element() && (element()->id() == ID_BUTTON || element()->id() == ID_LEGEND))) - return true; - - // Children of a horizontal marquee do not fill the container by default. - // FIXME: Need to deal with MAUTO value properly. It could be vertical. - if (parent()->style()->overflowX() == OMARQUEE) { - EMarqueeDirection dir = parent()->style()->marqueeDirection(); - if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT) - return true; - } - -#ifdef APPLE_CHANGES // ### what the heck is a flexbox? - // Flexible horizontal boxes lay out children at their maxwidths. Also vertical boxes - // that don't stretch their kids lay out their children at their maxwidths. - if (parent()->isFlexibleBox() && - (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH)) - return true; -#endif - - return false; -} - -// from Mozilla's nsCSSColorUtils.cpp -static int brightness(int red, int green, int blue) -{ - - int intensity = (red + green + blue) / 3; - - int luminosity = - ((RED_LUMINOSITY * red) / 100) + - ((GREEN_LUMINOSITY * green) / 100) + - ((BLUE_LUMINOSITY * blue) / 100); - - return ((intensity * INTENSITY_FACTOR) + - (luminosity * LUMINOSITY_FACTOR)) / 100; -} - -static void calc3DColor(TQColor &color, bool darken) -{ - int rb = color.red(); - int gb = color.green(); - int bb = color.blue(); - - int brightness_ = brightness(rb,gb,bb); - - int f0, f1; - if (brightness_ < COLOR_DARK_THRESHOLD) { - f0 = COLOR_DARK_BS_FACTOR; - f1 = COLOR_DARK_TS_FACTOR; - } else if (brightness_ > COLOR_LIGHT_THRESHOLD) { - f0 = COLOR_LITE_BS_FACTOR; - f1 = COLOR_LITE_TS_FACTOR; - } else { - f0 = COLOR_DARK_BS_FACTOR + - (brightness_ * - (COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR) / MAX_COLOR); - f1 = COLOR_DARK_TS_FACTOR + - (brightness_ * - (COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR) / MAX_COLOR); - } - - if (darken) { - int r = rb - (f0 * rb / 100); - int g = gb - (f0 * gb / 100); - int b = bb - (f0 * bb / 100); - if ((r == rb) && (g == gb) && (b == bb)) - color = (color == Qt::black) ? DARK_GRAY : Qt::black; - else - color.setRgb(r, g, b); - } else { - int r = kMin(rb + (f1 * (MAX_COLOR - rb) / 100), 255); - int g = kMin(gb + (f1 * (MAX_COLOR - gb) / 100), 255); - int b = kMin(bb + (f1 * (MAX_COLOR - bb) / 100), 255); - if ((r == rb) && (g == gb) && (b == bb)) - color = (color == Qt::white) ? LIGHT_GRAY : Qt::white; - else - color.setRgb(r, g, b); - } -} - -void RenderObject::drawBorder(TQPainter *p, int x1, int y1, int x2, int y2, - BorderSide s, TQColor c, const TQColor& textcolor, EBorderStyle style, - int adjbw1, int adjbw2, bool invalidisInvert) -{ - int width = (s==BSTop||s==BSBottom?y2-y1:x2-x1); - - if(style == DOUBLE && width < 3) - style = SOLID; - - if(!c.isValid()) { - if(invalidisInvert) - { - p->setRasterOp(TQt::XorROP); - c = Qt::white; - } - else { - if(style == INSET || style == OUTSET || style == RIDGE || style == - GROOVE) - c = Qt::white; - else - c = textcolor; - } - } - - switch(style) - { - case BNATIVE: - case BNONE: - case BHIDDEN: - // should not happen - if(invalidisInvert && p->rasterOp() == TQt::XorROP) - p->setRasterOp(TQt::CopyROP); - - return; - case DOTTED: - if ( width == 1 ) { - // workaround Qt brokenness - p->setPen(TQPen(c, width, Qt::SolidLine)); - switch(s) { - case BSBottom: - case BSTop: - for ( ; x1 < x2; x1 += 2 ) - p->drawPoint( x1, y1 ); - break; - case BSRight: - case BSLeft: - for ( ; y1 < y2; y1 += 2 ) - p->drawPoint( x1, y1 ); - } - break; - } - - p->setPen(TQPen(c, width, Qt::DotLine)); - /* nobreak; */ - case DASHED: - if(style == DASHED) - p->setPen(TQPen(c, width == 1 ? 0 : width, width == 1 ? Qt::DotLine : Qt::DashLine)); - - if (width > 0) - switch(s) { - case BSBottom: - case BSTop: - p->drawLine(x1, (y1+y2)/2, x2, (y1+y2)/2); - break; - case BSRight: - case BSLeft: - p->drawLine((x1+x2)/2, y1, (x1+x2)/2, y2); - break; - } - - break; - case DOUBLE: - { - int third = (width+1)/3; - - if (adjbw1 == 0 && adjbw2 == 0) - { - p->setPen(Qt::NoPen); - p->setBrush(c); - switch(s) - { - case BSTop: - case BSBottom: - p->drawRect(x1, y1 , x2-x1, third); - p->drawRect(x1, y2-third, x2-x1, third); - break; - case BSLeft: - p->drawRect(x1 , y1+1, third, y2-y1-1); - p->drawRect(x2-third, y1+1, third, y2-y1-1); - break; - case BSRight: - p->drawRect(x1 , y1+1, third, y2-y1-1); - p->drawRect(x2-third, y1+1, third, y2-y1-1); - break; - } - } - else - { - int adjbw1bigthird; - if (adjbw1>0) adjbw1bigthird = adjbw1+1; - else adjbw1bigthird = adjbw1 - 1; - adjbw1bigthird /= 3; - - int adjbw2bigthird; - if (adjbw2>0) adjbw2bigthird = adjbw2 + 1; - else adjbw2bigthird = adjbw2 - 1; - adjbw2bigthird /= 3; - - switch(s) - { - case BSTop: - drawBorder(p, x1+kMax((-adjbw1*2+1)/3,0), y1 , x2-kMax((-adjbw2*2+1)/3,0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(p, x1+kMax(( adjbw1*2+1)/3,0), y2 - third, x2-kMax(( adjbw2*2+1)/3,0), y2 , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - break; - case BSLeft: - drawBorder(p, x1 , y1+kMax((-adjbw1*2+1)/3,0), x1+third, y2-kMax((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(p, x2 - third, y1+kMax(( adjbw1*2+1)/3,0), x2 , y2-kMax(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - break; - case BSBottom: - drawBorder(p, x1+kMax(( adjbw1*2+1)/3,0), y1 , x2-kMax(( adjbw2*2+1)/3,0), y1+third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(p, x1+kMax((-adjbw1*2+1)/3,0), y2-third, x2-kMax((-adjbw2*2+1)/3,0), y2 , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - break; - case BSRight: - drawBorder(p, x1 , y1+kMax(( adjbw1*2+1)/3,0), x1+third, y2-kMax(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(p, x2-third, y1+kMax((-adjbw1*2+1)/3,0), x2 , y2-kMax((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - break; - default: - break; - } - } - break; - } - case RIDGE: - case GROOVE: - { - EBorderStyle s1; - EBorderStyle s2; - if (style==GROOVE) - { - s1 = INSET; - s2 = OUTSET; - } - else - { - s1 = OUTSET; - s2 = INSET; - } - - int adjbw1bighalf; - int adjbw2bighalf; - if (adjbw1>0) adjbw1bighalf=adjbw1+1; - else adjbw1bighalf=adjbw1-1; - adjbw1bighalf/=2; - - if (adjbw2>0) adjbw2bighalf=adjbw2+1; - else adjbw2bighalf=adjbw2-1; - adjbw2bighalf/=2; - - switch (s) - { - case BSTop: - drawBorder(p, x1+kMax(-adjbw1 ,0)/2, y1 , x2-kMax(-adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf); - drawBorder(p, x1+kMax( adjbw1+1,0)/2, (y1+y2+1)/2, x2-kMax( adjbw2+1,0)/2, y2 , s, c, textcolor, s2, adjbw1/2, adjbw2/2); - break; - case BSLeft: - drawBorder(p, x1 , y1+kMax(-adjbw1 ,0)/2, (x1+x2+1)/2, y2-kMax(-adjbw2,0)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf); - drawBorder(p, (x1+x2+1)/2, y1+kMax( adjbw1+1,0)/2, x2 , y2-kMax( adjbw2+1,0)/2, s, c, textcolor, s2, adjbw1/2, adjbw2/2); - break; - case BSBottom: - drawBorder(p, x1+kMax( adjbw1 ,0)/2, y1 , x2-kMax( adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf); - drawBorder(p, x1+kMax(-adjbw1+1,0)/2, (y1+y2+1)/2, x2-kMax(-adjbw2+1,0)/2, y2 , s, c, textcolor, s1, adjbw1/2, adjbw2/2); - break; - case BSRight: - drawBorder(p, x1 , y1+kMax( adjbw1 ,0)/2, (x1+x2+1)/2, y2-kMax( adjbw2,0)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf); - drawBorder(p, (x1+x2+1)/2, y1+kMax(-adjbw1+1,0)/2, x2 , y2-kMax(-adjbw2+1,0)/2, s, c, textcolor, s1, adjbw1/2, adjbw2/2); - break; - } - break; - } - case INSET: - case OUTSET: - calc3DColor(c, (style == OUTSET && (s == BSBottom || s == BSRight)) || - (style == INSET && ( s == BSTop || s == BSLeft ) ) ); - /* nobreak; */ - case SOLID: - p->setPen(Qt::NoPen); - p->setBrush(c); - Q_ASSERT(x2>=x1); - Q_ASSERT(y2>=y1); - if (adjbw1==0 && adjbw2 == 0) { - p->drawRect(x1,y1,x2-x1,y2-y1); - return; - } - TQPointArray quad(4); - switch(s) { - case BSTop: - quad.setPoints(4, - x1+kMax(-adjbw1,0), y1, - x1+kMax( adjbw1,0), y2, - x2-kMax( adjbw2,0), y2, - x2-kMax(-adjbw2,0), y1); - break; - case BSBottom: - quad.setPoints(4, - x1+kMax( adjbw1,0), y1, - x1+kMax(-adjbw1,0), y2, - x2-kMax(-adjbw2,0), y2, - x2-kMax( adjbw2,0), y1); - break; - case BSLeft: - quad.setPoints(4, - x1, y1+kMax(-adjbw1,0), - x1, y2-kMax(-adjbw2,0), - x2, y2-kMax( adjbw2,0), - x2, y1+kMax( adjbw1,0)); - break; - case BSRight: - quad.setPoints(4, - x1, y1+kMax( adjbw1,0), - x1, y2-kMax( adjbw2,0), - x2, y2-kMax(-adjbw2,0), - x2, y1+kMax(-adjbw1,0)); - break; - } - p->drawConvexPolygon(quad); - break; - } - - if(invalidisInvert && p->rasterOp() == TQt::XorROP) - p->setRasterOp(TQt::CopyROP); -} - -void RenderObject::paintBorder(TQPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin, bool end) -{ - const TQColor& tc = style->borderTopColor(); - const TQColor& bc = style->borderBottomColor(); - const TQColor& lc = style->borderLeftColor(); - const TQColor& rc = style->borderRightColor(); - - bool tt = style->borderTopIsTransparent(); - bool bt = style->borderBottomIsTransparent(); - bool rt = style->borderRightIsTransparent(); - bool lt = style->borderLeftIsTransparent(); - - EBorderStyle ts = style->borderTopStyle(); - EBorderStyle bs = style->borderBottomStyle(); - EBorderStyle ls = style->borderLeftStyle(); - EBorderStyle rs = style->borderRightStyle(); - - bool render_t = ts > BHIDDEN && !tt; - bool render_l = ls > BHIDDEN && begin && !lt; - bool render_r = rs > BHIDDEN && end && !rt; - bool render_b = bs > BHIDDEN && !bt; - - if(render_t) { - bool ignore_left = - (tc == lc) && (tt == lt) && - (ts >= OUTSET) && - (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET); - - bool ignore_right = - (tc == rc) && (tt == rt) && - (ts >= OUTSET) && - (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET); - - drawBorder(p, _tx, _ty, _tx + w, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, - ignore_left?0:style->borderLeftWidth(), - ignore_right?0:style->borderRightWidth()); - } - - if(render_b) { - bool ignore_left = - (bc == lc) && (bt == lt) && - (bs >= OUTSET) && - (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET); - - bool ignore_right = - (bc == rc) && (bt == rt) && - (bs >= OUTSET) && - (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET); - - drawBorder(p, _tx, _ty + h - style->borderBottomWidth(), _tx + w, _ty + h, BSBottom, bc, style->color(), bs, - ignore_left?0:style->borderLeftWidth(), - ignore_right?0:style->borderRightWidth()); - } - - if(render_l) - { - bool ignore_top = - (tc == lc) && (tt == lt) && - (ls >= OUTSET) && - (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); - - bool ignore_bottom = - (bc == lc) && (bt == lt) && - (ls >= OUTSET) && - (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); - - drawBorder(p, _tx, _ty, _tx + style->borderLeftWidth(), _ty + h, BSLeft, lc, style->color(), ls, - ignore_top?0:style->borderTopWidth(), - ignore_bottom?0:style->borderBottomWidth()); - } - - if(render_r) - { - bool ignore_top = - (tc == rc) && (tt == rt) && - (rs >= DOTTED || rs == INSET) && - (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); - - bool ignore_bottom = - (bc == rc) && (bt == rt) && - (rs >= DOTTED || rs == INSET) && - (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); - - drawBorder(p, _tx + w - style->borderRightWidth(), _ty, _tx + w, _ty + h, BSRight, rc, style->color(), rs, - ignore_top?0:style->borderTopWidth(), - ignore_bottom?0:style->borderBottomWidth()); - } -} - -void RenderObject::paintOutline(TQPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style) -{ - int ow = style->outlineWidth(); - if(!ow) return; - - const TQColor& oc = style->outlineColor(); - EBorderStyle os = style->outlineStyle(); - int offset = style->outlineOffset(); - -#ifdef APPLE_CHANGES - if (style->outlineStyleIsAuto()) { - p->initFocusRing(ow, offset, oc); - addFocusRingRects(p, _tx, _ty); - p->drawFocusRing(); - p->clearFocusRing(); - return; - } -#endif - - _tx -= offset; - _ty -= offset; - w += 2*offset; - h += 2*offset; - - drawBorder(p, _tx-ow, _ty-ow, _tx, _ty+h+ow, BSLeft, - TQColor(oc), style->color(), - os, ow, ow, true); - - drawBorder(p, _tx-ow, _ty-ow, _tx+w+ow, _ty, BSTop, - TQColor(oc), style->color(), - os, ow, ow, true); - - drawBorder(p, _tx+w, _ty-ow, _tx+w+ow, _ty+h+ow, BSRight, - TQColor(oc), style->color(), - os, ow, ow, true); - - drawBorder(p, _tx-ow, _ty+h, _tx+w+ow, _ty+h+ow, BSBottom, - TQColor(oc), style->color(), - os, ow, ow, true); - -} - -void RenderObject::paint( PaintInfo&, int /*tx*/, int /*ty*/) -{ -} - -void RenderObject::repaintRectangle(int x, int y, int w, int h, Priority p, bool f) -{ - if(parent()) parent()->repaintRectangle(x, y, w, h, p, f); -} - -#ifdef ENABLE_DUMP - -TQString RenderObject::information() const -{ - TQString str; - int x; int y; - absolutePosition(x,y); - x += inlineXPos(); - y += inlineYPos(); - TQTextStream ts( &str, IO_WriteOnly ); - ts << renderName() - << "(" << (style() ? style()->refCount() : 0) << ")" - << ": " << (void*)this << " "; - ts << "{" << x << " " << y << "} "; - if (isInline()) ts << "il "; - if (childrenInline()) ts << "ci "; - if (isFloating()) ts << "fl "; - if (isAnonymous()) ts << "an "; - if (isRelPositioned()) ts << "rp "; - if (isPositioned()) ts << "ps "; - if (isReplaced()) ts << "rp "; - if (overhangingContents()) ts << "oc "; - if (needsLayout()) ts << "nl "; - if (minMaxKnown()) ts << "mmk "; - if (m_recalcMinMax) ts << "rmm "; - if (mouseInside()) ts << "mi "; - if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex(); - if (style() && style()->hasAutoZIndex()) ts << "zI: auto "; - if (element()) { - if (element()->active()) ts << "act "; - if (element()->hasAnchor()) ts << "anchor "; - if (element()->focused()) ts << "focus "; - ts << " <" << getTagName(element()->id()) << ">"; - - } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO) { - ts << " <" << getTagName(node()->id()); - TQString pseudo; - switch (style()->styleType()) { - case RenderStyle::FIRST_LETTER: - pseudo = ":first-letter"; break; - case RenderStyle::BEFORE: - pseudo = ":before"; break; - case RenderStyle::AFTER: - pseudo = ":after"; break; - default: - pseudo = ":pseudo-element"; - } - ts << pseudo; - ts << ">"; - } - ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")" - << " [" << minWidth() << "-" << maxWidth() << "]" - << " { mT: " << marginTop() << " qT: " << isTopMarginQuirk() - << " mB: " << marginBottom() << " qB: " << isBottomMarginQuirk() - << "}" - << (isTableCell() ? - ( TQString::fromLatin1(" [r=") + - TQString::number( static_cast<const RenderTableCell *>(this)->row() ) + - TQString::fromLatin1(" c=") + - TQString::number( static_cast<const RenderTableCell *>(this)->col() ) + - TQString::fromLatin1(" rs=") + - TQString::number( static_cast<const RenderTableCell *>(this)->rowSpan() ) + - TQString::fromLatin1(" cs=") + - TQString::number( static_cast<const RenderTableCell *>(this)->colSpan() ) + - TQString::fromLatin1("]") ) : TQString::null ); - if ( layer() ) - ts << " layer=" << layer(); - if ( continuation() ) - ts << " continuation=" << continuation(); - if (isText()) - ts << " \"" << TQConstString(static_cast<const RenderText *>(this)->text(), kMin(static_cast<const RenderText *>(this)->length(), 10u)).string() << "\""; - return str; -} - -void RenderObject::printTree(int indent) const -{ - TQString ind; - ind.fill(' ', indent); - - kdDebug() << ind << information() << endl; - - RenderObject *child = firstChild(); - while( child != 0 ) - { - child->printTree(indent+2); - child = child->nextSibling(); - } -} - -static TQTextStream &operator<<(TQTextStream &ts, const TQRect &r) -{ - return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height(); -} - -//A bit like getTagName, but handles XML, too. -static TQString lookupTagName(NodeImpl* node) { - return node->getDocument()->getName(NodeImpl::ElementId, node->id()).string(); -} - -void RenderObject::dump(TQTextStream &ts, const TQString &ind) const -{ - if ( !layer() ) - ts << endl; - - ts << ind << renderName(); - - if (style() && style()->zIndex()) { - ts << " zI: " << style()->zIndex(); - } - - if (element()) { - TQString tagName(lookupTagName(element())); - if (!tagName.isEmpty()) { - ts << " {" << tagName << "}"; - } - } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO) { - TQString pseudo; - TQString tagName(lookupTagName(node())); - switch (style()->styleType()) { - case RenderStyle::FIRST_LETTER: - pseudo = ":first-letter"; break; - case RenderStyle::BEFORE: - pseudo = ":before"; break; - case RenderStyle::AFTER: - pseudo = ":after"; break; - default: - pseudo = ":pseudo-element"; - } - ts << " {" << tagName << pseudo << "}"; - } - - TQRect r(xPos(), yPos(), width(), height()); - ts << " " << r; - - if ( parent() ) - ts << style()->createDiff( *parent()->style() ); - - if (isAnonymous()) { ts << " anonymousBox"; } - if (isFloating()) { ts << " floating"; } - if (isPositioned()) { ts << " positioned"; } - if (isRelPositioned()) { ts << " relPositioned"; } - if (isText()) { ts << " text"; } - if (isInline()) { ts << " inline"; } - if (isReplaced()) { ts << " replaced"; } - if (shouldPaintBackgroundOrBorder()) { ts << " paintBackground"; } - if (needsLayout()) { ts << " needsLayout"; } - if (minMaxKnown()) { ts << " minMaxKnown"; } - if (overhangingContents()) { ts << " overhangingContents"; } - if (hasFirstLine()) { ts << " hasFirstLine"; } - if (afterPageBreak()) { ts << " afterPageBreak"; } -} -#endif - -void RenderObject::selectionStartEnd(int& spos, int& epos) -{ - if (parent()) - parent()->selectionStartEnd(spos, epos); -} - -void RenderObject::setStyle(RenderStyle *style) -{ - if (m_style == style) - return; - - RenderStyle::Diff d = m_style ? m_style->diff( style ) : RenderStyle::Layout; - //tqDebug("m_style: %p new style, diff=%d", m_style, d); - - Priority pri = NormalPriority; - if (m_style) { - pri = HighPriority; - if ( d >= RenderStyle::Visible && !isText() && m_parent && - ( d == RenderStyle::Position || - m_style->outlineWidth() > style->outlineWidth() || - (!m_style->hidesOverflow() && style->hidesOverflow()) || - ( m_style->hasClip() && !(m_style->clip() == style->clip()) ) ) ) { - // schedule a repaint with the old style - if (layer() && !isInlineFlow()) - layer()->repaint(pri); - else - repaint(pri); - } - - if ( ( isFloating() && m_style->floating() != style->floating() ) || - ( isPositioned() && m_style->position() != style->position() && - style->position() != ABSOLUTE && style->position() != FIXED ) ) - removeFromObjectLists(); - - if ( layer() ) { - if ( ( m_style->hasAutoZIndex() != style->hasAutoZIndex() || - m_style->zIndex() != style->zIndex() || - m_style->visibility() != style->visibility() ) ) { - layer()->stackingContext()->dirtyZOrderLists(); - layer()->dirtyZOrderLists(); - } - } - - // reset style flags - m_floating = false; - m_positioned = false; - m_relPositioned = false; - m_paintBackground = false; - m_hasOverflowClip = false; - } - - // only honour z-index for non-static objects - // ### and objects with opacity - if ( style->position() == STATIC ) { - if ( isRoot() ) - style->setZIndex( 0 ); - else - style->setHasAutoZIndex(); - } - - RenderStyle *oldStyle = m_style; - m_style = style; - - updateBackgroundImages(oldStyle); - - m_style->ref(); - - if (oldStyle) - oldStyle->deref(); - - setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground()); - - m_hasFirstLine = (style->getPseudoStyle(RenderStyle::FIRST_LINE) != 0); - if (m_parent) { - if (d == RenderStyle::Position && !attemptDirectLayerTranslation()) - d = RenderStyle::Layout; - - if ( d > RenderStyle::Position) { - // we must perform a full layout - if (!isText() && d == RenderStyle::CbLayout) { - dirtyFormattingContext( true ); - } - setNeedsLayoutAndMinMaxRecalc(); - } else if (!isText() && d >= RenderStyle::Visible) { - // a repaint is enough - if (layer()) { - if (canvas() && canvas()->needsWidgetMasks()) { - // update our widget masks - RenderLayer *p, *d = 0; - for (p=layer()->parent();p;p=p->parent()) - if (p->hasOverlaidWidgets()) d=p; - if (d) // deepest - d->updateWidgetMasks( canvas()->layer() ); - } - } - if (layer() && !isInlineFlow()) - layer()->repaint(pri); - else - repaint(pri); - } - } -} - -bool RenderObject::attemptDirectLayerTranslation() -{ - // When the difference between two successive styles is only 'Position' - // we may attempt to save a layout by directly updating the object position. - - KHTMLAssert( m_style->position() != STATIC ); - if (!layer()) - return false; - setInline(m_style->isDisplayInlineType()); - setPositioned(m_style->position() != RELATIVE); - setRelPositioned(m_style->position() == RELATIVE); - int oldXPos = xPos(); - int oldYPos = yPos(); - int oldWidth = width(); - int oldHeight = height(); - calcWidth(); - calcHeight(); - if (oldWidth != width() || oldHeight != height()) { - // implicit size change or overconstrained dimensions: - // we'll need a layout. - setWidth(oldWidth); - setHeight(oldHeight); - // kdDebug() << "Layer translation failed for " << information() << endl; - return false; - } - layer()->updateLayerPosition(); - if (m_style->position() != FIXED) { - bool needsDocSizeUpdate = true; - RenderObject *cb = container(); - while (cb) { - if (cb->hasOverflowClip() && cb->layer()) { - cb->layer()->checkScrollbarsAfterLayout(); - needsDocSizeUpdate = false; - break; - } - cb = cb->container(); - } - if (needsDocSizeUpdate && canvas()) { - bool posXOffset = (xPos()-oldXPos >= 0); - bool posYOffset = (yPos()-oldYPos >= 0); - canvas()->updateDocSizeAfterLayerTranslation(this, posXOffset, posYOffset); - } - } - // success - return true; -} - -void RenderObject::dirtyFormattingContext( bool checkContainer ) -{ - if (m_markedForRepaint && !checkContainer) - return; - m_markedForRepaint = true; - if (layer() && (style()->position() == FIXED || style()->position() == ABSOLUTE)) - return; - if (m_parent && (checkContainer || style()->width().isVariable() || style()->height().isVariable() || - !(isFloating() || flowAroundFloats() || isTableCell()))) - m_parent->dirtyFormattingContext(false); -} - -void RenderObject::repaintDuringLayout() -{ - if (canvas()->needsFullRepaint() || isText()) - return; - if (layer() && !isInlineFlow()) { - layer()->repaint( NormalPriority, true ); - } else { - repaint(); - canvas()->deferredRepaint( this ); - } -} - -void RenderObject::setOverhangingContents(bool p) -{ - if (m_overhangingContents == p) - return; - - RenderBlock *cb = containingBlock(); - if (p) - { - m_overhangingContents = true; - KHTMLAssert( cb != this || isCanvas()); - if (cb && cb != this) - cb->setOverhangingContents(); - } - else - { - RenderObject *n; - bool c=false; - - for( n = firstChild(); n != 0; n = n->nextSibling() ) - { - if (n->isPositioned() || n->overhangingContents()) - c=true; - } - - if (c) - return; - else - { - m_overhangingContents = false; - KHTMLAssert( cb != this ); - if (cb && cb != this) - cb->setOverhangingContents(false); - } - } -} - -void RenderObject::updateBackgroundImages(RenderStyle* oldStyle) -{ - // FIXME: This will be slow when a large number of images is used. Fix by using a dict. - const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0; - const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0; - for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) { - if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage()))) - currOld->backgroundImage()->deref(this); - } - for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) { - if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage()))) - currNew->backgroundImage()->ref(this); - } -} - -TQRect RenderObject::viewRect() const -{ - return containingBlock()->viewRect(); -} - -bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f) const -{ - RenderObject* p = parent(); - if (p) { - p->absolutePosition(xPos, yPos, f); - if ( p->hasOverflowClip() ) - p->layer()->subtractScrollOffset( xPos, yPos ); - return true; - } - else - { - xPos = yPos = 0; - return false; - } -} - -void RenderObject::caretPos(int /*offset*/, int /*flags*/, int &_x, int &_y, int &width, int &height) -{ - _x = _y = height = -1; - width = 1; // the caret has a default width of one pixel. If you want - // to check for validity, only test the x-coordinate for >= 0. -} - -int RenderObject::paddingTop() const -{ - int w = 0; - Length padding = m_style->paddingTop(); - if (padding.isPercent()) - w = containingBlock()->contentWidth(); - w = padding.minWidth(w); - if ( isTableCell() && padding.isVariable() ) - w = static_cast<const RenderTableCell *>(this)->table()->cellPadding(); - return w; -} - -int RenderObject::paddingBottom() const -{ - int w = 0; - Length padding = style()->paddingBottom(); - if (padding.isPercent()) - w = containingBlock()->contentWidth(); - w = padding.minWidth(w); - if ( isTableCell() && padding.isVariable() ) - w = static_cast<const RenderTableCell *>(this)->table()->cellPadding(); - return w; -} - -int RenderObject::paddingLeft() const -{ - int w = 0; - Length padding = style()->paddingLeft(); - if (padding.isPercent()) - w = containingBlock()->contentWidth(); - w = padding.minWidth(w); - if ( isTableCell() && padding.isVariable() ) - w = static_cast<const RenderTableCell *>(this)->table()->cellPadding(); - return w; -} - -int RenderObject::paddingRight() const -{ - int w = 0; - Length padding = style()->paddingRight(); - if (padding.isPercent()) - w = containingBlock()->contentWidth(); - w = padding.minWidth(w); - if ( isTableCell() && padding.isVariable() ) - w = static_cast<const RenderTableCell *>(this)->table()->cellPadding(); - return w; -} - -RenderObject *RenderObject::container() const -{ - // This method is extremely similar to containingBlock(), but with a few notable - // exceptions. - // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when - // the object is not part of the primary document subtree yet. - // (2) For normal flow elements, it just returns the parent. - // (3) For absolute positioned elements, it will return a relative positioned inline. - // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle - // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and - // calcAbsoluteVertical have to use container(). - EPosition pos = m_style->position(); - RenderObject *o = 0; - if( pos == FIXED ) { - // container() can be called on an object that is not in the - // tree yet. We don't call canvas() since it will assert if it - // can't get back to the canvas. Instead we just walk as high up - // as we can. If we're in the tree, we'll get the root. If we - // aren't we'll get the root of our little subtree (most likely - // we'll just return 0). - o = parent(); - while ( o && o->parent() ) o = o->parent(); - } - else if ( pos == ABSOLUTE ) { - // Same goes here. We technically just want our containing block, but - // we may not have one if we're part of an uninstalled subtree. We'll - // climb as high as we can though. - o = parent(); - while (o && o->style()->position() == STATIC && !o->isCanvas()) - o = o->parent(); - } - else - o = parent(); - return o; -} - -DOM::DocumentImpl* RenderObject::document() const -{ - return m_node->getDocument(); -} - -void RenderObject::remove() -{ - if ( parent() ) - //have parent, take care of the tree integrity - parent()->removeChild(this); -} - -void RenderObject::removeFromObjectLists() -{ - // in destruction mode, don't care. - if ( !document()->renderer() ) return; - - if (isFloating()) { - RenderBlock* outermostBlock = containingBlock(); - for (RenderBlock* p = outermostBlock; p && !p->isCanvas() && p->containsFloat(this);) { - outermostBlock = p; - if (p->isFloatingOrPositioned()) - break; - p = p->containingBlock(); - } - - if (outermostBlock) - outermostBlock->markAllDescendantsWithFloatsForLayout(this); - } - - if (isPositioned()) { - RenderObject *p; - for (p = parent(); p; p = p->parent()) { - if (p->isRenderBlock()) - static_cast<RenderBlock*>(p)->removePositionedObject(this); - } - } -} - -RenderArena* RenderObject::renderArena() const -{ - return m_node->getDocument()->renderArena(); -} - -void RenderObject::detach() -{ - detachCounters(); - - deleteInlineBoxes(); - remove(); - - // make sure our DOM-node don't think we exist - if ( node() && node()->renderer() == this) - node()->setRenderer(0); - - // by default no refcounting - arenaDelete(renderArena(), this); -} - -void RenderObject::arenaDelete(RenderArena *arena, void *base) -{ -#ifndef NDEBUG - void *savedBase = baseOfRenderObjectBeingDeleted; - baseOfRenderObjectBeingDeleted = base; -#endif - delete this; -#ifndef NDEBUG - baseOfRenderObjectBeingDeleted = savedBase; -#endif - - // Recover the size left there for us by operator delete and free the memory. - arena->free(*(size_t *)base, base); -} - -void RenderObject::arenaDelete(RenderArena *arena) -{ - // static_cast unfortunately doesn't work, since we multiple inherit - // in eg. RenderWidget. - arenaDelete(arena, dynamic_cast<void *>(this)); -} - -FindSelectionResult RenderObject::checkSelectionPoint( int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int & offset, SelPointState &state ) -{ -#if 0 - NodeInfo info(true, false); - if ( nodeAtPoint( info, _x, _y, _tx, _ty ) && info.innerNode() ) - { - RenderObject* r = info.innerNode()->renderer(); - if ( r ) { - if ( r == this ) { - node = info.innerNode(); - offset = 0; // we have no text... - return SelectionPointInside; - } - else - return r->checkSelectionPoint( _x, _y, _tx, _ty, node, offset, state ); - } - } - //kdDebug(6030) << "nodeAtPoint Failed. Fallback - hmm, SelectionPointAfter" << endl; - node = 0; - offset = 0; - return SelectionPointAfter; -#endif - int off = offset; - DOM::NodeImpl* nod = node; - - for (RenderObject *child = firstChild(); child; child=child->nextSibling()) { - // ignore empty text boxes, they produce totally bogus information - // for caret navigation (LS) - if (child->isText() && !static_cast<RenderText *>(child)->inlineTextBoxCount()) - continue; - -// kdDebug(6040) << "iterating " << (child ? child->renderName() : "") << "@" << child << (child->isText() ? " contains: \"" + TQConstString(static_cast<RenderText *>(child)->text(), kMin(static_cast<RenderText *>(child)->length(), 10u)).string() + "\"" : TQString::null) << endl; -// kdDebug(6040) << "---------- checkSelectionPoint recursive -----------" << endl; - khtml::FindSelectionResult pos = child->checkSelectionPoint(_x, _y, _tx+xPos(), _ty+yPos(), nod, off, state); -// kdDebug(6040) << "-------- end checkSelectionPoint recursive ---------" << endl; -// kdDebug(6030) << this << " child->findSelectionNode returned result=" << pos << " nod=" << nod << " off=" << off << endl; - switch(pos) { - case SelectionPointBeforeInLine: - case SelectionPointInside: - //kdDebug(6030) << "RenderObject::checkSelectionPoint " << this << " returning SelectionPointInside offset=" << offset << endl; - node = nod; - offset = off; - return SelectionPointInside; - case SelectionPointBefore: - //x,y is before this element -> stop here - if ( state.m_lastNode ) { - node = state.m_lastNode; - offset = state.m_lastOffset; - //kdDebug(6030) << "RenderObject::checkSelectionPoint " << this << " before this child " - // << node << "-> returning SelectionPointInside, offset=" << offset << endl; - return SelectionPointInside; - } else { - node = nod; - offset = off; - //kdDebug(6030) << "RenderObject::checkSelectionPoint " << this << " before us -> returning SelectionPointBefore " << node << "/" << offset << endl; - return SelectionPointBefore; - } - break; - case SelectionPointAfter: - if (state.m_afterInLine) break; - // fall through - case SelectionPointAfterInLine: - if (pos == SelectionPointAfterInLine) state.m_afterInLine = true; - //kdDebug(6030) << "RenderObject::checkSelectionPoint: selection after: " << nod << " offset: " << off << " afterInLine: " << state.m_afterInLine << endl; - state.m_lastNode = nod; - state.m_lastOffset = off; - // No "return" here, obviously. We must keep looking into the children. - break; - } - } - // If we are after the last child, return lastNode/lastOffset - // But lastNode can be 0L if there is no child, for instance. - if ( state.m_lastNode ) - { - node = state.m_lastNode; - offset = state.m_lastOffset; - } - //kdDebug(6030) << "fallback - SelectionPointAfter node=" << node << " offset=" << offset << endl; - return SelectionPointAfter; -} - -bool RenderObject::mouseInside() const -{ - if (!m_mouseInside && continuation()) - return continuation()->mouseInside(); - return m_mouseInside; -} - -bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside) -{ - int tx = _tx + xPos(); - int ty = _ty + yPos(); - - inside |= ( style()->visibility() != HIDDEN && - (_y >= ty) && (_y < ty + height()) && (_x >= tx) && (_x < tx + width())) || isRoot() || isBody(); - bool inOverflowRect = inside; - if ( !inOverflowRect ) { - int ol = overflowLeft(); - int ot = overflowTop(); - TQRect overflowRect( tx+ol, ty+ot, overflowWidth()-ol, overflowHeight()-ot ); - inOverflowRect = overflowRect.contains( _x, _y ); - } - - // ### table should have its own, more performant method - if (hitTestAction != HitTestSelfOnly && - (( !isRenderBlock() || - !static_cast<RenderBlock*>( this )->isPointInScrollbar( _x, _y, _tx, _ty )) && - (overhangingContents() || inOverflowRect || isInline() || isRoot() || isCanvas() || - isTableRow() || isTableSection() || inside || mouseInside() ))) { - if ( hitTestAction == HitTestChildrenOnly ) - inside = false; - if ( hasOverflowClip() && layer() ) - layer()->subtractScrollOffset(tx, ty); - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) - if (!child->layer() && child->nodeAtPoint(info, _x, _y, tx, ty, HitTestAll)) - inside = true; - } - - if (inside) - setInnerNode(info); - - return inside; -} - - -void RenderObject::setInnerNode(NodeInfo& info) -{ - if (!info.innerNode() && !isInline() && continuation()) { - // We are in the margins of block elements that are part of a continuation. In - // this case we're actually still inside the enclosing inline element that was - // split. Go ahead and set our inner node accordingly. - info.setInnerNode(continuation()->element()); - if (!info.innerNonSharedNode()) - info.setInnerNonSharedNode(continuation()->element()); - } - - if (!info.innerNode() && element()) - info.setInnerNode(element()); - - if(!info.innerNonSharedNode() && element()) - info.setInnerNonSharedNode(element()); -} - - -short RenderObject::verticalPositionHint( bool firstLine ) const -{ - short vpos = m_verticalPosition; - if ( m_verticalPosition == PositionUndefined || firstLine ) { - vpos = getVerticalPosition( firstLine ); - if ( !firstLine ) - const_cast<RenderObject *>(this)->m_verticalPosition = vpos; - } - return vpos; - -} - -short RenderObject::getVerticalPosition( bool firstLine, RenderObject* ref ) const -{ - // vertical align for table cells has a different meaning - int vpos = 0; - if ( !isTableCell() && isInline() ) { - EVerticalAlign va = style()->verticalAlign(); - if ( va == TOP ) { - vpos = PositionTop; - } else if ( va == BOTTOM ) { - vpos = PositionBottom; - } else { - if (!ref) ref = parent(); - bool checkParent = ref->isInline() && !ref->isReplacedBlock() && - !( ref->style()->verticalAlign() == TOP || ref->style()->verticalAlign() == BOTTOM ); - vpos = checkParent ? ref->verticalPositionHint( firstLine ) : 0; - // don't allow elements nested inside text-top to have a different valignment. - if ( va == BASELINE ) - return vpos; - else if ( va == LENGTH ) - return vpos - style()->verticalAlignLength().width( lineHeight( firstLine ) ); - - const TQFont &f = ref->font( firstLine ); - int fontsize = f.pixelSize(); - - if ( va == SUB ) - vpos += fontsize/5 + 1; - else if ( va == SUPER ) - vpos -= fontsize/3 + 1; - else if ( va == TEXT_TOP ) { - vpos += baselinePosition( firstLine ) - (TQFontMetrics(f).ascent() + TQFontMetrics(f).leading()/2); - } else if ( va == MIDDLE ) { - TQRect b = TQFontMetrics(f).boundingRect('x'); - vpos += -b.height()/2 - lineHeight( firstLine )/2 + baselinePosition( firstLine ); - } else if ( va == TEXT_BOTTOM ) { - vpos += TQFontMetrics(f).descent() + TQFontMetrics(f).leading()/2; - if ( !isReplaced() ) - vpos -= fontMetrics(firstLine).descent(); - } else if ( va == BASELINE_MIDDLE ) - vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine ); - } - } - return vpos; -} - -short RenderObject::lineHeight( bool firstLine ) const -{ - // Inline blocks are replaced elements. Otherwise, just pass off to - // the base class. If we're being queried as though we're the root line - // box, then the fact that we're an inline-block is irrelevant, and we behave - // just like a block. - - if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout())) - return height()+marginTop()+marginBottom(); - - Length lh; - if( firstLine && hasFirstLine() ) { - RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LINE); - if ( pseudoStyle ) - lh = pseudoStyle->lineHeight(); - } - else - lh = style()->lineHeight(); - - // its "unset", choose nice default - if ( lh.value() < 0 ) - return style()->fontMetrics().lineSpacing(); - - if ( lh.isPercent() ) - return lh.minWidth( style()->font().pixelSize() ); - - // its fixed - return lh.value(); -} - -short RenderObject::baselinePosition( bool firstLine ) const -{ - // Inline blocks are replaced elements. Otherwise, just pass off to - // the base class. If we're being queried as though we're the root line - // box, then the fact that we're an inline-block is irrelevant, and we behave - // just like a block. - - if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout())) - return height()+marginTop()+marginBottom(); - - const TQFontMetrics &fm = fontMetrics( firstLine ); - return fm.ascent() + ( lineHeight( firstLine) - fm.height() ) / 2; -} - -void RenderObject::invalidateVerticalPositions() -{ - m_verticalPosition = PositionUndefined; - RenderObject *child = firstChild(); - while( child ) { - child->invalidateVerticalPositions(); - child = child->nextSibling(); - } -} - -void RenderObject::recalcMinMaxWidths() -{ - KHTMLAssert( m_recalcMinMax ); - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl; -#endif - - RenderObject *child = firstChild(); - int cmin=0; - int cmax=0; - - while( child ) { - bool test = false; - if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) { - cmin = child->minWidth(); - cmax = child->maxWidth(); - test = true; - } - if ( child->m_recalcMinMax ) - child->recalcMinMaxWidths(); - if ( !child->m_minMaxKnown ) - child->calcMinMaxWidth(); - if ( m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth()) ) - m_minMaxKnown = false; - child = child->nextSibling(); - } - - // we need to recalculate, if the contains inline children, as the change could have - // happened somewhere deep inside the child tree - if ( ( !isInline() || isReplacedBlock() ) && childrenInline() ) - m_minMaxKnown = false; - - if ( !m_minMaxKnown ) - calcMinMaxWidth(); - m_recalcMinMax = false; -} - -void RenderObject::scheduleRelayout(RenderObject *clippedObj) -{ - if (!isCanvas()) return; - KHTMLView *view = static_cast<RenderCanvas *>(this)->view(); - if ( view ) - view->scheduleRelayout(clippedObj); -} - - -void RenderObject::removeLeftoverAnonymousBoxes() -{ -} - -InlineBox* RenderObject::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/) -{ - KHTMLAssert(false); - return 0; -} - -void RenderObject::getTextDecorationColors(int decorations, TQColor& underline, TQColor& overline, - TQColor& linethrough, bool quirksMode) -{ - RenderObject* curr = this; - do { - RenderStyle *st = curr->style(); - int currDecs = st->textDecoration(); - if (currDecs) { - if (currDecs & UNDERLINE) { - decorations &= ~UNDERLINE; - underline = st->color(); - } - if (currDecs & OVERLINE) { - decorations &= ~OVERLINE; - overline = st->color(); - } - if (currDecs & LINE_THROUGH) { - decorations &= ~LINE_THROUGH; - linethrough = st->color(); - } - } - curr = curr->parent(); - if (curr && curr->isRenderBlock() && curr->continuation()) - curr = curr->continuation(); - } while (curr && decorations && (!quirksMode || !curr->element() || - (curr->element()->id() != ID_A && curr->element()->id() != ID_FONT))); - - // If we bailed out, use the element we bailed out at (typically a <font> or <a> element). - if (decorations && curr) { - RenderStyle *st = curr->style(); - if (decorations & UNDERLINE) - underline = st->color(); - if (decorations & OVERLINE) - overline = st->color(); - if (decorations & LINE_THROUGH) - linethrough = st->color(); - } -} - -int RenderObject::maximalOutlineSize(PaintAction p) const -{ - if (p != PaintActionOutline) - return 0; - return static_cast<RenderCanvas*>(document()->renderer())->maximalOutlineSize(); -} - -void RenderObject::collectBorders(TQValueList<CollapsedBorderValue>& borderStyles) -{ - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) - curr->collectBorders(borderStyles); -} - -bool RenderObject::flowAroundFloats() const -{ - return isReplaced() || hasOverflowClip() || style()->flowAroundFloats(); -} - -bool RenderObject::usesLineWidth() const -{ - // 1. All auto-width objects that avoid floats should always use lineWidth - // 2. For objects with a specified width, we match WinIE's behavior: - // (a) tables use contentWidth - // (b) <hr>s use lineWidth - // (c) all other objects use lineWidth in quirks mode and contentWidth in strict mode. - return (flowAroundFloats() && (style()->width().isVariable() || isHR() || (style()->htmlHacks() && !isTable()))); -} - -bool RenderObject::hasCounter(const TQString& counter) const -{ - if (style() && (!isText() || isCounter())) { - if (lookupCounter(counter)) return true; - if (style()->hasCounterReset(counter)) { - return true; - } - else if (style()->hasCounterIncrement(counter)) { - return true; - } - } - if (counter == "list-item") { - if (isListItem()) return true; - if (element() && ( - element()->id() == ID_OL || - element()->id() == ID_UL || - element()->id() == ID_MENU || - element()->id() == ID_DIR)) - return true; - } else - if (counter == "-khtml-quotes" && isQuote()) { - return (static_cast<const RenderQuote*>(this)->quoteCount() != 0); - } - return false; -} - -CounterNode* RenderObject::getCounter(const TQString& counter, bool view, bool counters) -{ -// kdDebug( 6040 ) << renderName() << " getCounter(" << counter << ")" << endl; - - if (!style()) return 0; - - if (isText() && !isCounter()) return 0; - - CounterNode *i = lookupCounter(counter); - if (i) return i; - int val = 0; - - if (style()->hasCounterReset(counter) || isRoot()) { - i = new CounterReset(this); - val = style()->counterReset(counter); - if (style()->hasCounterIncrement(counter)) { - val += style()->counterIncrement(counter); - } -// kdDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val << endl; - } - else - if (style()->hasCounterIncrement(counter)) { - i = new CounterNode(this); - val = style()->counterIncrement(counter); -// kdDebug( 6040 ) << renderName() << " counter-increment: " << counter << " " << val << endl; - } - else if (counter == "list-item") { - if (isListItem()) { - if (element() && element()->id() == ID_LI) { - DOMString v = static_cast<ElementImpl*>(element())->getAttribute(ATTR_VALUE); - if ( !v.isEmpty() ) { - i = new CounterReset(this); - val = v.toInt(); -// kdDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val << endl; - } - } - if (!i) { - i = new CounterNode(this); - val = 1; -// kdDebug( 6040 ) << renderName() << " counter-increment: " << counter << " " << val << endl; - } - } - else - if (element() && element()->id() == ID_OL) { - i = new CounterReset(this); - DOMString v = static_cast<ElementImpl*>(element())->getAttribute(ATTR_START); - if ( !v.isEmpty() ) - val = v.toInt()-1; - else - val = 0; -// kdDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val << endl; - } - else - if (element() && - (element()->id() == ID_UL || - element()->id() == ID_MENU|| - element()->id() == ID_DIR)) - { - i = new CounterReset(this); - val = 0; -// kdDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val << endl; - } - } - else if (counter == "-khtml-quotes" && isQuote()) { - i = new CounterNode(this); - val = static_cast<RenderQuote*>(this)->quoteCount(); - } - - if (!i) { - i = new CounterNode(this); - val = 0; -// kdDebug( 6040 ) << renderName() << " counter-increment: " << counter << " " << val << endl; - } - i->setValue(val); - if (view) i->setIsVisual(); - if (counters) i->setHasCounters(); - - insertCounter(counter, i); - - if (!isRoot()) { - CounterNode *last=0, *current=0; - RenderObject *n = previousSibling(); - while(n) { - if (n->hasCounter(counter)) { - current = n->getCounter(counter); - break; - } - else - n = n->previousSibling(); - } - last = current; - - CounterNode *sibling = current; - // counter-reset on same render-level is our counter-parent - if (last) { - // Found render-sibling, now search for later counter-siblings among its render-children - n = n->lastChild(); - while (n) { - if (n->hasCounter(counter)) { - current = n->getCounter(counter); - if (last->parent() == current->parent() || sibling == current->parent()) { - last = current; - // If the current counter is not the last, search deeper - if (current->nextSibling()) { - n = n->lastChild(); - continue; - } - else - break; - } - } - n = n->previousSibling(); - } - if (sibling->isReset()) - { - if (last != sibling) - sibling->insertAfter(i, last); - else - sibling->insertAfter(i, 0); - } - else if (last->parent()) - last->parent()->insertAfter(i, last); - } - else if (parent()) { - // Nothing found among siblings, let our parent search - last = parent()->getCounter(counter, false); - if (last->isReset()) - last->insertAfter(i, 0); - else if (last->parent()) - last->parent()->insertAfter(i, last); - } - } - - return i; -} - -CounterNode* RenderObject::lookupCounter(const TQString& counter) const -{ - TQDict<khtml::CounterNode>* counters = document()->counters(this); - if (counters) - return counters->find(counter); - else - return 0; -} - -void RenderObject::detachCounters() -{ - TQDict<khtml::CounterNode>* counters = document()->counters(this); - if (!counters) return; - - TQDictIterator<khtml::CounterNode> i(*counters); - - while (i.current()) { - (*i)->remove(); - delete (*i); - ++i; - } - document()->removeCounters(this); -} - -void RenderObject::insertCounter(const TQString& counter, CounterNode* val) -{ - TQDict<khtml::CounterNode>* counters = document()->counters(this); - - if (!counters) { - counters = new TQDict<khtml::CounterNode>(11); - document()->setCounters(this, counters); - } - - counters->insert(counter, val); -} - -void RenderObject::updateWidgetMasks() { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if ( curr->isWidget() && static_cast<RenderWidget*>(curr)->needsMask() ) { - TQWidget* w = static_cast<RenderWidget*>(curr)->widget(); - if (!w) - return; - RenderLayer* l = curr->enclosingStackingContext(); - TQRegion r = l ? l->getMask() : TQRegion(); - int x,y; - if (!r.isNull() && curr->absolutePosition(x,y)) { - int pbx = curr->borderLeft()+curr->paddingLeft(); - int pby = curr->borderTop()+curr->paddingTop(); - x+= pbx; - y+= pby; - r = r.intersect(TQRect(x,y, - curr->width()-pbx-curr->borderRight()-curr->paddingRight(), - curr->height()-pby-curr->borderBottom()-curr->paddingBottom())); -#ifdef MASK_DEBUG - TQMemArray<TQRect> ar = r.rects(); - kdDebug(6040) << "|| Setting widget mask for " << curr->information() << endl; - for (int i = 0; i < ar.size() ; ++i) { - kdDebug(6040) << " " << ar[i] << endl; - } -#endif - r.translate(-x,-y); - w->setMask(r); - } else { - w->clearMask(); - } - } - else if (!curr->layer() || !curr->layer()->isStackingContext()) - curr->updateWidgetMasks(); - - } -} - -TQRegion RenderObject::visibleFlowRegion(int x, int y) const -{ - TQRegion r; - for (RenderObject* ro=firstChild();ro;ro=ro->nextSibling()) { - if( !ro->layer() && !ro->isInlineFlow() && ro->style()->visibility() == VISIBLE) { - const RenderStyle *s = ro->style(); - if (ro->isRelPositioned()) - static_cast<const RenderBox*>(ro)->relativePositionOffset(x,y); - if ( s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() ) - r += TQRect(x + ro->effectiveXPos(),y + ro->effectiveYPos(), ro->effectiveWidth(), ro->effectiveHeight()); - else - r += ro->visibleFlowRegion(x+ro->xPos(), y+ro->yPos()); - } - } - return r; -} - -#undef RED_LUMINOSITY -#undef GREEN_LUMINOSITY -#undef BLUE_LUMINOSITY -#undef INTENSITY_FACTOR -#undef LIGHT_FACTOR -#undef LUMINOSITY_FACTOR - -#undef MAX_COLOR -#undef COLOR_DARK_THRESHOLD -#undef COLOR_LIGHT_THRESHOLD - -#undef COLOR_LITE_BS_FACTOR -#undef COLOR_LITE_TS_FACTOR - -#undef COLOR_DARK_BS_FACTOR -#undef COLOR_DARK_TS_FACTOR - -#undef LIGHT_GRAY -#undef DARK_GRAY - diff --git a/khtml/rendering/render_object.h b/khtml/rendering/render_object.h deleted file mode 100644 index e15dabbbc..000000000 --- a/khtml/rendering/render_object.h +++ /dev/null @@ -1,866 +0,0 @@ -/* - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2002-2003 Apple Computer, Inc. - * (C) 2004 Allan Sandfeld Jensen - * - * 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. - * - */ -#ifndef render_object_h -#define render_object_h - -#include <tqcolor.h> -#include <tqrect.h> -#include <assert.h> -#include <tqvaluelist.h> - -#include <kdebug.h> -#include <kglobal.h> - -#include "xml/dom_docimpl.h" -#include "misc/khtmllayout.h" -#include "misc/loader_client.h" -#include "misc/helper.h" -#include "rendering/render_style.h" - -class TQPainter; -class TQTextStream; -class CSSStyle; -class KHTMLView; - -#ifndef NDEBUG -#define KHTMLAssert( x ) if( !(x) ) { \ - const RenderObject *o = this; while( o->parent() ) o = o->parent(); \ - o->printTree(); \ - tqDebug(" this object = %p, %s", (void*) this, kdBacktrace().latin1() ); \ - assert( x ); \ -} -#else -#define KHTMLAssert( x ) -#endif - -/* - * The painting of a layer occurs in three distinct phases. Each phase involves - * a recursive descent into the layer's render objects. The first phase is the background phase. - * The backgrounds and borders of all blocks are painted. Inlines are not painted at all. - * Floats must paint above block backgrounds but entirely below inline content that can overlap them. - * In the foreground phase, all inlines are fully painted. Inline replaced elements will get all - * three phases invoked on them during this phase. - */ - -typedef enum { - PaintActionElementBackground = 0, - PaintActionChildBackground, - PaintActionChildBackgrounds, - PaintActionFloat, - PaintActionForeground, - PaintActionOutline, - PaintActionSelection, - PaintActionCollapsedTableBorders -} PaintAction; - -typedef enum { - HitTestAll = 0, - HitTestSelfOnly = 1, - HitTestChildrenOnly = 2 -} HitTestAction; - -typedef enum { - PageBreakNormal = 0, // all rules apply - PageBreakHarder = 1, // page-break-inside: avoid is ignored - PageBreakForced = 2 // page-break-after/before: avoid, orphans and widows ignored -} PageBreakLevel; - -typedef enum { - LowPriority = 0, - NormalPriority = 1, - HighPriority = 2, - RealtimePriority = 3 -} Priority; - -inline PageBreakLevel operator| (PageBreakLevel a, PageBreakLevel b) { - if (a == PageBreakForced || b == PageBreakForced) - return PageBreakForced; - if (a == PageBreakHarder || b == PageBreakHarder) - return PageBreakHarder; - return PageBreakNormal; -} - -namespace DOM { - class HTMLAreaElementImpl; - class DOMString; - class NodeImpl; - class DocumentImpl; - class ElementImpl; - class EventImpl; -} - -namespace khtml { - class RenderFlow; - class RenderStyle; - class RenderTable; - class CachedObject; - class RenderObject; - class RenderCanvas; - class RenderText; - class RenderFrameSet; - class RenderArena; - class RenderLayer; - class RenderBlock; - class InlineBox; - class InlineFlowBox; - class CounterNode; - -/** - * Base Class for all rendering tree objects. - */ -class RenderObject : public CachedObjectClient -{ - RenderObject(const RenderObject&); - RenderObject& operator=(const RenderObject&); -public: - - RenderObject(DOM::NodeImpl* node); - virtual ~RenderObject(); - - RenderObject *parent() const { return m_parent; } - - RenderObject *previousSibling() const { return m_previous; } - RenderObject *nextSibling() const { return m_next; } - - virtual RenderObject *firstChild() const { return 0; } - virtual RenderObject *lastChild() const { return 0; } - - RenderObject *nextRenderer() const; - RenderObject *previousRenderer() const; - - virtual bool childAllowed() const { return false; } - virtual int borderTopExtra() const { return 0; } - virtual int borderBottomExtra() const { return 0; } - - virtual RenderLayer* layer() const { return 0; } - RenderLayer* enclosingLayer() const; - RenderLayer* enclosingStackingContext() const; - void addLayers(RenderLayer* parentLayer, RenderObject* newObject); - void removeLayers(RenderLayer* parentLayer); - void moveLayers(RenderLayer* oldParent, RenderLayer* newParent); - RenderLayer* findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, - bool checkParent=true); - virtual void positionChildLayers() { } - virtual bool requiresLayer() const { - return isRoot()/* ### */ || isPositioned() || isRelPositioned() || hasOverflowClip(); - } - - // ### rename to overflowClipRect and clipRect - virtual TQRect getOverflowClipRect(int /*tx*/, int /*ty*/) - { return TQRect(0,0,0,0); } - virtual TQRect getClipRect(int /*tx*/, int /*ty*/) { return TQRect(0,0,0,0); } - bool hasClip() const { return isPositioned() && style()->hasClip(); } - bool hasOverflowClip() const { return m_hasOverflowClip; } - - bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } - bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } - bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } - - virtual int getBaselineOfFirstLineBox() { return -1; } // Tables and blocks implement this. - virtual InlineFlowBox* getFirstLineBox() { return 0; } // Tables and blocks implement this. - - // Whether or not a positioned element requires normal flow x/y to be computed - // to determine its position. - bool hasStaticX() const; - bool hasStaticY() const; - - // Linear tree traversal - RenderObject *objectBelow() const; - RenderObject *objectAbove() const; - - // Returns if an object has counter-increment or counter-reset - bool hasCounter(const TQString& counter) const; - // Calculates the value of the counter - CounterNode* getCounter(const TQString& counter, bool view = false, bool counters = false); - // Detaches all counterNodes - void detachCounters(); - - -protected: - // Helper functions for counter-cache - void insertCounter(const TQString& counter, CounterNode* value); - CounterNode* lookupCounter(const TQString& counter) const; - -public: - ////////////////////////////////////////// - // RenderObject tree manipulation - virtual void addChild(RenderObject *newChild, RenderObject *beforeChild = 0); - void removeChild(RenderObject *oldChild); - - // raw tree manipulation - virtual RenderObject* removeChildNode(RenderObject* child); - virtual void appendChildNode(RenderObject* child); - virtual void insertChildNode(RenderObject* child, RenderObject* before); - ////////////////////////////////////////// - - ////////////////////////////////////////// - // Helper functions. Dangerous to use! - void setPreviousSibling(RenderObject *previous) { m_previous = previous; } - void setNextSibling(RenderObject *next) { m_next = next; } - void setParent(RenderObject *parent) { m_parent = parent; } - ////////////////////////////////////////// - -public: - virtual const char *renderName() const { return "RenderObject"; } -#ifdef ENABLE_DUMP - TQString information() const; - virtual void printTree(int indent=0) const; - virtual void dump(TQTextStream &stream, const TQString &ind = TQString::null) const; -#endif - - static RenderObject *createObject(DOM::NodeImpl* node, RenderStyle* style); - - // Overloaded new operator. Derived classes must override operator new - // in order to allocate out of the RenderArena. - void* operator new(size_t sz, RenderArena* renderArena) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* ptr, size_t sz); - -private: - // The normal operator new is disallowed on all render objects. - void* operator new(size_t sz); - -public: - RenderArena* renderArena() const; - virtual RenderFlow* continuation() const { return 0; } - virtual bool isInlineContinuation() const { return false; } - - - bool isRoot() const { return m_isRoot && !m_isAnonymous; } - void setIsRoot(bool b) { m_isRoot = b; } - bool isHR() const; - // some helper functions... - virtual bool isRenderBlock() const { return false; } - virtual bool isRenderInline() const { return false; } - virtual bool isInlineFlow() const { return false; } - virtual bool isBlockFlow() const { return false; } - virtual bool isInlineBlockOrInlineTable() const { return false; } - virtual bool childrenInline() const { return false; } - virtual bool isBox() const { return false; } - virtual bool isRenderReplaced() const { return false; } - - virtual bool isGlyph() const { return false; } - virtual bool isCounter() const { return false; } - virtual bool isQuote() const { return false; } - virtual bool isListItem() const { return false; } - virtual bool isListMarker() const { return false; } - virtual bool isCanvas() const { return false; } - virtual bool isBR() const { return false; } - virtual bool isTableCell() const { return false; } - virtual bool isTableRow() const { return false; } - virtual bool isTableSection() const { return false; } - virtual bool isTableCol() const { return false; } - virtual bool isTable() const { return false; } - virtual bool isWidget() const { return false; } - virtual bool isBody() const { return false; } - virtual bool isFormElement() const { return false; } - virtual bool isFrameSet() const { return false; } - virtual bool isApplet() const { return false; } - - bool isHTMLMarquee() const; - bool isWordBreak() const; - - bool isAnonymous() const { return m_isAnonymous; } - void setIsAnonymous(bool b) { m_isAnonymous = b; } - bool isAnonymousBlock() const { return isAnonymous() && style()->display() == BLOCK && node()->isDocumentNode(); } - bool isPseudoAnonymous() const { return isAnonymous() && !node()->isDocumentNode(); } - - bool isFloating() const { return m_floating; } - bool isPositioned() const { return m_positioned; } - bool isRelPositioned() const { return m_relPositioned; } - bool isText() const { return m_isText; } - bool isInline() const { return m_inline; } - bool isCompact() const { return style()->display() == COMPACT; } // compact - bool isRunIn() const { return style()->display() == RUN_IN; } // run-in object - bool mouseInside() const; - bool isReplaced() const { return m_replaced; } - bool isReplacedBlock() const { return isInline() && isReplaced() && isRenderBlock(); } - bool shouldPaintBackgroundOrBorder() const { return m_paintBackground; } - bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout; } - bool markedForRepaint() const { return m_markedForRepaint; } - void setMarkedForRepaint(bool m) { m_markedForRepaint = m; } - bool selfNeedsLayout() const { return m_needsLayout; } - bool posChildNeedsLayout() const { return m_posChildNeedsLayout; } - bool normalChildNeedsLayout() const { return m_normalChildNeedsLayout; } - bool minMaxKnown() const{ return m_minMaxKnown; } - bool overhangingContents() const { return m_overhangingContents; } - bool hasFirstLine() const { return m_hasFirstLine; } - bool isSelectionBorder() const { return m_isSelectionBorder; } - bool recalcMinMax() const { return m_recalcMinMax; } - - RenderCanvas* canvas() const; - // don't even think about making this method virtual! - DOM::DocumentImpl* document() const; - DOM::NodeImpl* element() const { return isAnonymous() ? 0L : m_node; } - DOM::NodeImpl* node() const { return m_node; } - - /** - * returns the object containing this one. can be different from parent for - * positioned elements - */ - RenderObject *container() const; - - void setOverhangingContents(bool p=true); - void markContainingBlocksForLayout(); - void dirtyFormattingContext( bool checkContainer ); - void repaintDuringLayout(); - void setNeedsLayout(bool b, bool markParents = true); - void setChildNeedsLayout(bool b, bool markParents = true); - void setMinMaxKnown(bool b=true) { - m_minMaxKnown = b; - if ( !b ) { - RenderObject *o = this; - RenderObject *root = this; - while( o ) { // ### && !o->m_recalcMinMax ) { - o->m_recalcMinMax = true; - root = o; - o = o->m_parent; - } - } - } - void setNeedsLayoutAndMinMaxRecalc() { - setMinMaxKnown(false); - setNeedsLayout(true); - } - void setPositioned(bool b=true) { m_positioned = b; } - void setRelPositioned(bool b=true) { m_relPositioned = b; } - void setFloating(bool b=true) { m_floating = b; } - void setInline(bool b=true) { m_inline = b; } - void setMouseInside(bool b=true) { m_mouseInside = b; } - void setShouldPaintBackgroundOrBorder(bool b=true) { m_paintBackground = b; } - void setRenderText() { m_isText = true; } - void setReplaced(bool b=true) { m_replaced = b; } - void setHasOverflowClip(bool b = true) { m_hasOverflowClip = b; } - void setIsSelectionBorder(bool b=true) { m_isSelectionBorder = b; } - - void scheduleRelayout(RenderObject *clippedObj = 0); - - void updateBackgroundImages(RenderStyle* oldStyle); - - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox); - - virtual short lineHeight( bool firstLine ) const; - virtual short verticalPositionHint( bool firstLine ) const; - virtual short baselinePosition( bool firstLine ) const; - short getVerticalPosition( bool firstLine, RenderObject* ref=0 ) const; - - /* - * Print the object and its children, clipped by (x|y|w|h). - * (tx|ty) is the calculated position of the parent - */ - struct PaintInfo { - PaintInfo(TQPainter* _p, const TQRect& _r, PaintAction _phase) - : p(_p), r(_r), phase(_phase), outlineObjects(0) {} - ~PaintInfo() { delete outlineObjects; } - TQPainter* p; - TQRect r; - PaintAction phase; - TQValueList<RenderFlow *>* outlineObjects; // used to list which outlines should be painted by a block with inline children - }; - virtual void paint( PaintInfo& i, int tx, int ty); - - void paintBorder(TQPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin=true, bool end=true); - void paintOutline(TQPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style); - - virtual void paintBoxDecorations(PaintInfo&, int /*_tx*/, int /*_ty*/) {} - - virtual void paintBackgroundExtended(TQPainter* /*p*/, const TQColor& /*c*/, const BackgroundLayer */*bgLayer*/, - int /*clipy*/, int /*cliph*/, int /*_tx*/, int /*_ty*/, - int /*w*/, int /*height*/, int /*bleft*/, int /*bright*/, int /*pleft*/, int /*pright*/ ) {} - - - /* - * This function calculates the minimum & maximum width that the object - * can be set to. - * - * when the Element calls setMinMaxKnown(true), calcMinMaxWidth() will - * be no longer called. - * - * when a element has a fixed size, m_minWidth and m_maxWidth should be - * set to the same value. This has the special meaning that m_width, - * contains the actual value. - * - * assumes calcMinMaxWidth has already been called for all children. - */ - virtual void calcMinMaxWidth() { } - - /* - * Does the min max width recalculations after changes. - */ - void recalcMinMaxWidths(); - - /* - * Calculates the actual width of the object (only for non inline - * objects) - */ - virtual void calcWidth() {} - - /* - * Calculates the actual width of the object (only for non inline - * objects) - */ - virtual void calcHeight() {} - - /* - * This function should cause the Element to calculate its - * width and height and the layout of its content - * - * when the Element calls setNeedsLayout(false), layout() is no - * longer called during relayouts, as long as there is no - * style sheet change. When that occurs, m_needsLayout will be - * set to true and the Element receives layout() calls - * again. - */ - virtual void layout() = 0; - - /* This function performs a layout only if one is needed. */ - void layoutIfNeeded() { if (needsLayout()) layout(); } - - // used for element state updates that can not be fixed with a - // repaint and do not need a relayout - virtual void updateFromElement() {} - - // Called immediately after render-object is inserted - virtual void attach() { m_attached = true; } - bool attached() { return m_attached; } - // The corresponding closing element has been parsed. ### remove me - virtual void close() { } - - virtual int availableHeight() const { return 0; } - - // Whether or not the element shrinks to its max width (rather than filling the width - // of a containing block). HTML4 buttons, legends, and floating/compact elements do this. - bool sizesToMaxWidth() const; - - /* - * NeesPageClear indicates the object crossed a page-break but could not break itself and now - * needs to be moved clear by its parent. - */ - void setNeedsPageClear(bool b = true) { m_needsPageClear = b; } - virtual bool needsPageClear() const { return m_needsPageClear; } - - /* - * ContainsPageBreak indicates the object contains a clean page-break. - * ### should be removed and replaced with (crossesPageBreak && !needsPageClear) - */ - void setContainsPageBreak(bool b = true) { m_containsPageBreak = b; } - virtual bool containsPageBreak() const { return m_containsPageBreak; } - - virtual int pageTopAfter(int y) const { if (parent()) return parent()->pageTopAfter(y); else return 0; } - - virtual int crossesPageBreak(int top, int bottom) const - { if (parent()) return parent()->crossesPageBreak(top, bottom); else return 0; } - - // Checks if a page-break before child is possible at the given page-break level - // false means the child should attempt the break self. - virtual bool canClear(RenderObject */*child*/, PageBreakLevel level) - { if (parent()) return parent()->canClear(this, level); else return false; } - - void setAfterPageBreak(bool b = true) { m_afterPageBreak = b; }; - void setBeforePageBreak(bool b = true) { m_beforePageBreak = b; }; - virtual bool afterPageBreak() const { return m_afterPageBreak; } - virtual bool beforePageBreak() const { return m_beforePageBreak; } - - // does a query on the rendertree and finds the innernode - // and overURL for the given position - // if readonly == false, it will recalc hover styles accordingly - class NodeInfo - { - friend class RenderImage; - friend class RenderFlow; - friend class RenderInline; - friend class RenderText; - friend class RenderWidget; - friend class RenderObject; - friend class RenderFrameSet; - friend class RenderLayer; - friend class DOM::HTMLAreaElementImpl; - public: - NodeInfo(bool readonly, bool active) - : m_innerNode(0), m_innerNonSharedNode(0), m_innerURLElement(0), m_readonly(readonly), m_active(active) - { } - - DOM::NodeImpl* innerNode() const { return m_innerNode; } - DOM::NodeImpl* innerNonSharedNode() const { return m_innerNonSharedNode; } - DOM::NodeImpl* URLElement() const { return m_innerURLElement; } - bool readonly() const { return m_readonly; } - bool active() const { return m_active; } - - private: - void setInnerNode(DOM::NodeImpl* n) { m_innerNode = n; } - void setInnerNonSharedNode(DOM::NodeImpl* n) { m_innerNonSharedNode = n; } - void setURLElement(DOM::NodeImpl* n) { m_innerURLElement = n; } - - DOM::NodeImpl* m_innerNode; - DOM::NodeImpl* m_innerNonSharedNode; - DOM::NodeImpl* m_innerURLElement; - bool m_readonly; - bool m_active; - }; - - /** contains stateful information for a checkSelectionPoint call - */ - struct SelPointState { - /** last node that was before the current position */ - DOM::NodeImpl *m_lastNode; - /** offset of last node */ - long m_lastOffset; - /** true when the last node had the result SelectionAfterInLine */ - bool m_afterInLine; - - SelPointState() : m_lastNode(0), m_lastOffset(0), m_afterInLine(false) - {} - }; - - virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty, - DOM::NodeImpl*&, int & offset, - SelPointState & ); - virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction, bool inside = false); - void setInnerNode(NodeInfo& info); - - // set the style of the object. - virtual void setStyle(RenderStyle *style); - - // returns the containing block level element for this element. - RenderBlock *containingBlock() const; - - // return just the width of the containing block - virtual short containingBlockWidth() const; - // return just the height of the containing block - virtual int containingBlockHeight() const; - - // size of the content area (box size minus padding/border) - virtual short contentWidth() const { return 0; } - virtual int contentHeight() const { return 0; } - - // intrinsic extend of replaced elements. undefined otherwise - virtual short intrinsicWidth() const { return 0; } - virtual int intrinsicHeight() const { return 0; } - - // relative to parent node - virtual void setPos( int /*xPos*/, int /*yPos*/ ) { } - virtual void setWidth( int /*width*/ ) { } - virtual void setHeight( int /*height*/ ) { } - - virtual int xPos() const { return 0; } - virtual int yPos() const { return 0; } - - /** the position of the object from where it begins drawing, including - * its negative overflow - */ - int effectiveXPos() const { return xPos() + (hasOverflowClip() ? 0 : overflowLeft()); } - - /** the position of the object from where it begins drawing, including - * its negative overflow - */ - int effectiveYPos() const { return yPos() + (hasOverflowClip() ? -borderTopExtra() : kMin(overflowTop(), -borderTopExtra())); } - - /** Leftmost coordinate of this inline element relative to containing - * block. Always zero for non-inline elements. - */ - virtual int inlineXPos() const { return 0; } - /** Topmost coordinate of this inline element relative to containing - * block. Always zero for non-inline elements. - */ - virtual int inlineYPos() const { return 0; } - - // calculate client position of box - virtual bool absolutePosition(int &/*xPos*/, int &/*yPos*/, bool fixed = false) const; - - // width and height are without margins but include paddings and borders - virtual short width() const { return 0; } - virtual int height() const { return 0; } - - // The height of a block when you include overflow spillage out of - // the bottom of the block (e.g., a <div style="height:25px"> that - // has a 100px tall image inside it would have an overflow height - // of borderTop() + paddingTop() + 100px. - virtual int overflowHeight() const { return height(); } - virtual int overflowWidth() const { return width(); } - // how much goes over the left hand side (0 or a negative number) - virtual int overflowTop() const { return 0; } - virtual int overflowLeft() const { return 0; } - - /** - * Returns the height that is effectively considered when contemplating the - * object as a whole -- usually the overflow height, or the height if clipped. - */ - int effectiveHeight() const { return hasOverflowClip() ? height() + borderTopExtra() + borderBottomExtra() : - kMax(overflowHeight() - overflowTop(), height() + borderTopExtra() + borderBottomExtra()); } - /** - * Returns the width that is effectively considered when contemplating the - * object as a whole -- usually the overflow width, or the width if clipped. - */ - int effectiveWidth() const { return hasOverflowClip() ? width() : overflowWidth() - overflowLeft(); } - - // IE extensions, heavily used in ECMA - virtual short offsetWidth() const { return width(); } - virtual int offsetHeight() const { return height() + borderTopExtra() + borderBottomExtra(); } - virtual int offsetLeft() const; - virtual int offsetTop() const; - virtual RenderObject* offsetParent() const; - short clientWidth() const; - int clientHeight() const; - short scrollWidth() const; - int scrollHeight() const; - - virtual bool isSelfCollapsingBlock() const { return false; } - short collapsedMarginTop() const { return maxTopMargin(true)-maxTopMargin(false); } - short collapsedMarginBottom() const { return maxBottomMargin(true)-maxBottomMargin(false); } - - virtual bool isTopMarginQuirk() const { return false; } - virtual bool isBottomMarginQuirk() const { return false; } - virtual short maxTopMargin(bool positive) const - { return positive ? kMax( int( marginTop() ), 0 ) : - kMin( int( marginTop() ), 0 ); } - virtual short maxBottomMargin(bool positive) const - { return positive ? kMax( int( marginBottom() ), 0 ) : - kMin( int( marginBottom() ), 0 ); } - - virtual short marginTop() const { return 0; } - virtual short marginBottom() const { return 0; } - virtual short marginLeft() const { return 0; } - virtual short marginRight() const { return 0; } - - virtual int paddingTop() const; - virtual int paddingBottom() const; - virtual int paddingLeft() const; - virtual int paddingRight() const; - - virtual int borderTop() const { return style()->borderTopWidth(); } - virtual int borderBottom() const { return style()->borderBottomWidth(); } - virtual int borderLeft() const { return style()->borderLeftWidth(); } - virtual int borderRight() const { return style()->borderRightWidth(); } - - virtual short minWidth() const { return 0; } - virtual int maxWidth() const { return 0; } - - RenderStyle* style() const { return m_style; } - RenderStyle* style( bool firstLine ) const { - RenderStyle *s = m_style; - if( firstLine && hasFirstLine() ) { - RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LINE); - if ( pseudoStyle ) - s = pseudoStyle; - } - return s; - } - - void getTextDecorationColors(int decorations, TQColor& underline, TQColor& overline, - TQColor& linethrough, bool quirksMode=false); - - enum BorderSide { - BSTop, BSBottom, BSLeft, BSRight - }; - void drawBorder(TQPainter *p, int x1, int y1, int x2, int y2, BorderSide s, - TQColor c, const TQColor& textcolor, EBorderStyle style, - int adjbw1, int adjbw2, bool invalidisInvert = false); - - // Used by collapsed border tables. - virtual void collectBorders(TQValueList<CollapsedBorderValue>& borderStyles); - - // force a complete repaint - virtual void repaint(Priority p = NormalPriority) { if(m_parent) m_parent->repaint(p); } - virtual void repaintRectangle(int x, int y, int w, int h, Priority p=NormalPriority, bool f=false); - - virtual unsigned int length() const { return 1; } - - virtual bool isHidden() const { return isFloating() || isPositioned(); } - - // Special objects are objects that are neither really inline nor blocklevel - bool isFloatingOrPositioned() const { return (isFloating() || isPositioned()); }; - virtual bool hasOverhangingFloats() const { return false; } - virtual bool hasFloats() const { return false; } - virtual bool containsFloat(RenderObject* /*o*/) const { return false; } - virtual void markAllDescendantsWithFloatsForLayout(RenderObject* /*floatToRemove*/ = 0) {} - - bool flowAroundFloats() const; - bool usesLineWidth() const; - - // positioning of inline children (bidi) - virtual void position(InlineBox*, int, int, bool) {} -// virtual void position(int, int, int, int, int, bool, bool, int) {} - - // Applied as a "slop" to dirty rect checks during the outline painting phase's dirty-rect checks. - int maximalOutlineSize(PaintAction p) const; - - enum SelectionState { - SelectionNone, - SelectionStart, - SelectionInside, - SelectionEnd, - SelectionBoth - }; - - virtual SelectionState selectionState() const { return SelectionNone;} - virtual void setSelectionState(SelectionState) {} - - /** - * Flags which influence the appearence and position - * @param CFOverride input overrides existing character, caret should be - * cover the whole character - * @param CFOutside coordinates are to be interpreted outside of the - * render object - * @param CFOutsideEnd coordinates are to be interpreted at the outside - * end of the render object (only valid if CFOutside is also set) - */ - enum CaretFlags { CFOverride = 0x01, CFOutside = 0x02, CFOutsideEnd = 0x04 }; - - /** - * Returns the content coordinates of the caret within this render object. - * @param offset zero-based offset determining position within the render object. - * @param flags combination of enum CaretFlags - * @param _x returns the left coordinate - * @param _y returns the top coordinate - * @param width returns the caret's width - * @param height returns the caret's height - */ - virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height); - - // returns the lowest position of the lowest object in that particular object. - // This 'height' is relative to the topleft of the margin box of the object. - // Implemented in RenderFlow. - virtual int lowestPosition(bool /*includeOverflowInterior*/=true, bool /*includeSelf*/=true) const { return 0; } - virtual int rightmostPosition(bool /*includeOverflowInterior*/=true, bool /*includeSelf*/=true) const { return 0; } - virtual int leftmostPosition(bool /*includeOverflowInterior*/=true, bool /*includeSelf*/=true) const { return 0; } - virtual int highestPosition(bool /*includeOverflowInterior*/=true, bool /*includeSelf*/=true) const { return 0; } - - // recursively invalidate current layout - // unused: void invalidateLayout(); - - virtual void calcVerticalMargins() {} - void removeFromObjectLists(); - - virtual void deleteInlineBoxes(RenderArena* arena=0) {(void)arena;} - virtual void detach( ); - - void setDoNotDelete(bool b) { m_doNotDelete = b; } - bool doNotDelete() const { return m_doNotDelete; } - - const TQFont &font(bool firstLine) const { - return style( firstLine )->font(); - } - - const TQFontMetrics &fontMetrics(bool firstLine) const { - return style( firstLine )->fontMetrics(); - } - - /** returns the lowest possible value the caret offset may have to - * still point to a valid position. - * - * Returns 0 by default. - */ - virtual long minOffset() const { return 0; } - /** returns the highest possible value the caret offset may have to - * still point to a valid position. - * - * Returns 0 by default, as generic elements are considered to have no - * width. - */ - virtual long maxOffset() const { return 0; } - - virtual void setPixmap(const TQPixmap &, const TQRect&, CachedImage *); - - TQRegion visibleFlowRegion(int x, int y) const; - -protected: - virtual void selectionStartEnd(int& spos, int& epos); - - virtual TQRect viewRect() const; - void remove(); - void invalidateVerticalPositions(); - bool attemptDirectLayerTranslation(); - void updateWidgetMasks(); - - virtual void removeLeftoverAnonymousBoxes(); - - void arenaDelete(RenderArena *arena); - -private: - RenderStyle* m_style; - DOM::NodeImpl* m_node; - RenderObject *m_parent; - RenderObject *m_previous; - RenderObject *m_next; - - short m_verticalPosition; - - bool m_needsLayout : 1; - bool m_normalChildNeedsLayout : 1; - bool m_markedForRepaint : 1; - bool m_posChildNeedsLayout : 1; - - bool m_minMaxKnown : 1; - bool m_floating : 1; - - bool m_positioned : 1; - bool m_overhangingContents : 1; - bool m_relPositioned : 1; - bool m_paintBackground : 1; // if the box has something to paint in the - // background painting phase (background, border, etc) - - bool m_isAnonymous : 1; - bool m_recalcMinMax : 1; - bool m_isText : 1; - bool m_inline : 1; - bool m_attached : 1; - - bool m_replaced : 1; - bool m_mouseInside : 1; - bool m_hasFirstLine : 1; - bool m_isSelectionBorder : 1; - - bool m_isRoot : 1; - - bool m_beforePageBreak : 1; - bool m_afterPageBreak : 1; - - bool m_needsPageClear : 1; - bool m_containsPageBreak : 1; - - bool m_hasOverflowClip : 1; - - bool m_doNotDelete : 1; // This object should not be auto-deleted - - // ### we have 16 + 26 bits. - - - void arenaDelete(RenderArena *arena, void *objectBase); - - friend class RenderLayer; - friend class RenderListItem; - friend class RenderContainer; - friend class RenderCanvas; -}; - - -enum VerticalPositionHint { - PositionTop = -0x4000, - PositionBottom = 0x4000, - PositionUndefined = 0x3fff -}; - -} //namespace -#endif diff --git a/khtml/rendering/render_replaced.cpp b/khtml/rendering/render_replaced.cpp deleted file mode 100644 index 319f842e7..000000000 --- a/khtml/rendering/render_replaced.cpp +++ /dev/null @@ -1,940 +0,0 @@ -/** - * 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_layer.h" -#include "render_canvas.h" -#include "render_line.h" - -#include "render_arena.h" - -#include <assert.h> -#include <tqwidget.h> -#include <tqpainter.h> -#include <tqevent.h> -#include <tqapplication.h> -#include <tqlineedit.h> -#include <kglobalsettings.h> -#include <tqobjectlist.h> -#include <tqvaluevector.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 = 300; - 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_arena.reset(renderArena()); - m_resizePending = false; - m_discardResizes = false; - m_isKHTMLWidget = false; - m_needsMask = 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 TQWidgetResizeEvent : public TQEvent -{ -public: - enum { Type = TQEvent::User + 0xbee }; - TQWidgetResizeEvent( int _w, int _h ) : - TQEvent( ( TQEvent::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 = isKHTMLWidget(); - ref(); - element()->ref(); - TQApplication::postEvent( this, new TQWidgetResizeEvent( w, h ) ); - element()->deref(); - deref(); - } -} - -void RenderWidget::cancelPendingResize() -{ - if (!m_widget) - return; - m_discardResizes = true; - TQApplication::sendPostedEvents(this, TQWidgetResizeEvent::Type); - m_discardResizes = false; -} - -bool RenderWidget::event( TQEvent *e ) -{ - if ( m_widget && (e->type() == (TQEvent::Type)TQWidgetResizeEvent::Type) ) { - m_resizePending = false; - if (m_discardResizes) - return true; - TQWidgetResizeEvent *re = static_cast<TQWidgetResizeEvent *>(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 ( ::tqqt_cast<KHTMLView *>( m_widget ) ) - return TQObject::event( e ); - return true; -} - -void RenderWidget::flushWidgetResizes() //static -{ - TQApplication::sendPostedEvents( 0, TQWidgetResizeEvent::Type ); -} - -void RenderWidget::setQWidget(TQWidget *widget) -{ - if (widget != m_widget) - { - if (m_widget) { - m_widget->removeEventFilter(this); - disconnect( m_widget, TQT_SIGNAL( destroyed()), this, TQT_SLOT( slotWidgetDestructed())); - m_widget->hide(); - m_widget->deleteLater(); //Might happen due to event on the widget, so be careful - m_widget = 0; - } - m_widget = widget; - if (m_widget) { - connect( m_widget, TQT_SIGNAL( destroyed()), this, TQT_SLOT( slotWidgetDestructed())); - m_widget->installEventFilter(this); - - if ( (m_isKHTMLWidget = !strcmp(m_widget->name(), "__khtml")) && !::tqqt_cast<TQFrame*>(m_widget)) - m_widget->setBackgroundMode( TQWidget::NoBackground ); - - if (m_widget->focusPolicy() > TQ_StrongFocus) - m_widget->setFocusPolicy(TQ_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() ); - if (!isKHTMLWidget() && !isFrame() && !m_needsMask) { - m_needsMask = true; - RenderLayer* rl = enclosingStackingContext(); - RenderLayer* el = enclosingLayer(); - while (rl && el && el != rl) { - if (el->renderer()->style()->position() != STATIC) { - m_needsMask = false; - break; - } - el = el->parent(); - } - if (m_needsMask) { - if (rl) rl->setHasOverlaidWidgets(); - canvas()->setNeedsWidgetMasks(); - } - } - } - - setNeedsLayout(false); -} - -void RenderWidget::updateFromElement() -{ - if (m_widget) { - // Color: - TQColor color = style()->color(); - TQColor backgroundColor = style()->backgroundColor(); - - if ( color.isValid() || backgroundColor.isValid() ) { - TQPalette pal(TQApplication::palette(m_widget)); - - int contrast_ = TDEGlobalSettings::contrast(); - int highlightVal = 100 + (2*contrast_+4)*16/10; - int lowlightVal = 100 + (2*contrast_+4)*10; - - if (backgroundColor.isValid()) { - if (!isKHTMLWidget()) - widget()->setEraseColor(backgroundColor ); - for ( int i = 0; i < TQPalette::NColorGroups; ++i ) { - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Background, backgroundColor ); - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Light, backgroundColor.light(highlightVal) ); - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Dark, backgroundColor.dark(lowlightVal) ); - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Mid, backgroundColor.dark(120) ); - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Midlight, backgroundColor.light(110) ); - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Button, backgroundColor ); - pal.setColor( (TQPalette::ColorGroup)i, TQColorGroup::Base, backgroundColor ); - } - } - if ( color.isValid() ) { - struct ColorSet { - TQPalette::ColorGroup cg; - TQColorGroup::ColorRole cr; - }; - const struct ColorSet toSet [] = { - { TQPalette::Active, TQColorGroup::Foreground }, - { TQPalette::Active, TQColorGroup::ButtonText }, - { TQPalette::Active, TQColorGroup::Text }, - { TQPalette::Inactive, TQColorGroup::Foreground }, - { TQPalette::Inactive, TQColorGroup::ButtonText }, - { TQPalette::Inactive, TQColorGroup::Text }, - { TQPalette::Disabled,TQColorGroup::ButtonText }, - { TQPalette::NColorGroups, TQColorGroup::NColorRoles }, - }; - const ColorSet *set = toSet; - while( set->cg != TQPalette::NColorGroups ) { - pal.setColor( set->cg, set->cr, color ); - ++set; - } - - TQColor 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(TQPalette::Disabled,TQColorGroup::Foreground,disfg); - } - - m_widget->setPalette(pal); - } - else - m_widget->unsetPalette(); - // Border: - TQFrame* frame = ::tqqt_cast<TQFrame*>(m_widget); - if (frame) { - if (shouldPaintBackgroundOrBorder()) - { - frame->setFrameShape(TQFrame::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 = isKHTMLWidget(); - 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; - - // tqDebug("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; - } -// tqDebug("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 <tqinternal_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 TQObject -{ -public: - static const int maxPixelBuffering = 320*200; - static const int leaseTime = 20*1000; - - static TQPixmap *grab( TQSize s = TQSize() ) { - if (!m_inst) - m_inst = new PaintBuffer; - return m_inst->getBuf( s ); - } - static void release() { m_inst->m_grabbed = false; } -protected: - PaintBuffer(): m_overflow(false), m_grabbed(false), - m_timer(0), m_resetWidth(0), m_resetHeight(0) {}; - void timerEvent(TQTimerEvent* e) { - assert( m_timer == e->timerId() ); - if (m_grabbed) - return; - m_buf.resize(m_resetWidth, m_resetHeight); - m_resetWidth = m_resetHeight = 0; - killTimer( m_timer ); - m_timer = 0; - } - - TQPixmap *getBuf( TQSize s ) { - assert( !m_grabbed ); - if (s.isEmpty()) - return 0; - - m_grabbed = true; - bool cur_overflow = false; - - int nw = kMax(m_buf.width(), s.width()); - int nh = kMax(m_buf.height(), s.height()); - - if (!m_overflow && (nw*nh > maxPixelBuffering)) - cur_overflow = true; - - if (nw != m_buf.width() || nh != m_buf.height()) - m_buf.resize(nw, nh); - - if (cur_overflow) { - m_overflow = true; - m_timer = startTimer( leaseTime ); - } else if (m_overflow) { - if( s.width()*s.height() > maxPixelBuffering ) { - killTimer( m_timer ); - m_timer = startTimer( leaseTime ); - } else { - if (s.width() > m_resetWidth) - m_resetWidth = s.width(); - if (s.height() > m_resetHeight) - m_resetHeight = s.height(); - } - } - return &m_buf; - } -private: - static PaintBuffer* m_inst; - TQPixmap m_buf; - bool m_overflow; - bool m_grabbed; - int m_timer; - int m_resetWidth; - int m_resetHeight; -}; - -PaintBuffer *PaintBuffer::m_inst = 0; - -static void copyWidget(const TQRect& r, TQPainter *p, TQWidget *widget, int tx, int ty) -{ - if (r.isNull() || r.isEmpty() ) - return; - TQRegion blit(r); - TQValueVector<TQWidget*> cw; - TQValueVector<TQRect> cr; - - if (!widget->childrenListObject().isEmpty()) { - // build region - TQObjectList childWidgets = widget->childrenListObject(); - TQObjectListIterator it(childWidgets); - for (; it.current(); ++it) { - TQWidget* const w = ::tqqt_cast<TQWidget *>(it.current()); - if ( w && !w->isTopLevel() && !w->isHidden()) { - TQRect r2 = w->geometry(); - blit -= r2; - r2 = r2.intersect( r ); - r2.moveBy(-w->x(), -w->y()); - cr.append(r2); - cw.append(w); - } - } - } - TQMemArray<TQRect> br = blit.rects(); - - const int cnt = br.size(); - const bool external = p->device()->isExtDev(); - TQPixmap* const pm = PaintBuffer::grab( widget->size() ); - if (!pm) - { - kdWarning(6040) << "Rendering widget [ " << widget->className() << " ] failed due to invalid size." << endl; - return; - } - - // fill background - if ( external ) { - // even hackier! - TQPainter pt( pm ); - const TQColor c = widget->colorGroup().base(); - for (int i = 0; i < cnt; ++i) - pt.fillRect( br[i], c ); - } else { - TQRect dr; - for (int i = 0; i < cnt; ++i ) { - dr = br[i]; - dr.moveBy( tx, ty ); - dr = p->xForm( dr ); - bitBlt(pm, br[i].topLeft(), p->device(), dr); - } - } - - // send paint event - TQPainter::redirect(widget, pm); - TQPaintEvent e( r, false ); - TQApplication::sendEvent( widget, &e ); - TQPainter::redirect(widget, 0); - - // transfer result - if ( external ) - for ( int i = 0; i < cnt; ++i ) - p->drawPixmap(TQPoint(tx+br[i].x(), ty+br[i].y()), *pm, br[i]); - else - for ( int i = 0; i < cnt; ++i ) - bitBlt(p->device(), p->xForm( TQPoint(tx, ty) + br[i].topLeft() ), pm, br[i]); - - // cleanup and recurse - PaintBuffer::release(); - TQValueVector<TQWidget*>::iterator cwit = cw.begin(); - TQValueVector<TQWidget*>::iterator cwitEnd = cw.end(); - TQValueVector<TQRect>::const_iterator crit = cr.begin(); - for (; cwit != cwitEnd; ++cwit, ++crit) - copyWidget(*crit, p, *cwit, tx+(*cwit)->x(), ty+(*cwit)->y()); -} - -void RenderWidget::paintWidget(PaintInfo& pI, TQWidget *widget, int tx, int ty) -{ - TQPainter* const p = pI.p; - allowWidgetPaintEvents = true; - - const bool dsbld = TQSharedDoubleBuffer::isDisabled(); - TQSharedDoubleBuffer::setDisabled(true); - TQRect rr = pI.r; - rr.moveBy(-tx, -ty); - const TQRect r = widget->rect().intersect( rr ); - copyWidget(r, p, widget, tx, ty); - TQSharedDoubleBuffer::setDisabled(dsbld); - - allowWidgetPaintEvents = false; -} - -bool RenderWidget::eventFilter(TQObject* /*o*/, TQEvent* e) -{ - // no special event processing if this is a frame (in which case KHTMLView handles it all) - if ( ::tqqt_cast<KHTMLView *>( m_widget ) ) - return false; - if ( !element() ) return true; - - - static bool directToWidget = false; - if (directToWidget) { - //We're trying to get the event to the widget - //promptly. So get out of here.. - return false; - } - - ref(); - element()->ref(); - - bool filtered = false; - - //kdDebug() << "RenderWidget::eventFilter type=" << e->type() << endl; - switch(e->type()) { - case TQEvent::FocusOut: - // First, forward it to the widget, so that Qt gets a precise - // state of the focus before pesky JS can try changing it.. - directToWidget = true; - TQApplication::sendEvent(m_widget, e); - directToWidget = false; - filtered = true; //We already delivered it! - - // Don't count popup as a valid reason for losing the focus - // (example: opening the options of a select combobox shouldn't emit onblur) - if ( TQT_TQFOCUSEVENT(e)->reason() != TQFocusEvent::Popup ) - handleFocusOut(); - break; - case TQEvent::FocusIn: - //As above, forward to the widget first... - directToWidget = true; - TQApplication::sendEvent(m_widget, e); - directToWidget = false; - filtered = true; //We already delivered it! - - //kdDebug(6000) << "RenderWidget::eventFilter captures FocusIn" << endl; - element()->getDocument()->setFocusNode(element()); -// if ( isEditable() ) { -// KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>( element()->view->part()->browserExtension() ); -// if ( ext ) ext->editableWidgetFocused( m_widget ); -// } - break; - case TQEvent::KeyPress: - case TQEvent::KeyRelease: - // TODO this seems wrong - Qt events are not correctly translated to DOM ones, - // like in KHTMLView::dispatchKeyEvent() - if (element()->dispatchKeyEvent(TQT_TQKEYEVENT(e),false)) - filtered = true; - break; - - case TQEvent::Wheel: - if (widget()->parentWidget() == view()->viewport()) { - // don't allow the widget to react to wheel event unless its - // currently focused. this avoids accidentally changing a select box - // or something while wheeling a webpage. - if (tqApp->focusWidget() != widget() && - widget()->focusPolicy() <= TQ_StrongFocus) { - TQT_TQWHEELEVENT(e)->ignore(); - TQApplication::sendEvent(view(), e); - filtered = true; - } - } - break; - default: - break; - }; - - element()->deref(); - - // stop processing if the widget gets deleted, but continue in all other cases - if (hasOneRef()) - filtered = true; - deref(); - - return filtered; -} - -void RenderWidget::EventPropagator::sendEvent(TQEvent *e) { - switch(e->type()) { - case TQEvent::MouseButtonPress: - mousePressEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::MouseButtonRelease: - mouseReleaseEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::MouseButtonDblClick: - mouseDoubleClickEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::MouseMove: - mouseMoveEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::KeyPress: - keyPressEvent(TQT_TQKEYEVENT(e)); - break; - case TQEvent::KeyRelease: - keyReleaseEvent(TQT_TQKEYEVENT(e)); - break; - default: - break; - } -} - -void RenderWidget::ScrollViewEventPropagator::sendEvent(TQEvent *e) { - switch(e->type()) { - case TQEvent::MouseButtonPress: - viewportMousePressEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::MouseButtonRelease: - viewportMouseReleaseEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::MouseButtonDblClick: - viewportMouseDoubleClickEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::MouseMove: - viewportMouseMoveEvent(TQT_TQMOUSEEVENT(e)); - break; - case TQEvent::KeyPress: - keyPressEvent(TQT_TQKEYEVENT(e)); - break; - case TQEvent::KeyRelease: - keyReleaseEvent(TQT_TQKEYEVENT(e)); - break; - default: - break; - } -} - -bool RenderWidget::handleEvent(const DOM::EventImpl& ev) -{ - bool ret = false; - switch(ev.id()) { - case EventImpl::MOUSEDOWN_EVENT: - case EventImpl::MOUSEUP_EVENT: - case EventImpl::MOUSEMOVE_EVENT: { - if (!ev.isMouseEvent()) break; - const MouseEventImpl &me = static_cast<const MouseEventImpl &>(ev); - TQMouseEvent* const qme = me.qEvent(); - - int absx = 0; - int absy = 0; - - absolutePosition(absx, absy); - TQPoint p(me.clientX() - absx + m_view->contentsX(), - me.clientY() - absy + m_view->contentsY()); - TQMouseEvent::Type type; - int button = 0; - int state = 0; - - if (qme) { - button = qme->button(); - state = qme->state(); - type = qme->type(); - } else { - switch(me.id()) { - case EventImpl::MOUSEDOWN_EVENT: - type = TQMouseEvent::MouseButtonPress; - break; - case EventImpl::MOUSEUP_EVENT: - type = TQMouseEvent::MouseButtonRelease; - break; - case EventImpl::MOUSEMOVE_EVENT: - default: - type = TQMouseEvent::MouseMove; - break; - } - switch (me.button()) { - case 0: - button = Qt::LeftButton; - break; - case 1: - button = Qt::MidButton; - break; - case 2: - button = Qt::RightButton; - break; - default: - break; - } - if (me.ctrlKey()) - state |= ControlButton; - if (me.altKey()) - state |= AltButton; - if (me.shiftKey()) - state |= ShiftButton; - if (me.metaKey()) - state |= MetaButton; - } - -// kdDebug(6000) << "sending event to widget " -// << " pos=" << p << " type=" << type -// << " button=" << button << " state=" << state << endl; - TQMouseEvent e(type, p, button, state); - TQScrollView * sc = ::tqqt_cast<TQScrollView*>(m_widget); - if (sc && !::tqqt_cast<TQListBox*>(m_widget)) - static_cast<ScrollViewEventPropagator *>(sc)->sendEvent(TQT_TQEVENT(&e)); - else - static_cast<EventPropagator *>(m_widget)->sendEvent(TQT_TQEVENT(&e)); - ret = e.isAccepted(); - break; - } - case EventImpl::KEYDOWN_EVENT: - // do nothing; see the mapping table below - break; - case EventImpl::KEYUP_EVENT: { - if (!ev.isKeyRelatedEvent()) break; - - const KeyEventBaseImpl& domKeyEv = static_cast<const KeyEventBaseImpl &>(ev); - if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) break; - - TQKeyEvent* const ke = domKeyEv.qKeyEvent(); - static_cast<EventPropagator *>(m_widget)->sendEvent(TQT_TQEVENT(ke)); - ret = ke->isAccepted(); - break; - } - case EventImpl::KEYPRESS_EVENT: { - if (!ev.isKeyRelatedEvent()) break; - - const KeyEventBaseImpl& domKeyEv = static_cast<const KeyEventBaseImpl &>(ev); - if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) break; - - // See KHTMLView::dispatchKeyEvent: autorepeat is just keypress in the DOM - // but it's keyrelease+keypress in Qt. So here we do the inverse mapping as - // the one done in KHTMLView: generate two events for one DOM auto-repeat keypress. - // Similarly, DOM keypress events with non-autorepeat Qt event do nothing here, - // because the matching Qt keypress event was already sent from DOM keydown event. - - // Reverse drawing as the one in KHTMLView: - // DOM: Down Press | Press | Up - // Qt: (nothing) Press | Release(autorepeat) + Press(autorepeat) | Release - // - // Qt::KeyPress is sent for DOM keypress and not DOM keydown to allow - // sites to block a key with onkeypress, #99749 - - TQKeyEvent* const ke = domKeyEv.qKeyEvent(); - if (ke->isAutoRepeat()) { - TQKeyEvent releaseEv( TQEvent::KeyRelease, ke->key(), ke->ascii(), ke->state(), - ke->text(), ke->isAutoRepeat(), ke->count() ); - static_cast<EventPropagator *>(m_widget)->sendEvent(TQT_TQEVENT(&releaseEv)); - } - static_cast<EventPropagator *>(m_widget)->sendEvent(TQT_TQEVENT(ke)); - ret = ke->isAccepted(); - break; - } - case EventImpl::MOUSEOUT_EVENT: { - TQEvent moe( TQEvent::Leave ); - TQApplication::sendEvent(m_widget, &moe); - break; - } - case EventImpl::MOUSEOVER_EVENT: { - TQEvent moe( TQEvent::Enter ); - TQApplication::sendEvent(m_widget, &moe); - view()->part()->resetHoverText(); - break; - } - default: - break; - } - return ret; -} - -void RenderWidget::deref() -{ - if (_ref) _ref--; -// tqDebug( "deref(%p): width get count is %d", this, _ref); - if (!_ref) { - khtml::SharedPtr<RenderArena> guard(m_arena); //Since delete on us gets called -first-, - //before the arena free - arenaDelete(m_arena.get()); - } -} - -FindSelectionResult RenderReplaced::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset, SelPointState &) -{ -#if 0 - kdDebug(6040) << "RenderReplaced::checkSelectionPoint(_x="<<_x<<",_y="<<_y<<",_tx="<<_tx<<",_ty="<<_ty<<")" << endl - << "xPos: " << xPos() << " yPos: " << yPos() << " width: " << width() << " height: " << height() << endl - << "_ty + yPos: " << (_ty + yPos()) << " + height: " << (_ty + yPos() + height()) << "; _tx + xPos: " << (_tx + xPos()) << " + width: " << (_tx + xPos() + width()) << endl; -#endif - node = element(); - offset = 0; - - if ( _y < _ty + yPos() ) - return SelectionPointBefore; // above -> before - - if ( _y > _ty + yPos() + height() ) { - // below -> after - // Set the offset to the max - offset = 1; - return SelectionPointAfter; - } - if ( _x > _tx + xPos() + width() ) { - // to the right - // ### how to regard bidi in replaced elements? (LS) - offset = 1; - return SelectionPointAfterInLine; - } - - // The Y matches, check if we're on the left - if ( _x < _tx + xPos() ) { - // ### how to regard bidi in replaced elements? (LS) - return SelectionPointBeforeInLine; - } - - offset = _x > _tx + xPos() + width()/2; - return SelectionPointInside; -} - -#ifdef ENABLE_DUMP -void RenderWidget::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderReplaced::dump(stream,ind); - if ( widget() ) - stream << " color=" << widget()->foregroundColor().name() - << " bg=" << widget()->backgroundColor().name(); - else - stream << " null widget"; -} -#endif - -#include "render_replaced.moc" - diff --git a/khtml/rendering/render_replaced.h b/khtml/rendering/render_replaced.h deleted file mode 100644 index 8432f170e..000000000 --- a/khtml/rendering/render_replaced.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * This file is part of the HTML widget for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.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. - * - */ -#ifndef render_replaced_h -#define render_replaced_h - -#include "rendering/render_block.h" -#include <tqobject.h> -#include <tqscrollview.h> - -class KHTMLView; -class TQWidget; - -namespace DOM -{ - class MouseEventImpl; -} - -namespace khtml { - -class RenderReplaced : public RenderBox -{ -public: - RenderReplaced(DOM::NodeImpl* node); - - virtual const char *renderName() const { return "RenderReplaced"; } - virtual bool isRenderReplaced() const { return true; } - - virtual bool childAllowed() const { return false; } - - virtual void calcMinMaxWidth(); - - virtual short intrinsicWidth() const { return m_intrinsicWidth; } - virtual int intrinsicHeight() const { return m_intrinsicHeight; } - - void setIntrinsicWidth(int w) { m_intrinsicWidth = w; } - void setIntrinsicHeight(int h) { m_intrinsicHeight = h; } - - virtual void position(InlineBox*, int, int, bool); - - // Return before, after (offset set to max), or inside the replaced element, - // at @p offset - virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty, - DOM::NodeImpl*& node, int & offset, - SelPointState & ); - - /** returns the lowest possible value the caret offset may have to - * still point to a valid position. - * - * Returns 0. - */ - virtual long minOffset() const { return 0; } - /** returns the highest possible value the caret offset may have to - * still point to a valid position. - * - * Returns 0. - */ - virtual long maxOffset() const { return 0; } - -protected: - short m_intrinsicWidth; - short m_intrinsicHeight; -}; - - -class RenderWidget : public TQObject, public RenderReplaced, public khtml::Shared<RenderWidget> -{ - Q_OBJECT -public: - RenderWidget(DOM::NodeImpl* node); - virtual ~RenderWidget(); - - virtual void setStyle(RenderStyle *style); - virtual void paint( PaintInfo& i, int tx, int ty ); - virtual bool isWidget() const { return true; }; - - virtual bool isFrame() const { return false; } - - virtual void detach( ); - virtual void layout( ); - - virtual void updateFromElement(); - - TQWidget *widget() const { return m_widget; } - KHTMLView* view() const { return m_view; } - - void deref(); - - void cancelPendingResize(); - bool needsMask() const { return m_needsMask; } - - static void paintWidget(PaintInfo& pI, TQWidget *widget, int tx, int ty); - virtual bool handleEvent(const DOM::EventImpl& ev); - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - - // for ECMA to flush all pending resizes - KDE_EXPORT static void flushWidgetResizes(); - -public slots: - void slotWidgetDestructed(); - bool isKHTMLWidget() const { return m_isKHTMLWidget; } - -protected: - virtual bool canHaveBorder() const { return false; } - - virtual bool acceptsSyntheticEvents() const { return true; } - - virtual void handleFocusOut() {} - bool event( TQEvent *e ); - - bool eventFilter(TQObject* /*o*/, TQEvent* e); - void setQWidget(TQWidget *widget); - void resizeWidget( int w, int h ); - - TQWidget *m_widget; - KHTMLView* m_view; - - //Because we mess with normal detach due to ref/deref, - //we need to keep track of the arena ourselves - //so it doesn't get yanked from us, etc. - SharedPtr<RenderArena> m_arena; - - bool m_resizePending; - bool m_discardResizes; - bool m_isKHTMLWidget; - bool m_needsMask; - -public: - virtual int borderTop() const { return canHaveBorder() ? RenderReplaced::borderTop() : 0; } - virtual int borderBottom() const { return canHaveBorder() ? RenderReplaced::borderBottom() : 0; } - virtual int borderLeft() const { return canHaveBorder() ? RenderReplaced::borderLeft() : 0; } - virtual int borderRight() const { return canHaveBorder() ? RenderReplaced::borderRight() : 0; } - - class EventPropagator : public TQWidget { - public: - void sendEvent(TQEvent *e); - }; - class ScrollViewEventPropagator : public TQScrollView { - public: - void sendEvent(TQEvent *e); - }; -}; - -extern bool allowWidgetPaintEvents; - -} - -#endif diff --git a/khtml/rendering/render_style.cpp b/khtml/rendering/render_style.cpp deleted file mode 100644 index a71dd4116..000000000 --- a/khtml/rendering/render_style.cpp +++ /dev/null @@ -1,1301 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002-2005 Apple Computer, Inc. - * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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 "xml/dom_stringimpl.h" -#include "css/cssstyleselector.h" -#include "css/css_valueimpl.h" -#include "render_style.h" - -#include "kdebug.h" - -using namespace khtml; -using namespace DOM; - -/* CSS says Fixed for the default padding value, but we treat variable as 0 padding anyways, and like - * this is works fine for table paddings aswell - */ -StyleSurroundData::StyleSurroundData() - : margin( Fixed ), padding( Variable ) -{ -} - -StyleSurroundData::StyleSurroundData(const StyleSurroundData& o ) - : Shared<StyleSurroundData>(), - offset( o.offset ), margin( o.margin ), padding( o.padding ), - border( o.border ) -{ -} - -bool StyleSurroundData::operator==(const StyleSurroundData& o) const -{ - return offset==o.offset && margin==o.margin && - padding==o.padding && border==o.border; -} - -StyleBoxData::StyleBoxData() - : z_index( 0 ), z_auto( true ) -{ - min_width = min_height = RenderStyle::initialMinSize(); - max_width = max_height = RenderStyle::initialMaxSize(); - box_sizing = RenderStyle::initialBoxSizing(); -} - -StyleBoxData::StyleBoxData(const StyleBoxData& o ) - : Shared<StyleBoxData>(), - width( o.width ), height( o.height ), - min_width( o.min_width ), max_width( o.max_width ), - min_height ( o.min_height ), max_height( o.max_height ), - box_sizing( o.box_sizing), - z_index( o.z_index ), z_auto( o.z_auto ) -{ -} - -bool StyleBoxData::operator==(const StyleBoxData& o) const -{ - return - width == o.width && - height == o.height && - min_width == o.min_width && - max_width == o.max_width && - min_height == o.min_height && - max_height == o.max_height && - box_sizing == o.box_sizing && - z_index == o.z_index && - z_auto == o.z_auto; -} - -StyleVisualData::StyleVisualData() - : textDecoration(RenderStyle::initialTextDecoration()), - palette( TQApplication::palette() ) -{ -} - -StyleVisualData::~StyleVisualData() { -} - -StyleVisualData::StyleVisualData(const StyleVisualData& o ) - : Shared<StyleVisualData>(), - clip( o.clip ), textDecoration(o.textDecoration), - palette( o.palette ) -{ -} - -BackgroundLayer::BackgroundLayer() -:m_image(RenderStyle::initialBackgroundImage()), - m_bgAttachment(RenderStyle::initialBackgroundAttachment()), - m_bgClip(RenderStyle::initialBackgroundClip()), - m_bgOrigin(RenderStyle::initialBackgroundOrigin()), - m_bgRepeat(RenderStyle::initialBackgroundRepeat()), - m_backgroundSize(RenderStyle::initialBackgroundSize()), - m_next(0) -{ - m_imageSet = m_attachmentSet = m_clipSet = m_originSet = - m_repeatSet = m_xPosSet = m_yPosSet = m_backgroundSizeSet = false; -} - -BackgroundLayer::BackgroundLayer(const BackgroundLayer& o) -{ - m_next = o.m_next ? new BackgroundLayer(*o.m_next) : 0; - m_image = o.m_image; - m_xPosition = o.m_xPosition; - m_yPosition = o.m_yPosition; - m_bgAttachment = o.m_bgAttachment; - m_bgClip = o.m_bgClip; - m_bgOrigin = o.m_bgOrigin; - m_bgRepeat = o.m_bgRepeat; - m_backgroundSize = o.m_backgroundSize; - m_imageSet = o.m_imageSet; - m_attachmentSet = o.m_attachmentSet; - m_clipSet = o.m_clipSet; - m_originSet = o.m_originSet; - m_repeatSet = o.m_repeatSet; - m_xPosSet = o.m_xPosSet; - m_yPosSet = o.m_yPosSet; - m_backgroundSizeSet = o.m_backgroundSizeSet; -} - -BackgroundLayer::~BackgroundLayer() -{ - delete m_next; -} - -BackgroundLayer& BackgroundLayer::operator=(const BackgroundLayer& o) { - if (m_next != o.m_next) { - delete m_next; - m_next = o.m_next ? new BackgroundLayer(*o.m_next) : 0; - } - - m_image = o.m_image; - m_xPosition = o.m_xPosition; - m_yPosition = o.m_yPosition; - m_bgAttachment = o.m_bgAttachment; - m_bgClip = o.m_bgClip; - m_bgOrigin = o.m_bgOrigin; - m_bgRepeat = o.m_bgRepeat; - m_backgroundSize = o.m_backgroundSize; - - m_imageSet = o.m_imageSet; - m_attachmentSet = o.m_attachmentSet; - m_originSet = o.m_originSet; - m_repeatSet = o.m_repeatSet; - m_xPosSet = o.m_xPosSet; - m_yPosSet = o.m_yPosSet; - m_backgroundSizeSet = o.m_backgroundSizeSet; - - return *this; -} - -bool BackgroundLayer::operator==(const BackgroundLayer& o) const { - return m_image == o.m_image && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition && - m_bgAttachment == o.m_bgAttachment && m_bgClip == o.m_bgClip && m_bgOrigin == o.m_bgOrigin && m_bgRepeat == o.m_bgRepeat && - m_backgroundSize.width == o.m_backgroundSize.width && m_backgroundSize.height == o.m_backgroundSize.height && - m_imageSet == o.m_imageSet && m_attachmentSet == o.m_attachmentSet && m_repeatSet == o.m_repeatSet && - m_xPosSet == o.m_xPosSet && m_yPosSet == o.m_yPosSet && m_backgroundSizeSet == o.m_backgroundSizeSet && - ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next); -} - -void BackgroundLayer::fillUnsetProperties() -{ - BackgroundLayer* curr; - for (curr = this; curr && curr->isBackgroundImageSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_image = pattern->m_image; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundXPositionSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_xPosition = pattern->m_xPosition; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundYPositionSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_yPosition = pattern->m_yPosition; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundAttachmentSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_bgAttachment = pattern->m_bgAttachment; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundClipSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_bgClip = pattern->m_bgClip; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundOriginSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_bgOrigin = pattern->m_bgOrigin; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundRepeatSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_bgRepeat = pattern->m_bgRepeat; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - - for (curr = this; curr && curr->isBackgroundSizeSet(); curr = curr->next()); - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (BackgroundLayer* pattern = this; curr; curr = curr->next()) { - curr->m_backgroundSize = pattern->m_backgroundSize; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } -} - -void BackgroundLayer::cullEmptyLayers() -{ - BackgroundLayer *next; - for (BackgroundLayer *p = this; p; p = next) { - next = p->m_next; - if (next && !next->isBackgroundImageSet() && - !next->isBackgroundXPositionSet() && !next->isBackgroundYPositionSet() && - !next->isBackgroundAttachmentSet() && !next->isBackgroundClipSet() && - !next->isBackgroundOriginSet() && !next->isBackgroundRepeatSet() && - !next->isBackgroundSizeSet()) { - delete next; - p->m_next = 0; - break; - } - } -} - -StyleBackgroundData::StyleBackgroundData() -{} - -StyleBackgroundData::StyleBackgroundData(const StyleBackgroundData& o) - : Shared<StyleBackgroundData>(), m_background(o.m_background), m_outline(o.m_outline) -{} - -bool StyleBackgroundData::operator==(const StyleBackgroundData& o) const -{ - return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline; -} - -StyleGeneratedData::StyleGeneratedData() : Shared<StyleGeneratedData>(), content(0), counter_reset(0), counter_increment(0) {} - -StyleGeneratedData::~StyleGeneratedData() -{ - if (counter_reset) counter_reset->deref(); - if (counter_increment) counter_increment->deref(); - delete content; -} - -StyleGeneratedData::StyleGeneratedData(const StyleGeneratedData& o) - : Shared<StyleGeneratedData>(), content(0), - counter_reset(o.counter_reset), counter_increment(o.counter_increment) -{ - if (o.content) content = new ContentData(*o.content); - if (counter_reset) counter_reset->ref(); - if (counter_increment) counter_increment->ref(); -} - -bool StyleGeneratedData::contentDataEquivalent(const StyleGeneratedData* otherStyle) const -{ - ContentData* c1 = content; - ContentData* c2 = otherStyle->content; - - while (c1 && c2) { - if (c1->_contentType != c2->_contentType) - return false; - if (c1->_contentType == CONTENT_TEXT) { - DOM::DOMString c1Str(c1->_content.text); - DOM::DOMString c2Str(c2->_content.text); - if (c1Str != c2Str) - return false; - } - else if (c1->_contentType == CONTENT_OBJECT) { - if (c1->_content.object != c2->_content.object) - return false; - } - else if (c1->_contentType == CONTENT_COUNTER) { - if (c1->_content.counter != c2->_content.counter) - return false; - } - else if (c1->_contentType == CONTENT_QUOTE) { - if (c1->_content.quote != c2->_content.quote) - return false; - } - - c1 = c1->_nextContent; - c2 = c2->_nextContent; - } - - return !c1 && !c2; -} - -static bool compareCounterActList(const CSSValueListImpl* ca, const CSSValueListImpl* cb) { - // weeee.... - CSSValueListImpl* a = const_cast<CSSValueListImpl*>(ca); - CSSValueListImpl* b = const_cast<CSSValueListImpl*>(cb); - - if (!a && !b) return true; - if (!a || !b) return false; - if (a->length() != b->length()) return false; - for(uint i=0; i< a->length(); i++) { - CSSValueImpl *ai = a->item(i); - CSSValueImpl *bi = b->item(i); - assert(ai && ai->cssValueType() == CSSValue::CSS_CUSTOM); - assert(bi && bi->cssValueType() == CSSValue::CSS_CUSTOM); - CounterActImpl* caa = static_cast<CounterActImpl*>(ai); - CounterActImpl* cab = static_cast<CounterActImpl*>(bi); - if (caa->value() != cab->value()) return false; - if (caa->counter() != cab->counter()) return false; - } - return true; -} - -bool StyleGeneratedData::counterDataEquivalent(const StyleGeneratedData* otherStyle) const -{ - return compareCounterActList(counter_reset, otherStyle->counter_reset) && - compareCounterActList(counter_increment, otherStyle->counter_increment); -} - -bool StyleGeneratedData::operator==(const StyleGeneratedData& o) const -{ - return contentDataEquivalent(&o) && counterDataEquivalent(&o); -} - -StyleMarqueeData::StyleMarqueeData() -{ - increment = RenderStyle::initialMarqueeIncrement(); - speed = RenderStyle::initialMarqueeSpeed(); - direction = RenderStyle::initialMarqueeDirection(); - behavior = RenderStyle::initialMarqueeBehavior(); - loops = RenderStyle::initialMarqueeLoopCount(); -} - -StyleMarqueeData::StyleMarqueeData(const StyleMarqueeData& o) -:Shared<StyleMarqueeData>(), increment(o.increment), speed(o.speed), loops(o.loops), - behavior(o.behavior), direction(o.direction) -{} - -bool StyleMarqueeData::operator==(const StyleMarqueeData& o) const -{ - return (increment == o.increment && speed == o.speed && direction == o.direction && - behavior == o.behavior && loops == o.loops); -} - -StyleCSS3NonInheritedData::StyleCSS3NonInheritedData() -:Shared<StyleCSS3NonInheritedData>() -, opacity(RenderStyle::initialOpacity()) -{ -} - -StyleCSS3NonInheritedData::StyleCSS3NonInheritedData(const StyleCSS3NonInheritedData& o) -:Shared<StyleCSS3NonInheritedData>(), - opacity(o.opacity), -#ifdef APPLE_CHANGES - flexibleBox(o.flexibleBox), -#endif - marquee(o.marquee) -{ -} - -bool StyleCSS3NonInheritedData::operator==(const StyleCSS3NonInheritedData& o) const -{ - return - opacity == o.opacity && -#ifdef APPLE_CHANGES - flexibleBox == o.flexibleBox && -#endif - marquee == o.marquee; -} - -StyleCSS3InheritedData::StyleCSS3InheritedData() -:Shared<StyleCSS3InheritedData>(), textShadow(0), wordWrap(RenderStyle::initialWordWrap()) -#ifdef APPLE_CHANGES -, userModify(READ_ONLY), textSizeAdjust(RenderStyle::initialTextSizeAdjust()) -#endif -{ - -} - -StyleCSS3InheritedData::StyleCSS3InheritedData(const StyleCSS3InheritedData& o) -:Shared<StyleCSS3InheritedData>() -{ - textShadow = o.textShadow ? new ShadowData(*o.textShadow) : 0; - wordWrap = o.wordWrap; -#ifdef APPLE_CHANGES - userModify = o.userModify; - textSizeAdjust = o.textSizeAdjust; -#endif -} - -StyleCSS3InheritedData::~StyleCSS3InheritedData() -{ - delete textShadow; -} - -bool StyleCSS3InheritedData::operator==(const StyleCSS3InheritedData& o) const -{ - return shadowDataEquivalent(o) && (wordWrap == o.wordWrap) -#ifdef APPLE_CHANGES - && (userModify == o.userModify) && (textSizeAdjust == o.textSizeAdjust) -#endif - ; -} - -bool StyleCSS3InheritedData::shadowDataEquivalent(const StyleCSS3InheritedData& o) const -{ - if (!textShadow && o.textShadow || textShadow && !o.textShadow) - return false; - if (textShadow && o.textShadow && (*textShadow != *o.textShadow)) - return false; - return true; -} - -StyleInheritedData::StyleInheritedData() - : indent( RenderStyle::initialTextIndent() ), line_height( RenderStyle::initialLineHeight() ), - style_image( RenderStyle::initialListStyleImage() ), - font(), color( RenderStyle::initialColor() ), - border_hspacing( RenderStyle::initialBorderHorizontalSpacing() ), - border_vspacing( RenderStyle::initialBorderVerticalSpacing() ), - widows( RenderStyle::initialWidows() ), orphans( RenderStyle::initialOrphans() ), - quotes(0) -{ -} - -StyleInheritedData::~StyleInheritedData() -{ - if (quotes) quotes->deref(); -} - -StyleInheritedData::StyleInheritedData(const StyleInheritedData& o ) - : Shared<StyleInheritedData>(), - indent( o.indent ), line_height( o.line_height ), style_image( o.style_image ), - font( o.font ), color( o.color ), - border_hspacing( o.border_hspacing ), - border_vspacing( o.border_vspacing ), - widows(o.widows), orphans(o.orphans) -{ - quotes = o.quotes; - if (quotes) quotes->ref(); -} - -bool StyleInheritedData::operator==(const StyleInheritedData& o) const -{ - return - indent == o.indent && - line_height == o.line_height && - border_hspacing == o.border_hspacing && - border_vspacing == o.border_vspacing && - style_image == o.style_image && - font == o.font && - color == o.color && - border_hspacing == o.border_hspacing && - border_vspacing == o.border_vspacing && - quotes == o.quotes && - widows == o.widows && - orphans == o.orphans ; - - // doesn't work because structs are not packed - //return memcmp(this, &o, sizeof(*this))==0; -} - -RenderStyle::RenderStyle() -{ -// counter++; - if (!_default) - _default = new RenderStyle(true); - - box = _default->box; - visual = _default->visual; - background = _default->background; - surround = _default->surround; - generated = _default->generated; - css3NonInheritedData = _default->css3NonInheritedData; - css3InheritedData = _default->css3InheritedData; - - inherited = _default->inherited; - - setBitDefaults(); - - pseudoStyle = 0; -} - -RenderStyle::RenderStyle(bool) -{ - setBitDefaults(); - - box.init(); - visual.init(); - background.init(); - surround.init(); - generated.init(); - css3NonInheritedData.init(); -#ifdef APPLE_CHANGES // ### yet to be merged - css3NonInheritedData.access()->flexibleBox.init(); -#endif - css3NonInheritedData.access()->marquee.init(); - css3InheritedData.init(); - inherited.init(); - - pseudoStyle = 0; -} - -RenderStyle::RenderStyle(const RenderStyle& o) - : Shared<RenderStyle>(), - inherited_flags( o.inherited_flags ), noninherited_flags( o.noninherited_flags ), - box( o.box ), visual( o.visual ), background( o.background ), surround( o.surround ), generated(o.generated), - css3NonInheritedData( o.css3NonInheritedData ), css3InheritedData( o.css3InheritedData ), - inherited( o.inherited ), pseudoStyle( 0 ) -{} - -void RenderStyle::inheritFrom(const RenderStyle* inheritParent) -{ - css3InheritedData = inheritParent->css3InheritedData; - inherited = inheritParent->inherited; - inherited_flags = inheritParent->inherited_flags; - - // Simulate ":after,:before { white-space: pre-line }" - if (styleType() == AFTER || styleType() == BEFORE) - setWhiteSpace(PRE_LINE); -} - -RenderStyle::~RenderStyle() -{ - RenderStyle *ps = pseudoStyle; - RenderStyle *prev = 0; - - while (ps) { - prev = ps; - ps = ps->pseudoStyle; - // to prevent a double deletion. - // this works only because the styles below aren't really shared - // Dirk said we need another construct as soon as these are shared - prev->pseudoStyle = 0; - prev->deref(); - } -} - -bool RenderStyle::operator==(const RenderStyle& o) const -{ -// compare everything except the pseudoStyle pointer - return (inherited_flags == o.inherited_flags && - noninherited_flags == o.noninherited_flags && - box == o.box && - visual == o.visual && - background == o.background && - surround == o.surround && - generated == o.generated && - css3NonInheritedData == o.css3NonInheritedData && - css3InheritedData == o.css3InheritedData && - inherited == o.inherited); -} - -enum EPseudoBit { NO_BIT = 0x0, - FIRST_LINE_BIT = 0x1, FIRST_LETTER_BIT = 0x2, SELECTION_BIT = 0x4, - BEFORE_BIT = 0x8, AFTER_BIT = 0x10, MARKER_BIT = 0x20, - REPLACED_BIT = 0x40 - }; - -static int pseudoBit(RenderStyle::PseudoId pseudo) -{ - switch (pseudo) { - case RenderStyle::BEFORE: - return BEFORE_BIT; - case RenderStyle::AFTER: - return AFTER_BIT; - case RenderStyle::MARKER: - return MARKER_BIT; - case RenderStyle::REPLACED: - return REPLACED_BIT; - case RenderStyle::FIRST_LINE: - return FIRST_LINE_BIT; - case RenderStyle::FIRST_LETTER: - return FIRST_LETTER_BIT; - case RenderStyle::SELECTION: - return SELECTION_BIT; - default: - return NO_BIT; - } -} - -bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const -{ - return (pseudoBit(pseudo) & noninherited_flags.f._pseudoBits) != 0; -} - -void RenderStyle::setHasPseudoStyle(PseudoId pseudo, bool b) -{ - if (b) - noninherited_flags.f._pseudoBits |= pseudoBit(pseudo); - else - noninherited_flags.f._pseudoBits &= ~(pseudoBit(pseudo)); -} - -RenderStyle* RenderStyle::getPseudoStyle(PseudoId pid) const -{ - if (!hasPseudoStyle(pid)) return 0; - - RenderStyle *ps = 0; - if (noninherited_flags.f._styleType==NOPSEUDO) - for (ps = pseudoStyle; ps; ps = ps->pseudoStyle) - if (ps->noninherited_flags.f._styleType==pid) - break; - return ps; -} - -RenderStyle* RenderStyle::addPseudoStyle(PseudoId pid) -{ - if (hasPseudoStyle(pid)) return getPseudoStyle(pid); - - RenderStyle *ps = 0; - - switch (pid) { - case FIRST_LETTER: // pseudo-elements (FIRST_LINE has a special handling) - case SELECTION: - case BEFORE: - case AFTER: - ps = new RenderStyle(); - break; - default: - ps = new RenderStyle(*this); // use the real copy constructor to get an identical copy - } - ps->ref(); - ps->noninherited_flags.f._styleType = pid; - ps->pseudoStyle = pseudoStyle; - - pseudoStyle = ps; - - setHasPseudoStyle(pid, true); - - return ps; -} - -void RenderStyle::removePseudoStyle(PseudoId pid) -{ - RenderStyle *ps = pseudoStyle; - RenderStyle *prev = this; - - while (ps) { - if (ps->noninherited_flags.f._styleType==pid) { - prev->pseudoStyle = ps->pseudoStyle; - ps->deref(); - return; - } - prev = ps; - ps = ps->pseudoStyle; - } - - setHasPseudoStyle(pid, false); -} - - -bool RenderStyle::inheritedNotEqual( RenderStyle *other ) const -{ - return - ( - inherited_flags != other->inherited_flags || - inherited != other->inherited || - css3InheritedData != other->css3InheritedData - ); -} - -/* - compares two styles. The result gives an idea of the action that - needs to be taken when replacing the old style with a new one. - - CbLayout: The containing block of the object needs a relayout. - Layout: the RenderObject needs a relayout after the style change - Visible: The change is visible, but no relayout is needed - NonVisible: The object does need neither repaint nor relayout after - the change. - - ### TODO: - A lot can be optimised here based on the display type, lots of - optimisations are unimplemented, and currently result in the - worst case result causing a relayout of the containing block. -*/ -RenderStyle::Diff RenderStyle::diff( const RenderStyle *other ) const -{ - // we anyway assume they are the same -// EDisplay _display : 5; - - // NonVisible: -// ECursor _cursor_style : 4; -// EUserInput _user_input : 2; as long as :enabled is not impl'd - -// ### this needs work to know more exactly if we need a relayout -// or just a repaint - -// non-inherited attributes -// DataRef<StyleBoxData> box; -// DataRef<StyleVisualData> visual; -// DataRef<StyleSurroundData> surround; - -// inherited attributes -// DataRef<StyleInheritedData> inherited; - - if ( *box.get() != *other->box.get() || - *visual.get() != *other->visual.get() || - (*surround.get() != *other->surround.get() - && (other->position() == STATIC || other->position() != position())) || - !(inherited->indent == other->inherited->indent) || - !(inherited->line_height == other->inherited->line_height) || - !(inherited->style_image == other->inherited->style_image) || - !(inherited->font == other->inherited->font) || - !(inherited->border_hspacing == other->inherited->border_hspacing) || - !(inherited->border_vspacing == other->inherited->border_vspacing) || - !(inherited_flags.f._visuallyOrdered == other->inherited_flags.f._visuallyOrdered) || - !(inherited_flags.f._htmlHacks == other->inherited_flags.f._htmlHacks) || - !(noninherited_flags.f._textOverflow == other->noninherited_flags.f._textOverflow) ) - return CbLayout; - - // changes causing Layout changes: - -// only for tables: -// _border_collapse -// EEmptyCell _empty_cells : 2 ; -// ECaptionSide _caption_side : 2; -// ETableLayout _table_layout : 1; -// EPosition _position : 2; -// EFloat _floating : 2; - if ( ((int)noninherited_flags.f._display) >= TABLE ) { - if ( !(inherited_flags.f._empty_cells == other->inherited_flags.f._empty_cells) || - !(inherited_flags.f._caption_side == other->inherited_flags.f._caption_side) || - !(inherited_flags.f._border_collapse == other->inherited_flags.f._border_collapse) || - !(noninherited_flags.f._table_layout == other->noninherited_flags.f._table_layout) || - !(noninherited_flags.f._position == other->noninherited_flags.f._position) || - !(noninherited_flags.f._floating == other->noninherited_flags.f._floating) || - !(noninherited_flags.f._flowAroundFloats == other->noninherited_flags.f._flowAroundFloats) || - !(noninherited_flags.f._unicodeBidi == other->noninherited_flags.f._unicodeBidi) ) - return CbLayout; - } - -// only for lists: -// EListStyleType _list_style_type : 5 ; -// EListStylePosition _list_style_position :1; - if (noninherited_flags.f._display == LIST_ITEM ) { - if ( !(inherited_flags.f._list_style_type == other->inherited_flags.f._list_style_type) || - !(inherited_flags.f._list_style_position == other->inherited_flags.f._list_style_position) ) - return Layout; - } - -// ### These could be better optimised -// ETextAlign _text_align : 3; -// ETextTransform _text_transform : 4; -// EDirection _direction : 1; -// EWhiteSpace _white_space : 2; -// EClear _clear : 2; - if ( !(inherited_flags.f._text_align == other->inherited_flags.f._text_align) || - !(inherited_flags.f._text_transform == other->inherited_flags.f._text_transform) || - !(inherited_flags.f._direction == other->inherited_flags.f._direction) || - !(inherited_flags.f._white_space == other->inherited_flags.f._white_space) || - !(noninherited_flags.f._clear == other->noninherited_flags.f._clear) - ) - return Layout; - - // Overflow returns a layout hint. - if (noninherited_flags.f._overflowX != other->noninherited_flags.f._overflowX || - noninherited_flags.f._overflowY != other->noninherited_flags.f._overflowY) - return Layout; - -// only for inline: -// EVerticalAlign _vertical_align : 4; - - if ( !(noninherited_flags.f._display == INLINE) && - !(noninherited_flags.f._vertical_align == other->noninherited_flags.f._vertical_align) ) - return Layout; - - if (*surround.get() != *other->surround.get()) { - assert( other->position() != STATIC ); // this style is positioned or relatively positioned - if ( surround->hasSamePBMData(*other->surround.get()) && // padding/border/margin are identical - (other->position() == RELATIVE || - !(other->left().isVariable() && other->right().isVariable()) && // X isn't static - !(other->top().isVariable() && other->bottom().isVariable()) )) // neither is Y - // therefore only the offset is different - return Position; - return Layout; - } - - // Visible: -// EVisibility _visibility : 2; -// int _text_decorations : 4; -// DataRef<StyleBackgroundData> background; - if (inherited->color != other->inherited->color || - !(inherited_flags.f._visibility == other->inherited_flags.f._visibility) || - !(inherited_flags.f._text_decorations == other->inherited_flags.f._text_decorations) || - !(noninherited_flags.f._hasClip == other->noninherited_flags.f._hasClip) || - visual->textDecoration != other->visual->textDecoration || - *background.get() != *other->background.get() || - css3NonInheritedData->opacity != other->css3NonInheritedData->opacity || - !css3InheritedData->shadowDataEquivalent(*other->css3InheritedData.get()) - ) - return Visible; - - RenderStyle::Diff ch = Equal; - // Check for visible pseudo-changes: - if (hasPseudoStyle(FIRST_LINE) != other->hasPseudoStyle(FIRST_LINE)) - ch = Visible; - else - if (hasPseudoStyle(FIRST_LINE) && other->hasPseudoStyle(FIRST_LINE)) - ch = getPseudoStyle(FIRST_LINE)->diff(other->getPseudoStyle(FIRST_LINE)); - - if (ch != Equal) return ch; - - // Check for visible pseudo-changes: - if (hasPseudoStyle(SELECTION) != other->hasPseudoStyle(SELECTION)) - ch = Visible; - else - if (hasPseudoStyle(SELECTION) && other->hasPseudoStyle(SELECTION)) - ch = getPseudoStyle(SELECTION)->diff(other->getPseudoStyle(SELECTION)); - - return ch; -} - - -RenderStyle* RenderStyle::_default = 0; - -void RenderStyle::cleanup() -{ - delete _default; - _default = 0; -} - -void RenderStyle::setPaletteColor(TQPalette::ColorGroup g, TQColorGroup::ColorRole r, const TQColor& c) -{ - visual.access()->palette.setColor(g,r,c); -} - -void RenderStyle::adjustBackgroundLayers() -{ - if (backgroundLayers()->next()) { - // First we cull out layers that have no properties set. - accessBackgroundLayers()->cullEmptyLayers(); - - // Next we repeat patterns into layers that don't have some properties set. - accessBackgroundLayers()->fillUnsetProperties(); - } -} - -void RenderStyle::setClip( Length top, Length right, Length bottom, Length left ) -{ - StyleVisualData *data = visual.access(); - data->clip.top = top; - data->clip.right = right; - data->clip.bottom = bottom; - data->clip.left = left; -} - -void RenderStyle::setQuotes(DOM::QuotesValueImpl* q) -{ - DOM::QuotesValueImpl *t = inherited->quotes; - inherited.access()->quotes = q; - if (q) q->ref(); - if (t) t->deref(); -} - -TQString RenderStyle::openQuote(int level) const -{ - if (inherited->quotes) - return inherited->quotes->openQuote(level); - else - return "\""; // 0 is default quotes -} - -TQString RenderStyle::closeQuote(int level) const -{ - if (inherited->quotes) - return inherited->quotes->closeQuote(level); - else - return "\""; // 0 is default quotes -} - -void RenderStyle::addContent(CachedObject* o) -{ - if (!o) - return; // The object is null. Nothing to do. Just bail. - - StyleGeneratedData *t_generated = generated.access(); - - ContentData* lastContent = t_generated->content; - while (lastContent && lastContent->_nextContent) - lastContent = lastContent->_nextContent; - - ContentData* newContentData = new ContentData; - - if (lastContent) - lastContent->_nextContent = newContentData; - else - t_generated->content = newContentData; - - // o->ref(); - newContentData->_content.object = o; - newContentData->_contentType = CONTENT_OBJECT; -} - -void RenderStyle::addContent(DOM::DOMStringImpl* s) -{ - if (!s) - return; // The string is null. Nothing to do. Just bail. - - StyleGeneratedData *t_generated = generated.access(); - - ContentData* lastContent = t_generated->content; - while (lastContent && lastContent->_nextContent) - lastContent = lastContent->_nextContent; - - if (lastContent) { - if (lastContent->_contentType == CONTENT_TEXT) { - // We can augment the existing string and share this ContentData node. - DOMStringImpl* oldStr = lastContent->_content.text; - DOMStringImpl* newStr = oldStr->copy(); - newStr->ref(); - oldStr->deref(); - newStr->append(s); - lastContent->_content.text = newStr; - return; - } - } - - ContentData* newContentData = new ContentData; - - if (lastContent) - lastContent->_nextContent = newContentData; - else - t_generated->content = newContentData; - - newContentData->_content.text = s; - newContentData->_content.text->ref(); - newContentData->_contentType = CONTENT_TEXT; - -} - -void RenderStyle::addContent(DOM::CounterImpl* c) -{ - if (!c) - return; - - StyleGeneratedData *t_generated = generated.access(); - - ContentData* lastContent = t_generated->content; - while (lastContent && lastContent->_nextContent) - lastContent = lastContent->_nextContent; - - ContentData* newContentData = new ContentData; - - if (lastContent) - lastContent->_nextContent = newContentData; - else - t_generated->content = newContentData; - - c->ref(); - newContentData->_content.counter = c; - newContentData->_contentType = CONTENT_COUNTER; -} - -void RenderStyle::addContent(EQuoteContent q) -{ - if (q == NO_QUOTE) - return; - - StyleGeneratedData *t_generated = generated.access(); - - ContentData* lastContent = t_generated->content; - while (lastContent && lastContent->_nextContent) - lastContent = lastContent->_nextContent; - - ContentData* newContentData = new ContentData; - - if (lastContent) - lastContent->_nextContent = newContentData; - else - t_generated->content = newContentData; - - newContentData->_content.quote = q; - newContentData->_contentType = CONTENT_QUOTE; -} - -// content: normal is the same as having no content at all -void RenderStyle::setContentNormal() { - if (generated->content != 0) { - delete generated->content; - generated.access()->content = 0; - } -} - -// content: none, add an empty content node -void RenderStyle::setContentNone() { - setContentNormal(); - generated.access()->content = new ContentData; -} - -void RenderStyle::setContentData(ContentData *data) { - if (data != generated->content) { - if (data) - generated.access()->content = new ContentData(*data); - else - generated.access()->content = 0; - } -} - -ContentData::ContentData(const ContentData& o) : _contentType(o._contentType) -{ - switch (_contentType) { - case CONTENT_OBJECT: - _content.object = o._content.object; - break; - case CONTENT_TEXT: - _content.text = o._content.text; - _content.text->ref(); - break; - case CONTENT_COUNTER: - _content.counter = o._content.counter; - _content.counter->ref(); - break; - case CONTENT_QUOTE: - _content.quote = o._content.quote; - break; - case CONTENT_NONE: - default: - break; - } - - _nextContent = o._nextContent ? new ContentData(*o._nextContent) : 0; -} - -ContentData::~ContentData() -{ - clearContent(); -} - -void ContentData::clearContent() -{ - delete _nextContent; - _nextContent = 0; - - switch (_contentType) - { - case CONTENT_OBJECT: - _content.object = 0; - break; - case CONTENT_TEXT: - _content.text->deref(); - _content.text = 0; - break; - case CONTENT_COUNTER: - _content.counter->deref(); - _content.counter = 0; - break; - case CONTENT_QUOTE: - _content.quote = NO_QUOTE; - break; - default: - ; - } -} - -void RenderStyle::setTextShadow(ShadowData* val, bool add) -{ - StyleCSS3InheritedData* css3Data = css3InheritedData.access(); - if (!add) { - delete css3Data->textShadow; - css3Data->textShadow = val; - return; - } - - ShadowData* last = css3Data->textShadow; - while (last->next) last = last->next; - last->next = val; -} - -ShadowData::ShadowData(const ShadowData& o) -:x(o.x), y(o.y), blur(o.blur), color(o.color) -{ - next = o.next ? new ShadowData(*o.next) : 0; -} - -bool ShadowData::operator==(const ShadowData& o) const -{ - if ((next && !o.next) || (!next && o.next) || - (next && o.next && *next != *o.next)) - return false; - - return x == o.x && y == o.y && blur == o.blur && color == o.color; -} - -static bool hasCounter(const DOM::DOMString& c, CSSValueListImpl *l) -{ - int len = l->length(); - for(int i=0; i<len; i++) { - CounterActImpl* ca = static_cast<CounterActImpl*>(l->item(i)); - Q_ASSERT(ca != 0); - if (ca->m_counter == c) return true; - } - return false; -} - -bool RenderStyle::hasCounterReset(const DOM::DOMString& c) const -{ - if (generated->counter_reset) - return hasCounter(c, generated->counter_reset); - else - return false; -} - -bool RenderStyle::hasCounterIncrement(const DOM::DOMString& c) const -{ - if (generated->counter_increment) - return hasCounter(c, generated->counter_increment); - else - return false; -} - -static short readCounter(const DOM::DOMString& c, CSSValueListImpl *l) -{ - int len = l->length(); - for(int i=0; i<len; i++) { - CounterActImpl* ca = static_cast<CounterActImpl*>(l->item(i)); - Q_ASSERT(ca != 0); - if (ca->m_counter == c) return ca->m_value; - } - return 0; -} - -short RenderStyle::counterReset(const DOM::DOMString& c) const -{ - if (generated->counter_reset) - return readCounter(c, generated->counter_reset); - else - return 0; -} - -short RenderStyle::counterIncrement(const DOM::DOMString& c) const -{ - if (generated->counter_increment) - return readCounter(c, generated->counter_increment); - else - return 0; -} - -void RenderStyle::setCounterReset(CSSValueListImpl *l) -{ - CSSValueListImpl *t = generated->counter_reset; - generated.access()->counter_reset = l; - if (l) l->ref(); - if (t) t->deref(); -} - -void RenderStyle::setCounterIncrement(CSSValueListImpl *l) -{ - CSSValueListImpl *t = generated->counter_increment; - generated.access()->counter_increment = l; - if (l) l->ref(); - if (t) t->deref(); -} - -#ifdef ENABLE_DUMP - -static TQString describeFont( const TQFont &f) -{ - TQString res = "'" + f.family() + "' "; - - if ( f.pointSize() > 0) - res += TQString::number( f.pointSize() ) + "pt"; - else - res += TQString::number( f.pixelSize() ) + "px"; - - if ( f.bold() ) - res += " bold"; - if ( f.italic() ) - res += " italic"; - if ( f.underline() ) - res += " underline"; - if ( f.overline() ) - res += " overline"; - if ( f.strikeOut() ) - res += " strikeout"; - return res; -} - -TQString RenderStyle::createDiff( const RenderStyle &parent ) const -{ - TQString res; - if ( color().isValid() && parent.color() != color() ) - res += " [color=" + color().name() + "]"; - if ( backgroundColor().isValid() && parent.backgroundColor() != backgroundColor() ) - res += " [bgcolor=" + backgroundColor().name() + "]"; - if ( parent.font() != font() ) - res += " [font=" + describeFont( font() ) + "]"; - - return res; -} -#endif - -RenderPageStyle::RenderPageStyle() : next(0), m_pageType(ANY_PAGE) -{ -} - -RenderPageStyle::~RenderPageStyle() -{ - delete next; -} - -RenderPageStyle* RenderPageStyle::getPageStyle(PageType type) -{ - RenderPageStyle *ps = 0; - for (ps = this; ps; ps = ps->next) - if (ps->m_pageType==type) - break; - return ps; -} - -RenderPageStyle* RenderPageStyle::addPageStyle(PageType type) -{ - RenderPageStyle *ps = getPageStyle(type); - - if (!ps) - { - ps = new RenderPageStyle(*this); // use the real copy constructor to get an identical copy - ps->m_pageType = type; - - ps->next = next; - next = ps; - } - - return ps; -} - -void RenderPageStyle::removePageStyle(PageType type) -{ - RenderPageStyle *ps = next; - RenderPageStyle *prev = this; - - while (ps) { - if (ps->m_pageType==type) { - prev->next = ps->next; - delete ps; - return; - } - prev = ps; - ps = ps->next; - } -} diff --git a/khtml/rendering/render_style.h b/khtml/rendering/render_style.h deleted file mode 100644 index 80d052980..000000000 --- a/khtml/rendering/render_style.h +++ /dev/null @@ -1,1524 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003-2005 Apple Computer, Inc. - * (C) 2004-2006 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ -#ifndef RENDERSTYLE_H -#define RENDERSTYLE_H - -/* - * WARNING: - * -------- - * - * The order of the values in the enums have to agree with the order specified - * in cssvalues.in, otherwise some optimizations in the parser will fail, - * and produce invaliud results. - */ - -#include <tqcolor.h> -#include <tqfont.h> -#include <tqfontmetrics.h> -#include <tqptrlist.h> -#include <tqpalette.h> -#include <tqapplication.h> - -#include "dom/dom_misc.h" -#include "dom/dom_string.h" -#include "misc/khtmllayout.h" -#include "misc/shared.h" -#include "rendering/font.h" - -#include <assert.h> - -#define SET_VAR(group,variable,value) \ - if (!(group->variable == value)) \ - group.access()->variable = value; - -#ifndef ENABLE_DUMP -#ifndef NDEBUG -#define ENABLE_DUMP 1 -#endif -#endif - -namespace DOM { - class DOMStringImpl; - class ShadowValueImpl; - class QuotesValueImpl; - class CounterImpl; - class CSSValueListImpl; - class CounterActImpl; -} - -namespace khtml { - - class CachedImage; - class CachedObject; - -template <class DATA> -class DataRef -{ -public: - - DataRef() - { - data=0; - } - DataRef( const DataRef<DATA> &d ) - { - data = d.data; - data->ref(); - } - - ~DataRef() - { - if(data) data->deref(); - } - - const DATA* operator->() const - { - return data; - } - - const DATA* get() const - { - return data; - } - - - DATA* access() - { - if (!data->hasOneRef()) - { - data->deref(); - data = new DATA(*data); - data->ref(); - } - return data; - } - - void init() - { - data = new DATA; - data->ref(); - } - - DataRef<DATA>& operator=(const DataRef<DATA>& d) - { - if (data==d.data) - return *this; - if (data) - data->deref(); - data = d.data; - - data->ref(); - - return *this; - } - - bool operator == ( const DataRef<DATA> &o ) const { - return (*data == *(o.data) ); - } - bool operator != ( const DataRef<DATA> &o ) const { - return (*data != *(o.data) ); - } - -private: - DATA* data; -}; - - -//------------------------------------------------ - -//------------------------------------------------ -// Box model attributes. Not inherited. - -struct LengthBox -{ - LengthBox() - { - } - LengthBox( LengthType t ) - : left( t ), right ( t ), top( t ), bottom( t ) {} - - Length left; - Length right; - Length top; - Length bottom; - Length& operator=(Length& len) - { - left=len; - right=len; - top=len; - bottom=len; - return len; - } - - bool operator==(const LengthBox& o) const - { - return left==o.left && right==o.right && top==o.top && bottom==o.bottom; - } - - - bool nonZero() const { return left.value() || right.value() || top.value() || bottom.value(); } -}; - - - -enum EPosition { - STATIC, RELATIVE, ABSOLUTE, FIXED -}; - -enum EFloat { - FNONE = 0, FLEFT = 0x01, FRIGHT = 0x02, FLEFT_ALIGN = 0x05, FRIGHT_ALIGN = 0x06 -}; - -enum EWordWrap { - WWNORMAL = 0, WWBREAKWORD = 0x01 -}; - -//------------------------------------------------ -// Border attributes. Not inherited. - - -// These have been defined in the order of their precedence for border-collapsing. Do -// not change this order! -enum EBorderStyle { - BNATIVE, BNONE, BHIDDEN, INSET, GROOVE, RIDGE, OUTSET, DOTTED, DASHED, SOLID, DOUBLE -}; - -class BorderValue -{ -public: - BorderValue() : width( 3 ), style( BNONE ) {} - - TQColor color; - unsigned short width : 12; - EBorderStyle style : 6; - - bool nonZero(bool checkStyle = true) const { - return width != 0 && !(checkStyle && style == BNONE); - } - - bool isTransparent() const { - return color.isValid() && tqAlpha(color.rgb()) == 0; - } - - bool operator==(const BorderValue& o) const - { - return width==o.width && style==o.style && color==o.color; - } - - bool operator!=(const BorderValue& o) const - { - return !(*this == o); - } -}; - -class OutlineValue : public BorderValue -{ - public: - OutlineValue() - { - _offset = 0; - _auto = false; - } - - bool operator==(const OutlineValue& o) const - { - return width==o.width && style==o.style && color==o.color && _offset == o._offset && _auto == o._auto; - } - - bool operator!=(const OutlineValue& o) const - { - return !(*this == o); - } - - int _offset; - bool _auto; -}; - -enum EBorderPrecedence { BOFF, BTABLE, BCOLGROUP, BCOL, BROWGROUP, BROW, BCELL }; - -struct CollapsedBorderValue -{ - CollapsedBorderValue() :border(0), precedence(BOFF) {} - CollapsedBorderValue(const BorderValue* b, EBorderPrecedence p) :border(b), precedence(p) {} - - int width() const { return border && border->nonZero() ? border->width : 0; } - EBorderStyle style() const { return border ? border->style : BHIDDEN; } - bool exists() const { return border; } - TQColor color() const { return border ? border->color : TQColor(); } - bool isTransparent() const { return border ? border->isTransparent() : true; } - - bool operator==(const CollapsedBorderValue& o) const - { - if (!border) return !o.border; - if (!o.border) return false; - return *border == *o.border && precedence == o.precedence; - } - - const BorderValue* border; - EBorderPrecedence precedence; -}; - -class BorderData : public Shared<BorderData> -{ -public: - BorderValue left; - BorderValue right; - BorderValue top; - BorderValue bottom; - - bool hasBorder() const - { - return left.nonZero() || right.nonZero() || top.nonZero() || bottom.nonZero(); - } - - unsigned short borderLeftWidth() const { - if (left.style == BNONE || left.style == BHIDDEN || left.style == BNATIVE) - return 0; - return left.width; - } - - unsigned short borderRightWidth() const { - if (right.style == BNONE || right.style == BHIDDEN || right.style == BNATIVE) - return 0; - return right.width; - } - - unsigned short borderTopWidth() const { - if (top.style == BNONE || top.style == BHIDDEN || top.style == BNATIVE) - return 0; - return top.width; - } - - unsigned short borderBottomWidth() const { - if (bottom.style == BNONE || bottom.style == BHIDDEN || bottom.style == BNATIVE) - return 0; - return bottom.width; - } - - bool operator==(const BorderData& o) const - { - return left==o.left && right==o.right && top==o.top && bottom==o.bottom; - } - -}; - -class StyleSurroundData : public Shared<StyleSurroundData> -{ -public: - StyleSurroundData(); - - StyleSurroundData(const StyleSurroundData& o ); - bool operator==(const StyleSurroundData& o) const; - bool operator!=(const StyleSurroundData& o) const { - return !(*this == o); - } - bool hasSamePBMData(const StyleSurroundData& o) const { - return (margin == o.margin) && (padding == o.padding) && (border == o.border); - } - - LengthBox offset; - LengthBox margin; - LengthBox padding; - BorderData border; -}; - - -//------------------------------------------------ -// Box attributes. Not inherited. - -enum EBoxSizing { - BORDER_BOX, CONTENT_BOX -}; - -class StyleBoxData : public Shared<StyleBoxData> -{ -public: - StyleBoxData(); - - StyleBoxData(const StyleBoxData& o ); - - - // copy and assignment -// StyleBoxData(const StyleBoxData &other); -// const StyleBoxData &operator = (const StyleBoxData &other); - - bool operator==(const StyleBoxData& o) const; - bool operator!=(const StyleBoxData& o) const { - return !(*this == o); - } - - Length width; - Length height; - - Length min_width; - Length max_width; - - Length min_height; - Length max_height; - - Length vertical_align; - - EBoxSizing box_sizing; - - signed int z_index :31; - bool z_auto : 1; -}; - -//------------------------------------------------ -// Random visual rendering model attributes. Not inherited. - -enum EOverflow { - OVISIBLE, OHIDDEN, OSCROLL, OAUTO, OMARQUEE -}; - -enum EVerticalAlign { - BASELINE, MIDDLE, SUB, SUPER, TEXT_TOP, - TEXT_BOTTOM, TOP, BOTTOM, BASELINE_MIDDLE, LENGTH -}; - -enum EClear{ - CNONE = 0, CLEFT = 1, CRIGHT = 2, CBOTH = 3 -}; - -enum ETableLayout { - TAUTO, TFIXED -}; - -enum EUnicodeBidi { - UBNormal, Embed, Override -}; - -class StyleVisualData : public Shared<StyleVisualData> -{ -public: - StyleVisualData(); - - ~StyleVisualData(); - - StyleVisualData(const StyleVisualData& o ); - - bool operator==( const StyleVisualData &o ) const { - return ( clip == o.clip && - palette == o.palette ); - } - bool operator!=( const StyleVisualData &o ) const { - return !(*this == o); - } - - LengthBox clip; - unsigned textDecoration : 4; // Text decorations defined *only* by this element. - - TQPalette palette; //widget styling with IE attributes - -}; - -//------------------------------------------------ -enum EBackgroundBox { - BGBORDER, BGPADDING, BGCONTENT -}; - -enum EBackgroundRepeat { - REPEAT, REPEAT_X, REPEAT_Y, NO_REPEAT -}; - -struct LengthSize { - Length width; - Length height; -}; - -struct BackgroundLayer { -public: - BackgroundLayer(); - ~BackgroundLayer(); - - CachedImage* backgroundImage() const { return m_image; } - Length backgroundXPosition() const { return m_xPosition; } - Length backgroundYPosition() const { return m_yPosition; } - bool backgroundAttachment() const { return m_bgAttachment; } - EBackgroundBox backgroundClip() const { return m_bgClip; } - EBackgroundBox backgroundOrigin() const { return m_bgOrigin; } - EBackgroundRepeat backgroundRepeat() const { return m_bgRepeat; } - LengthSize backgroundSize() const { return m_backgroundSize; } - - BackgroundLayer* next() const { return m_next; } - BackgroundLayer* next() { return m_next; } - - bool isBackgroundImageSet() const { return m_imageSet; } - bool isBackgroundXPositionSet() const { return m_xPosSet; } - bool isBackgroundYPositionSet() const { return m_yPosSet; } - bool isBackgroundAttachmentSet() const { return m_attachmentSet; } - bool isBackgroundClipSet() const { return m_clipSet; } - bool isBackgroundOriginSet() const { return m_originSet; } - bool isBackgroundRepeatSet() const { return m_repeatSet; } - bool isBackgroundSizeSet() const { return m_backgroundSizeSet; } - - void setBackgroundImage(CachedImage* i) { m_image = i; m_imageSet = true; } - void setBackgroundXPosition(const Length& l) { m_xPosition = l; m_xPosSet = true; } - void setBackgroundYPosition(const Length& l) { m_yPosition = l; m_yPosSet = true; } - void setBackgroundAttachment(bool b) { m_bgAttachment = b; m_attachmentSet = true; } - void setBackgroundClip(EBackgroundBox b) { m_bgClip = b; m_clipSet = true; } - void setBackgroundOrigin(EBackgroundBox b) { m_bgOrigin = b; m_originSet = true; } - void setBackgroundRepeat(EBackgroundRepeat r) { m_bgRepeat = r; m_repeatSet = true; } - void setBackgroundSize(const LengthSize& b) { m_backgroundSize = b; m_backgroundSizeSet = true; } - - void clearBackgroundImage() { m_imageSet = false; } - void clearBackgroundXPosition() { m_xPosSet = false; } - void clearBackgroundYPosition() { m_yPosSet = false; } - void clearBackgroundAttachment() { m_attachmentSet = false; } - void clearBackgroundClip() { m_clipSet = false; } - void clearBackgroundOrigin() { m_originSet = false; } - void clearBackgroundRepeat() { m_repeatSet = false; } - void clearBackgroundSize() { m_backgroundSizeSet = false; } - - void setNext(BackgroundLayer* n) { if (m_next != n) { delete m_next; m_next = n; } } - - BackgroundLayer& operator=(const BackgroundLayer& o); - BackgroundLayer(const BackgroundLayer& o); - - bool operator==(const BackgroundLayer& o) const; - bool operator!=(const BackgroundLayer& o) const { - return !(*this == o); - } - - bool containsImage(CachedImage* c) const { if (c == m_image) return true; if (m_next) return m_next->containsImage(c); return false; } - - bool hasImage() const { - if (m_image) - return true; - return m_next ? m_next->hasImage() : false; - } - bool hasFixedImage() const { - if (m_image && !m_bgAttachment) - return true; - return m_next ? m_next->hasFixedImage() : false; - } - - void fillUnsetProperties(); - void cullEmptyLayers(); - - CachedImage* m_image; - - Length m_xPosition; - Length m_yPosition; - - bool m_bgAttachment : 1; - EBackgroundBox m_bgClip : 2; - EBackgroundBox m_bgOrigin : 2; - EBackgroundRepeat m_bgRepeat : 2; - - LengthSize m_backgroundSize; - - bool m_imageSet : 1; - bool m_attachmentSet : 1; - bool m_clipSet : 1; - bool m_originSet : 1; - bool m_repeatSet : 1; - bool m_xPosSet : 1; - bool m_yPosSet : 1; - bool m_backgroundSizeSet : 1; - - BackgroundLayer* m_next; -}; - -class StyleBackgroundData : public Shared<StyleBackgroundData> -{ -public: - StyleBackgroundData(); - ~StyleBackgroundData() {} - StyleBackgroundData(const StyleBackgroundData& o ); - - bool operator==(const StyleBackgroundData& o) const; - bool operator!=(const StyleBackgroundData &o) const { - return !(*this == o); - } - - BackgroundLayer m_background; - TQColor m_color; - OutlineValue m_outline; -}; - -enum EQuoteContent { - NO_QUOTE = 0, OPEN_QUOTE, CLOSE_QUOTE, NO_OPEN_QUOTE, NO_CLOSE_QUOTE -}; - -enum ContentType { - CONTENT_NONE = 0, CONTENT_NORMAL, CONTENT_OBJECT, - CONTENT_TEXT, CONTENT_COUNTER, CONTENT_QUOTE -}; - -struct ContentData { - ContentData() : _contentType( CONTENT_NONE ), _nextContent(0) {} - ContentData(const ContentData& o); - ~ContentData(); - void clearContent(); - - DOM::DOMStringImpl* contentText() - { if (_contentType == CONTENT_TEXT) return _content.text; return 0; } - CachedObject* contentObject() - { if (_contentType == CONTENT_OBJECT) return _content.object; return 0; } - DOM::CounterImpl* contentCounter() - { if (_contentType == CONTENT_COUNTER) return _content.counter; return 0; } - EQuoteContent contentQuote() - { if (_contentType == CONTENT_QUOTE) return _content.quote; return NO_QUOTE; } - - ContentType _contentType; - - union { - CachedObject* object; - DOM::DOMStringImpl* text; - DOM::CounterImpl* counter; - EQuoteContent quote; - } _content ; - - ContentData* _nextContent; -}; - -class StyleGeneratedData : public Shared<StyleGeneratedData> -{ -public: - StyleGeneratedData(); - ~StyleGeneratedData(); - StyleGeneratedData(const StyleGeneratedData& o ); - - bool operator==(const StyleGeneratedData& o) const; - bool operator!=(const StyleGeneratedData &o) const { - return !(*this == o); - } - - bool contentDataEquivalent(const StyleGeneratedData* otherStyle) const; - bool counterDataEquivalent(const StyleGeneratedData* otherStyle) const; - - ContentData *content; - DOM::CSSValueListImpl *counter_reset; - DOM::CSSValueListImpl *counter_increment; -}; - -//------------------------------------------------ -// CSS3 Marquee Properties - -enum EMarqueeBehavior { MNONE, MSCROLL, MSLIDE, MALTERNATE, MUNFURL }; -enum EMarqueeDirection { MAUTO = 0, MLEFT = 1, MRIGHT = -1, MUP = 2, MDOWN = -2, MFORWARD = 3, MBACKWARD = -3 }; - -class StyleMarqueeData : public Shared<StyleMarqueeData> -{ -public: - StyleMarqueeData(); - StyleMarqueeData(const StyleMarqueeData& o); - - bool operator==(const StyleMarqueeData& o) const; - bool operator!=(const StyleMarqueeData& o) const { - return !(*this == o); - } - - Length increment; - int speed; - - int loops; // -1 means infinite. - - EMarqueeBehavior behavior : 3; - EMarqueeDirection direction : 3; -}; - -// This struct holds information about shadows for the text-shadow and box-shadow properties. -struct ShadowData { - ShadowData(int _x, int _y, int _blur, const TQColor& _color) - :x(_x), y(_y), blur(_blur), color(_color), next(0) {} - ShadowData(const ShadowData& o); - - ~ShadowData() { delete next; } - - bool operator==(const ShadowData& o) const; - bool operator!=(const ShadowData &o) const { - return !(*this == o); - } - - int x; - int y; - int blur; - TQColor color; - ShadowData* next; -}; - -// This struct is for rarely used non-inherited CSS3 properties. By grouping them together, -// we save space, and only allocate this object when someone actually uses -// a non-inherited CSS3 property. -class StyleCSS3NonInheritedData : public Shared<StyleCSS3NonInheritedData> -{ -public: - StyleCSS3NonInheritedData(); - ~StyleCSS3NonInheritedData() {} - StyleCSS3NonInheritedData(const StyleCSS3NonInheritedData& o); - - bool operator==(const StyleCSS3NonInheritedData& o) const; - bool operator!=(const StyleCSS3NonInheritedData &o) const { - return !(*this == o); - } - - float opacity; // Whether or not we're transparent. -#ifdef APPLE_CHANGES // ### we don't have those (yet) - DataRef<StyleFlexibleBoxData> flexibleBox; // Flexible box properties -#endif - DataRef<StyleMarqueeData> marquee; // Marquee properties -}; - -// This struct is for rarely used inherited CSS3 properties. By grouping them together, -// we save space, and only allocate this object when someone actually uses -// an inherited CSS3 property. -class StyleCSS3InheritedData : public Shared<StyleCSS3InheritedData> -{ - public: - StyleCSS3InheritedData(); - ~StyleCSS3InheritedData(); - StyleCSS3InheritedData(const StyleCSS3InheritedData& o); - - bool operator==(const StyleCSS3InheritedData& o) const; - bool operator!=(const StyleCSS3InheritedData &o) const { - return !(*this == o); - } - bool shadowDataEquivalent(const StyleCSS3InheritedData& o) const; - - ShadowData* textShadow; // Our text shadow information for shadowed text drawing. -#ifdef APPLE_CHANGES - EUserModify userModify : 2; // Flag used for editing state - bool textSizeAdjust : 1; // An Apple extension. Not really CSS3 but not worth making a new struct over. -#endif - EWordWrap wordWrap : 1; - private: - StyleCSS3InheritedData &operator=(const StyleCSS3InheritedData &); -}; - -//------------------------------------------------ -// Inherited attributes. -// -// the inherited-decoration and inherited-shadow attributes -// are inherited from the -// first parent which is block level -// - -enum EWhiteSpace { - NORMAL, PRE, NOWRAP, PRE_WRAP, PRE_LINE, KHTML_NOWRAP -}; - -enum ETextAlign { - TAAUTO, LEFT, RIGHT, CENTER, JUSTIFY, KHTML_LEFT, KHTML_RIGHT, KHTML_CENTER -}; - -enum ETextTransform { - CAPITALIZE, UPPERCASE, LOWERCASE, TTNONE -}; - -enum EDirection { - LTR, RTL -}; - -enum ETextDecoration { - TDNONE = 0x0 , UNDERLINE = 0x1, OVERLINE = 0x2, LINE_THROUGH= 0x4, BLINK = 0x8 -}; - -enum EPageBreak { - PBAUTO, PBALWAYS, PBAVOID, - /* reserved for later use: */ - PBLEFT, PBRIGHT -}; - -class StyleInheritedData : public Shared<StyleInheritedData> -{ - StyleInheritedData& operator=(const StyleInheritedData&); -public: - StyleInheritedData(); - ~StyleInheritedData(); - StyleInheritedData(const StyleInheritedData& o ); - - bool operator==(const StyleInheritedData& o) const; - bool operator != ( const StyleInheritedData &o ) const { - return !(*this == o); - } - - Length indent; - // could be packed in a short but doesn't - // make a difference currently because of padding - Length line_height; - - CachedImage *style_image; - - khtml::Font font; - TQColor color; - - short border_hspacing; - short border_vspacing; - - // Paged media properties. - short widows; - short orphans; - - DOM::QuotesValueImpl* quotes; -}; - - -enum EEmptyCell { - SHOW, HIDE -}; - -enum ECaptionSide { - CAPTOP, CAPBOTTOM, CAPLEFT, CAPRIGHT -}; - - -enum EListStyleType { - // Symbols: - LDISC, LCIRCLE, LSQUARE, LBOX, LDIAMOND, - // Numeric: - LDECIMAL, DECIMAL_LEADING_ZERO, ARABIC_INDIC, LAO, PERSIAN, URDU, THAI, TIBETAN, - // Algorithmic: - LOWER_ROMAN, UPPER_ROMAN, HEBREW, ARMENIAN, GEORGIAN, - // Ideographic: - CJK_IDEOGRAPHIC, JAPANESE_FORMAL, JAPANESE_INFORMAL, - SIMP_CHINESE_FORMAL, SIMP_CHINESE_INFORMAL, TRAD_CHINESE_FORMAL, TRAD_CHINESE_INFORMAL, - // Alphabetic: - LOWER_GREEK, UPPER_GREEK, LOWER_ALPHA, LOWER_LATIN, UPPER_ALPHA, UPPER_LATIN, - HIRAGANA, KATAKANA, HIRAGANA_IROHA, KATAKANA_IROHA, - // Special: - LNONE -}; - -inline bool isListStyleCounted(EListStyleType type) -{ - switch(type) { - case LDISC: case LCIRCLE: case LSQUARE: case LBOX: case LDIAMOND: - case LNONE: - return false; - default: - return true; - } -} - -enum EListStylePosition { OUTSIDE, INSIDE }; - -enum EVisibility { VISIBLE, HIDDEN, COLLAPSE }; - -enum ECursor { - CURSOR_AUTO, CURSOR_CROSS, CURSOR_DEFAULT, CURSOR_POINTER, CURSOR_PROGRESS, CURSOR_MOVE, - CURSOR_E_RESIZE, CURSOR_NE_RESIZE, CURSOR_NW_RESIZE, CURSOR_N_RESIZE, CURSOR_SE_RESIZE, CURSOR_SW_RESIZE, - CURSOR_S_RESIZE, CURSOR_W_RESIZE, CURSOR_TEXT, CURSOR_WAIT, CURSOR_HELP -}; - -enum EUserInput { - UI_ENABLED, UI_DISABLED, UI_NONE -}; - -//------------------------------------------------ - -enum EDisplay { - INLINE, BLOCK, LIST_ITEM, RUN_IN, - COMPACT, INLINE_BLOCK, TABLE, INLINE_TABLE, - TABLE_ROW_GROUP, TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_ROW, - TABLE_COLUMN_GROUP, TABLE_COLUMN, TABLE_CELL, - TABLE_CAPTION, NONE -}; - -class RenderStyle : public Shared<RenderStyle> -{ - friend class CSSStyleSelector; -public: - KDE_EXPORT static void cleanup(); - - // pseudo elements - enum PseudoId { - NOPSEUDO, FIRST_LINE, FIRST_LETTER, SELECTION, - BEFORE, AFTER, REPLACED, MARKER - }; - -protected: - -// !START SYNC!: Keep this in sync with the copy constructor in render_style.cpp - - // inherit - struct InheritedFlags { - // 64 bit inherited, update unused when adding to the struct, or the operator will break. - bool operator==( const InheritedFlags &other ) const - { return _iflags ==other._iflags; } - bool operator!=( const InheritedFlags &other ) const - { return _iflags != other._iflags; } - - union { - struct { - EEmptyCell _empty_cells : 1 ; - ECaptionSide _caption_side : 2; - EListStyleType _list_style_type : 6; - EListStylePosition _list_style_position :1; - - EVisibility _visibility : 2; - ETextAlign _text_align : 4; - ETextTransform _text_transform : 2; - unsigned _text_decorations : 4; - ECursor _cursor_style : 5; - - EDirection _direction : 1; - bool _border_collapse : 1 ; - EWhiteSpace _white_space : 3; - // non CSS2 inherited - bool _visuallyOrdered : 1; - bool _htmlHacks :1; - EUserInput _user_input : 2; - - bool _page_break_inside : 1; // AUTO/AVOID - - unsigned int unused : 27; - } f; - TQ_UINT64 _iflags; - }; - } inherited_flags; - -// don't inherit - struct NonInheritedFlags { - // 64 bit non-inherited, update unused when adding to the struct, or the operator will break. - bool operator==( const NonInheritedFlags &other ) const - { return _niflags == other._niflags; } - bool operator!=( const NonInheritedFlags &other ) const - { return _niflags != other._niflags; } - - union { - struct { - EDisplay _display : 5; - EDisplay _originalDisplay: 5; - EOverflow _overflowX : 4 ; - EOverflow _overflowY : 4 ; - EVerticalAlign _vertical_align : 4; - EClear _clear : 2; - EPosition _position : 2; - EFloat _floating : 3; - ETableLayout _table_layout : 1; - bool _flowAroundFloats :1; - - EPageBreak _page_break_before : 3; - EPageBreak _page_break_after : 3; - - PseudoId _styleType : 4; - bool _hasClip : 1; - unsigned _pseudoBits : 8; - EUnicodeBidi _unicodeBidi : 2; - - // non CSS2 non-inherited - bool _textOverflow : 1; // Whether or not lines that spill out should be truncated with "..." - - unsigned int unused : 11; - } f; - TQ_UINT64 _niflags; - }; - } noninherited_flags; - -// non-inherited attributes - DataRef<StyleBoxData> box; - DataRef<StyleVisualData> visual; - DataRef<StyleBackgroundData> background; - DataRef<StyleSurroundData> surround; - DataRef<StyleGeneratedData> generated; - DataRef<StyleCSS3NonInheritedData> css3NonInheritedData; - -// inherited attributes - DataRef<StyleCSS3InheritedData> css3InheritedData; - DataRef<StyleInheritedData> inherited; - -// list of associated pseudo styles - RenderStyle* pseudoStyle; - -// !END SYNC! - -// static default style - static RenderStyle* _default; - -private: - RenderStyle(const RenderStyle*) {} - -protected: - void setBitDefaults() - { - inherited_flags.f._empty_cells = initialEmptyCells(); - inherited_flags.f._caption_side = initialCaptionSide(); - inherited_flags.f._list_style_type = initialListStyleType(); - inherited_flags.f._list_style_position = initialListStylePosition(); - inherited_flags.f._visibility = initialVisibility(); - inherited_flags.f._text_align = initialTextAlign(); - inherited_flags.f._text_transform = initialTextTransform(); - inherited_flags.f._text_decorations = initialTextDecoration(); - inherited_flags.f._cursor_style = initialCursor(); - inherited_flags.f._direction = initialDirection(); - inherited_flags.f._border_collapse = initialBorderCollapse(); - inherited_flags.f._white_space = initialWhiteSpace(); - inherited_flags.f._visuallyOrdered = false; - inherited_flags.f._htmlHacks=false; - inherited_flags.f._user_input = UI_NONE; - inherited_flags.f._page_break_inside = true; - inherited_flags.f.unused = 0; - - noninherited_flags._niflags = 0L; // for safety: without this, the equality method sometimes - // makes use of uninitialised bits according to valgrind - - noninherited_flags.f._display = noninherited_flags.f._originalDisplay = initialDisplay(); - noninherited_flags.f._overflowX = initialOverflowX(); - noninherited_flags.f._overflowY = initialOverflowY(); - noninherited_flags.f._vertical_align = initialVerticalAlign(); - noninherited_flags.f._clear = initialClear(); - noninherited_flags.f._position = initialPosition(); - noninherited_flags.f._floating = initialFloating(); - noninherited_flags.f._table_layout = initialTableLayout(); - noninherited_flags.f._flowAroundFloats= initialFlowAroundFloats(); - noninherited_flags.f._page_break_before = initialPageBreak(); - noninherited_flags.f._page_break_after = initialPageBreak(); - noninherited_flags.f._styleType = NOPSEUDO; - noninherited_flags.f._hasClip = false; - noninherited_flags.f._pseudoBits = 0; - noninherited_flags.f._unicodeBidi = initialUnicodeBidi(); - noninherited_flags.f._textOverflow = initialTextOverflow(); - noninherited_flags.f.unused = 0; - } - -public: - - RenderStyle(); - // used to create the default style. - RenderStyle(bool); - RenderStyle(const RenderStyle&); - - ~RenderStyle(); - - void inheritFrom(const RenderStyle* inheritParent); - - PseudoId styleType() const { return noninherited_flags.f._styleType; } - void setStyleType(PseudoId pi) { noninherited_flags.f._styleType = pi; } - bool isGenerated() const { - if (styleType() == AFTER || styleType() == BEFORE || styleType() == MARKER || styleType() == REPLACED) - return true; - else - return false; - } - - bool hasPseudoStyle(PseudoId pi) const; - void setHasPseudoStyle(PseudoId pi, bool b=true); - RenderStyle* getPseudoStyle(PseudoId pi) const; - RenderStyle* addPseudoStyle(PseudoId pi); - void removePseudoStyle(PseudoId pi); - - bool operator==(const RenderStyle& other) const; - bool isFloating() const { return !(noninherited_flags.f._floating == FNONE); } - bool hasMargin() const { return surround->margin.nonZero(); } - bool hasBorder() const { return surround->border.hasBorder(); } - bool hasOffset() const { return surround->offset.nonZero(); } - - bool hasBackground() const { - if (backgroundColor().isValid() && tqAlpha(backgroundColor().rgb()) > 0) - return true; - else - return background->m_background.hasImage(); - } - bool hasFixedBackgroundImage() const { return background->m_background.hasFixedImage(); } - - bool visuallyOrdered() const { return inherited_flags.f._visuallyOrdered; } - void setVisuallyOrdered(bool b) { inherited_flags.f._visuallyOrdered = b; } - -// attribute getter methods - - EDisplay display() const { return noninherited_flags.f._display; } - EDisplay originalDisplay() const { return noninherited_flags.f._originalDisplay; } - - Length left() const { return surround->offset.left; } - Length right() const { return surround->offset.right; } - Length top() const { return surround->offset.top; } - Length bottom() const { return surround->offset.bottom; } - - EPosition position() const { return noninherited_flags.f._position; } - EFloat floating() const { return noninherited_flags.f._floating; } - - Length width() const { return box->width; } - Length height() const { return box->height; } - Length minWidth() const { return box->min_width; } - Length maxWidth() const { return box->max_width; } - Length minHeight() const { return box->min_height; } - Length maxHeight() const { return box->max_height; } - - const BorderData& border() const { return surround->border; } - const BorderValue& borderLeft() const { return surround->border.left; } - const BorderValue& borderRight() const { return surround->border.right; } - const BorderValue& borderTop() const { return surround->border.top; } - const BorderValue& borderBottom() const { return surround->border.bottom; } - - unsigned short borderLeftWidth() const { return surround->border.borderLeftWidth(); } - EBorderStyle borderLeftStyle() const { return surround->border.left.style; } - const TQColor& borderLeftColor() const { return surround->border.left.color; } - bool borderLeftIsTransparent() const { return surround->border.left.isTransparent(); } - unsigned short borderRightWidth() const { return surround->border.borderRightWidth(); } - EBorderStyle borderRightStyle() const { return surround->border.right.style; } - const TQColor& borderRightColor() const { return surround->border.right.color; } - bool borderRightIsTransparent() const { return surround->border.right.isTransparent(); } - unsigned short borderTopWidth() const { return surround->border.borderTopWidth(); } - EBorderStyle borderTopStyle() const { return surround->border.top.style; } - const TQColor& borderTopColor() const { return surround->border.top.color; } - bool borderTopIsTransparent() const { return surround->border.top.isTransparent(); } - unsigned short borderBottomWidth() const { return surround->border.borderBottomWidth(); } - EBorderStyle borderBottomStyle() const { return surround->border.bottom.style; } - const TQColor& borderBottomColor() const { return surround->border.bottom.color; } - bool borderBottomIsTransparent() const { return surround->border.bottom.isTransparent(); } - - unsigned short outlineSize() const { return outlineWidth() + outlineOffset(); } - unsigned short outlineWidth() const - { if(background->m_outline.style == BNONE || background->m_outline.style == BHIDDEN) return 0; - else return background->m_outline.width; } - EBorderStyle outlineStyle() const { return background->m_outline.style; } - bool outlineStyleIsAuto() const { return background->m_outline._auto; } - const TQColor & outlineColor() const { return background->m_outline.color; } - - EOverflow overflowX() const { return noninherited_flags.f._overflowX; } - EOverflow overflowY() const { return noninherited_flags.f._overflowY; } - bool hidesOverflow() const { - // either both overflow are visible or none are - return overflowX() != OVISIBLE; - } - - EVisibility visibility() const { return inherited_flags.f._visibility; } - EVerticalAlign verticalAlign() const { return noninherited_flags.f._vertical_align; } - Length verticalAlignLength() const { return box->vertical_align; } - - Length clipLeft() const { return visual->clip.left; } - Length clipRight() const { return visual->clip.right; } - Length clipTop() const { return visual->clip.top; } - Length clipBottom() const { return visual->clip.bottom; } - LengthBox clip() const { return visual->clip; } - bool hasClip() const { return noninherited_flags.f._hasClip; } - - EUnicodeBidi unicodeBidi() const { return noninherited_flags.f._unicodeBidi; } - - EClear clear() const { return noninherited_flags.f._clear; } - ETableLayout tableLayout() const { return noninherited_flags.f._table_layout; } - - const TQFont & font() const { return inherited->font.f; } - // use with care. call font->update() after modifications - const Font &htmlFont() { return inherited->font; } - const TQFontMetrics & fontMetrics() const { return inherited->font.fm; } - - const TQColor & color() const { return inherited->color; } - Length textIndent() const { return inherited->indent; } - ETextAlign textAlign() const { return inherited_flags.f._text_align; } - ETextTransform textTransform() const { return inherited_flags.f._text_transform; } - int textDecorationsInEffect() const { return inherited_flags.f._text_decorations; } - int textDecoration() const { return visual->textDecoration; } - int wordSpacing() const { return inherited->font.wordSpacing; } - int letterSpacing() const { return inherited->font.letterSpacing; } - - EDirection direction() const { return inherited_flags.f._direction; } - Length lineHeight() const { return inherited->line_height; } - - EWhiteSpace whiteSpace() const { return inherited_flags.f._white_space; } - bool autoWrap() const { - if (whiteSpace() == NORMAL || whiteSpace() == PRE_WRAP || whiteSpace() == PRE_LINE) - return true; - // nowrap | pre - return false; - } - bool preserveLF() const { - if (whiteSpace() == PRE || whiteSpace() == PRE_WRAP || whiteSpace() == PRE_LINE) - return true; - // normal | nowrap - return false; - } - bool preserveWS() const { - if (whiteSpace() == PRE || whiteSpace() == PRE_WRAP) - return true; - // normal | nowrap | pre-line - return false; - } - - const TQColor & backgroundColor() const { return background->m_color; } - CachedImage *backgroundImage() const { return background->m_background.m_image; } - EBackgroundRepeat backgroundRepeat() const { return background->m_background.m_bgRepeat; } - bool backgroundAttachment() const { return background->m_background.m_bgAttachment; } - Length backgroundXPosition() const { return background->m_background.m_xPosition; } - Length backgroundYPosition() const { return background->m_background.m_yPosition; } - BackgroundLayer* accessBackgroundLayers() { return &(background.access()->m_background); } - const BackgroundLayer* backgroundLayers() const { return &(background->m_background); } - - // returns true for collapsing borders, false for separate borders - bool borderCollapse() const { return inherited_flags.f._border_collapse; } - short borderHorizontalSpacing() const { return inherited->border_hspacing; } - short borderVerticalSpacing() const { return inherited->border_vspacing; } - EEmptyCell emptyCells() const { return inherited_flags.f._empty_cells; } - ECaptionSide captionSide() const { return inherited_flags.f._caption_side; } - - EListStyleType listStyleType() const { return inherited_flags.f._list_style_type; } - CachedImage *listStyleImage() const { return inherited->style_image; } - EListStylePosition listStylePosition() const { return inherited_flags.f._list_style_position; } - - Length marginTop() const { return surround->margin.top; } - Length marginBottom() const { return surround->margin.bottom; } - Length marginLeft() const { return surround->margin.left; } - Length marginRight() const { return surround->margin.right; } - - Length paddingTop() const { return surround->padding.top; } - Length paddingBottom() const { return surround->padding.bottom; } - Length paddingLeft() const { return surround->padding.left; } - Length paddingRight() const { return surround->padding.right; } - - ECursor cursor() const { return inherited_flags.f._cursor_style; } - - short widows() const { return inherited->widows; } - short orphans() const { return inherited->orphans; } - bool pageBreakInside() const { return inherited_flags.f._page_break_inside; } - EPageBreak pageBreakBefore() const { return noninherited_flags.f._page_break_before; } - EPageBreak pageBreakAfter() const { return noninherited_flags.f._page_break_after; } - - DOM::QuotesValueImpl* quotes() const { return inherited->quotes; } - TQString openQuote(int level) const; - TQString closeQuote(int level) const; - - // CSS3 Getter Methods - EBoxSizing boxSizing() const { return box->box_sizing; } - int outlineOffset() const { - if (background->m_outline.style == BNONE || background->m_outline.style == BHIDDEN) return 0; - return background->m_outline._offset; - } - ShadowData* textShadow() const { return css3InheritedData->textShadow; } - EWordWrap wordWrap() const { return css3InheritedData->wordWrap; } - float opacity() { return css3NonInheritedData->opacity; } - EUserInput userInput() const { return inherited_flags.f._user_input; } - - Length marqueeIncrement() { return css3NonInheritedData->marquee->increment; } - int marqueeSpeed() { return css3NonInheritedData->marquee->speed; } - int marqueeLoopCount() { return css3NonInheritedData->marquee->loops; } - EMarqueeBehavior marqueeBehavior() { return css3NonInheritedData->marquee->behavior; } - EMarqueeDirection marqueeDirection() { return css3NonInheritedData->marquee->direction; } - bool textOverflow() const { return noninherited_flags.f._textOverflow; } - // End CSS3 Getters - -// attribute setter methods - - void setDisplay(EDisplay v) { noninherited_flags.f._display = v; } - void setOriginalDisplay(EDisplay v) { noninherited_flags.f._originalDisplay = v; } - void setPosition(EPosition v) { noninherited_flags.f._position = v; } - void setFloating(EFloat v) { noninherited_flags.f._floating = v; } - - void setLeft(Length v) { SET_VAR(surround,offset.left,v) } - void setRight(Length v) { SET_VAR(surround,offset.right,v) } - void setTop(Length v) { SET_VAR(surround,offset.top,v) } - void setBottom(Length v){ SET_VAR(surround,offset.bottom,v) } - - void setWidth(Length v) { SET_VAR(box,width,v) } - void setHeight(Length v) { SET_VAR(box,height,v) } - - void setMinWidth(Length v) { SET_VAR(box,min_width,v) } - void setMaxWidth(Length v) { SET_VAR(box,max_width,v) } - void setMinHeight(Length v) { SET_VAR(box,min_height,v) } - void setMaxHeight(Length v) { SET_VAR(box,max_height,v) } - - void resetBorderTop() { SET_VAR(surround, border.top, BorderValue()) } - void resetBorderRight() { SET_VAR(surround, border.right, BorderValue()) } - void resetBorderBottom() { SET_VAR(surround, border.bottom, BorderValue()) } - void resetBorderLeft() { SET_VAR(surround, border.left, BorderValue()) } - void resetOutline() { SET_VAR(background, m_outline, OutlineValue()) } - - void setBackgroundColor(const TQColor& v) { SET_VAR(background, m_color, v) } - - void setBorderLeftWidth(unsigned short v) { SET_VAR(surround,border.left.width,v) } - void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround,border.left.style,v) } - void setBorderLeftColor(const TQColor & v) { SET_VAR(surround,border.left.color,v) } - void setBorderRightWidth(unsigned short v) { SET_VAR(surround,border.right.width,v) } - void setBorderRightStyle(EBorderStyle v) { SET_VAR(surround,border.right.style,v) } - void setBorderRightColor(const TQColor & v) { SET_VAR(surround,border.right.color,v) } - void setBorderTopWidth(unsigned short v) { SET_VAR(surround,border.top.width,v) } - void setBorderTopStyle(EBorderStyle v) { SET_VAR(surround,border.top.style,v) } - void setBorderTopColor(const TQColor & v) { SET_VAR(surround,border.top.color,v) } - void setBorderBottomWidth(unsigned short v) { SET_VAR(surround,border.bottom.width,v) } - void setBorderBottomStyle(EBorderStyle v) { SET_VAR(surround,border.bottom.style,v) } - void setBorderBottomColor(const TQColor & v) { SET_VAR(surround,border.bottom.color,v) } - void setOutlineWidth(unsigned short v) { SET_VAR(background,m_outline.width,v) } - void setOutlineStyle(EBorderStyle v, bool isAuto = false) - { - SET_VAR(background,m_outline.style,v) - SET_VAR(background,m_outline._auto, isAuto) - } - void setOutlineColor(const TQColor & v) { SET_VAR(background,m_outline.color,v) } - - void setOverflowX(EOverflow v) { noninherited_flags.f._overflowX = v; } - void setOverflowY(EOverflow v) { noninherited_flags.f._overflowY = v; } - void setVisibility(EVisibility v) { inherited_flags.f._visibility = v; } - void setVerticalAlign(EVerticalAlign v) { noninherited_flags.f._vertical_align = v; } - void setVerticalAlignLength(Length l) { SET_VAR(box, vertical_align, l ) } - - void setClipLeft(Length v) { SET_VAR(visual,clip.left,v) } - void setClipRight(Length v) { SET_VAR(visual,clip.right,v) } - void setClipTop(Length v) { SET_VAR(visual,clip.top,v) } - void setClipBottom(Length v) { SET_VAR(visual,clip.bottom,v) } - void setClip( Length top, Length right, Length bottom, Length left ); - void setHasClip( bool b ) { noninherited_flags.f._hasClip = b; } - - void setUnicodeBidi( EUnicodeBidi b ) { noninherited_flags.f._unicodeBidi = b; } - - void setClear(EClear v) { noninherited_flags.f._clear = v; } - void setTableLayout(ETableLayout v) { noninherited_flags.f._table_layout = v; } - bool setFontDef(const khtml::FontDef & v) { - // bah, this doesn't compare pointers. broken! (Dirk) - if (!(inherited->font.fontDef == v)) { - inherited.access()->font = Font( v ); - return true; - } - return false; - } - - void setColor(const TQColor & v) { SET_VAR(inherited,color,v) } - void setTextIndent(Length v) { SET_VAR(inherited,indent,v) } - void setTextAlign(ETextAlign v) { inherited_flags.f._text_align = v; } - void setTextTransform(ETextTransform v) { inherited_flags.f._text_transform = v; } - void addToTextDecorationsInEffect(int v) { inherited_flags.f._text_decorations |= v; } - void setTextDecorationsInEffect(int v) { inherited_flags.f._text_decorations = v; } - void setTextDecoration(unsigned v) { SET_VAR(visual, textDecoration, v); } - void setDirection(EDirection v) { inherited_flags.f._direction = v; } - void setLineHeight(Length v) { SET_VAR(inherited,line_height,v) } - - void setWhiteSpace(EWhiteSpace v) { inherited_flags.f._white_space = v; } - - void setWordSpacing(int v) { SET_VAR(inherited,font.wordSpacing,v) } - void setLetterSpacing(int v) { SET_VAR(inherited,font.letterSpacing,v) } - - void clearBackgroundLayers() { background.access()->m_background = BackgroundLayer(); } - void inheritBackgroundLayers(const BackgroundLayer& parent) { background.access()->m_background = parent; } - void adjustBackgroundLayers(); - - void setBorderCollapse(bool collapse) { inherited_flags.f._border_collapse = collapse; } - void setBorderHorizontalSpacing(short v) { SET_VAR(inherited,border_hspacing,v) } - void setBorderVerticalSpacing(short v) { SET_VAR(inherited,border_vspacing,v) } - - void setEmptyCells(EEmptyCell v) { inherited_flags.f._empty_cells = v; } - void setCaptionSide(ECaptionSide v) { inherited_flags.f._caption_side = v; } - - void setListStyleType(EListStyleType v) { inherited_flags.f._list_style_type = v; } - void setListStyleImage(CachedImage *v) { SET_VAR(inherited,style_image,v)} - void setListStylePosition(EListStylePosition v) { inherited_flags.f._list_style_position = v; } - - void resetMargin() { SET_VAR(surround, margin, LengthBox(Fixed)) } - void setMarginTop(Length v) { SET_VAR(surround,margin.top,v) } - void setMarginBottom(Length v) { SET_VAR(surround,margin.bottom,v) } - void setMarginLeft(Length v) { SET_VAR(surround,margin.left,v) } - void setMarginRight(Length v) { SET_VAR(surround,margin.right,v) } - - void resetPadding() { SET_VAR(surround, padding, LengthBox(Variable)) } - void setPaddingTop(Length v) { SET_VAR(surround,padding.top,v) } - void setPaddingBottom(Length v) { SET_VAR(surround,padding.bottom,v) } - void setPaddingLeft(Length v) { SET_VAR(surround,padding.left,v) } - void setPaddingRight(Length v) { SET_VAR(surround,padding.right,v) } - - void setCursor( ECursor c ) { inherited_flags.f._cursor_style = c; } - - bool htmlHacks() const { return inherited_flags.f._htmlHacks; } - void setHtmlHacks(bool b=true) { inherited_flags.f._htmlHacks = b; } - - bool flowAroundFloats() const { return noninherited_flags.f._flowAroundFloats; } - void setFlowAroundFloats(bool b=true) { noninherited_flags.f._flowAroundFloats = b; } - - int zIndex() const { return box->z_auto? 0 : box->z_index; } - void setZIndex(int v) { SET_VAR(box,z_auto,false ); SET_VAR(box, z_index, v); } - bool hasAutoZIndex() const { return box->z_auto; } - void setHasAutoZIndex() { SET_VAR(box, z_auto, true ); } - - void setWidows(short w) { SET_VAR(inherited, widows, w); } - void setOrphans(short o) { SET_VAR(inherited, orphans, o); } - void setPageBreakInside(bool b) { inherited_flags.f._page_break_inside = b; } - void setPageBreakBefore(EPageBreak b) { noninherited_flags.f._page_break_before = b; } - void setPageBreakAfter(EPageBreak b) { noninherited_flags.f._page_break_after = b; } - - void setQuotes(DOM::QuotesValueImpl* q); - - // CSS3 Setters - void setBoxSizing( EBoxSizing b ) { SET_VAR(box,box_sizing,b); } - void setOutlineOffset(unsigned short v) { SET_VAR(background,m_outline._offset,v) } - void setWordWrap(EWordWrap w) { SET_VAR(css3InheritedData, wordWrap, w); } - void setTextShadow(ShadowData* val, bool add=false); - void setOpacity(float f) { SET_VAR(css3NonInheritedData, opacity, f); } - void setUserInput(EUserInput ui) { inherited_flags.f._user_input = ui; } - - void setMarqueeIncrement(const Length& f) { SET_VAR(css3NonInheritedData.access()->marquee, increment, f); } - void setMarqueeSpeed(int f) { SET_VAR(css3NonInheritedData.access()->marquee, speed, f); } - void setMarqueeDirection(EMarqueeDirection d) { SET_VAR(css3NonInheritedData.access()->marquee, direction, d); } - void setMarqueeBehavior(EMarqueeBehavior b) { SET_VAR(css3NonInheritedData.access()->marquee, behavior, b); } - void setMarqueeLoopCount(int i) { SET_VAR(css3NonInheritedData.access()->marquee, loops, i); } - void setTextOverflow(bool b) { noninherited_flags.f._textOverflow = b; } - // End CSS3 Setters - - TQPalette palette() const { return visual->palette; } - void setPaletteColor(TQPalette::ColorGroup g, TQColorGroup::ColorRole r, const TQColor& c); - void resetPalette() // Called when the desktop color scheme changes. - { - const_cast<StyleVisualData *>(visual.get())->palette = TQApplication::palette(); - } - - bool useNormalContent() const { return generated->content == 0; } - ContentData* contentData() const { return generated->content; } - bool contentDataEquivalent(const RenderStyle* otherStyle) const - { - return generated->contentDataEquivalent(otherStyle->generated.get()); - } - void addContent(DOM::DOMStringImpl* s); - void addContent(CachedObject* o); - void addContent(DOM::CounterImpl* c); - void addContent(EQuoteContent q); - void setContentNone(); - void setContentNormal(); - void setContentData(ContentData* content); - - DOM::CSSValueListImpl* counterReset() const { return generated->counter_reset; } - DOM::CSSValueListImpl* counterIncrement() const { return generated->counter_increment; } - void setCounterReset(DOM::CSSValueListImpl* v); - void setCounterIncrement(DOM::CSSValueListImpl* v); - bool hasCounterReset(const DOM::DOMString& c) const; - bool hasCounterIncrement(const DOM::DOMString& c) const; - short counterReset(const DOM::DOMString& c) const; - short counterIncrement(const DOM::DOMString& c) const; - - - bool inheritedNotEqual( RenderStyle *other ) const; - - enum Diff { Equal, NonVisible = Equal, Visible, Position, Layout, CbLayout }; - Diff diff( const RenderStyle *other ) const; - - bool isDisplayReplacedType() { - return display() == INLINE_BLOCK ||/* display() == INLINE_BOX ||*/ display() == INLINE_TABLE; - } - bool isDisplayInlineType() { - return display() == INLINE || isDisplayReplacedType(); - } - bool isOriginalDisplayInlineType() { - return originalDisplay() == INLINE || originalDisplay() == INLINE_BLOCK || - /*originalDisplay() == INLINE_BOX ||*/ originalDisplay() == INLINE_TABLE; - } - - -#ifdef ENABLE_DUMP - TQString createDiff( const RenderStyle &parent ) const; -#endif - - // Initial values for all the properties - static bool initialBackgroundAttachment() { return true; } - static EBackgroundBox initialBackgroundClip() { return BGBORDER; } - static EBackgroundBox initialBackgroundOrigin() { return BGPADDING; } - static EBackgroundRepeat initialBackgroundRepeat() { return REPEAT; } - static LengthSize initialBackgroundSize() { return LengthSize(); } - static bool initialBorderCollapse() { return false; } - static EBorderStyle initialBorderStyle() { return BNONE; } - static ECaptionSide initialCaptionSide() { return CAPTOP; } - static EClear initialClear() { return CNONE; } - static EDirection initialDirection() { return LTR; } - static EDisplay initialDisplay() { return INLINE; } - static EEmptyCell initialEmptyCells() { return SHOW; } - static EFloat initialFloating() { return FNONE; } - static EWordWrap initialWordWrap() { return WWNORMAL; } - static EListStylePosition initialListStylePosition() { return OUTSIDE; } - static EListStyleType initialListStyleType() { return LDISC; } - static EOverflow initialOverflowX() { return OVISIBLE; } - static EOverflow initialOverflowY() { return OVISIBLE; } - static EPageBreak initialPageBreak() { return PBAUTO; } - static bool initialPageBreakInside() { return true; } - static EPosition initialPosition() { return STATIC; } - static ETableLayout initialTableLayout() { return TAUTO; } - static EUnicodeBidi initialUnicodeBidi() { return UBNormal; } - static DOM::QuotesValueImpl* initialQuotes() { return 0; } - static EBoxSizing initialBoxSizing() { return CONTENT_BOX; } - static ETextTransform initialTextTransform() { return TTNONE; } - static EVisibility initialVisibility() { return VISIBLE; } - static EWhiteSpace initialWhiteSpace() { return NORMAL; } - static Length initialBackgroundXPosition() { return Length(); } - static Length initialBackgroundYPosition() { return Length(); } - static short initialBorderHorizontalSpacing() { return 0; } - static short initialBorderVerticalSpacing() { return 0; } - static ECursor initialCursor() { return CURSOR_AUTO; } - static TQColor initialColor() { return Qt::black; } - static CachedImage* initialBackgroundImage() { return 0; } - static CachedImage* initialListStyleImage() { return 0; } - static unsigned short initialBorderWidth() { return 3; } - static int initialLetterWordSpacing() { return 0; } - static Length initialSize() { return Length(); } - static Length initialMinSize() { return Length(0, Fixed); } - static Length initialMaxSize() { return Length(UNDEFINED, Fixed); } - static Length initialOffset() { return Length(); } - static Length initialMargin() { return Length(Fixed); } - static Length initialPadding() { return Length(Variable); } - static Length initialTextIndent() { return Length(Fixed); } - static EVerticalAlign initialVerticalAlign() { return BASELINE; } - static int initialWidows() { return 2; } - static int initialOrphans() { return 2; } - static Length initialLineHeight() { return Length(-100, Percent); } - static ETextAlign initialTextAlign() { return TAAUTO; } - static ETextDecoration initialTextDecoration() { return TDNONE; } - static bool initialFlowAroundFloats() { return false; } - static int initialOutlineOffset() { return 0; } - static float initialOpacity() { return 1.0f; } - static int initialMarqueeLoopCount() { return -1; } - static int initialMarqueeSpeed() { return 85; } - static Length initialMarqueeIncrement() { return Length(6, Fixed); } - static EMarqueeBehavior initialMarqueeBehavior() { return MSCROLL; } - static EMarqueeDirection initialMarqueeDirection() { return MAUTO; } - static bool initialTextOverflow() { return false; } -}; - -class RenderPageStyle { - friend class CSSStyleSelector; -public: - enum PageType { NO_PAGE = 0, ANY_PAGE, FIRST_PAGE, LEFT_PAGES, RIGHT_PAGES }; - - RenderPageStyle(); - ~RenderPageStyle(); - - PageType pageType() { return m_pageType; } - - RenderPageStyle* getPageStyle(PageType type); - RenderPageStyle* addPageStyle(PageType type); - void removePageStyle(PageType type); - - Length marginTop() const { return margin.top; } - Length marginBottom() const { return margin.bottom; } - Length marginLeft() const { return margin.left; } - Length marginRight() const { return margin.right; } - - Length pageWidth() const { return m_pageWidth; } - Length pageHeight() const { return m_pageHeight; } - - void setMarginTop(Length v) { margin.top = v; } - void setMarginBottom(Length v) { margin.bottom = v; } - void setMarginLeft(Length v) { margin.left = v; } - void setMarginRight(Length v) { margin.right = v; } - - void setPageWidth(Length v) { m_pageWidth = v; } - void setPageHeight(Length v) { m_pageHeight = v; } - -protected: - RenderPageStyle *next; - PageType m_pageType; - - LengthBox margin; - Length m_pageWidth; - Length m_pageHeight; -}; - -} // namespace - -#endif - diff --git a/khtml/rendering/render_table.cpp b/khtml/rendering/render_table.cpp deleted file mode 100644 index d98aa2072..000000000 --- a/khtml/rendering/render_table.cpp +++ /dev/null @@ -1,3070 +0,0 @@ -/** - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1997 Martin Jones (mjones@kde.org) - * (C) 1997 Torben Weis (weis@kde.org) - * (C) 1998 Waldo Bastian (bastian@kde.org) - * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2003 Apple Computer, Inc. - * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - */ - -//#define TABLE_DEBUG -//#define TABLE_PRINT -//#define DEBUG_LAYOUT -//#define BOX_DEBUG -#include "rendering/render_table.h" -#include "rendering/render_replaced.h" -#include "rendering/render_canvas.h" -#include "rendering/table_layout.h" -#include "html/html_tableimpl.h" -#include "html/html_formimpl.h" -#include "misc/htmltags.h" -#include "misc/htmlattrs.h" -#include "rendering/render_line.h" -#include "xml/dom_docimpl.h" - -#include <kglobal.h> - -#include <tqapplication.h> -#include <tqstyle.h> - -#include <kdebug.h> -#include <assert.h> - -using namespace khtml; -using namespace DOM; - -RenderTable::RenderTable(DOM::NodeImpl* node) - : RenderBlock(node) -{ - - tCaption = 0; - head = foot = firstBody = 0; - tableLayout = 0; - m_currentBorder = 0; - - has_col_elems = false; - hspacing = vspacing = 0; - padding = 0; - needSectionRecalc = false; - padding = 0; - - columnPos.resize( 2 ); - columnPos.fill( 0 ); - columns.resize( 1 ); - columns.fill( ColumnStruct() ); - - columnPos[0] = 0; -} - -RenderTable::~RenderTable() -{ - delete tableLayout; -} - -void RenderTable::setStyle(RenderStyle *_style) -{ - ETableLayout oldTableLayout = style() ? style()->tableLayout() : TAUTO; - if ( _style->display() == INLINE ) _style->setDisplay( INLINE_TABLE ); - if ( _style->display() != INLINE_TABLE ) _style->setDisplay(TABLE); - if ( !_style->flowAroundFloats() ) _style->setFlowAroundFloats(true); - RenderBlock::setStyle(_style); - - // init RenderObject attributes - setInline(style()->display()==INLINE_TABLE && !isPositioned()); - setReplaced(style()->display()==INLINE_TABLE); - - // In the collapsed border model, there is no cell spacing. - hspacing = collapseBorders() ? 0 : style()->borderHorizontalSpacing(); - vspacing = collapseBorders() ? 0 : style()->borderVerticalSpacing(); - columnPos[0] = hspacing; - - if ( !tableLayout || style()->tableLayout() != oldTableLayout ) { - delete tableLayout; - - // According to the CSS2 spec, you only use fixed table layout if an - // explicit width is specified on the table. Auto width implies auto table layout. - if (style()->tableLayout() == TFIXED && !style()->width().isVariable()) { - tableLayout = new FixedTableLayout(this); -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "using fixed table layout" << endl; -#endif - } else - tableLayout = new AutoTableLayout(this); - } -} - -short RenderTable::lineHeight(bool b) const -{ - // Inline tables are replaced elements. Otherwise, just pass off to - // the base class. - if (isReplaced()) - return height()+marginTop()+marginBottom(); - return RenderBlock::lineHeight(b); -} - -short RenderTable::baselinePosition(bool b) const -{ - // Inline tables are replaced elements. Otherwise, just pass off to - // the base class. - if (isReplaced()) - return height()+marginTop()+marginBottom(); - return RenderBlock::baselinePosition(b); -} - - -void RenderTable::addChild(RenderObject *child, RenderObject *beforeChild) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(Table)::addChild( " << child->renderName() << ", " << - (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; -#endif - bool wrapInAnonymousSection = false; - - switch(child->style()->display()) - { - case TABLE_CAPTION: - if (child->isRenderBlock()) - tCaption = static_cast<RenderBlock *>(child); - break; - case TABLE_COLUMN: - case TABLE_COLUMN_GROUP: - has_col_elems = true; - break; - case TABLE_HEADER_GROUP: - if ( !head ) { - if (child->isTableSection()) - head = static_cast<RenderTableSection *>(child); - } - else if ( !firstBody ) - if (child->isTableSection()) - firstBody = static_cast<RenderTableSection *>(child); - break; - case TABLE_FOOTER_GROUP: - if ( !foot ) { - if (child->isTableSection()) - foot = static_cast<RenderTableSection *>(child); - break; - } - // fall through - case TABLE_ROW_GROUP: - if(!firstBody) - if (child->isTableSection()) - firstBody = static_cast<RenderTableSection *>(child); - break; - case TABLE_CELL: - case TABLE_ROW: - wrapInAnonymousSection = true; - break; - case BLOCK: -// case BOX: - case COMPACT: - case INLINE: - case INLINE_BLOCK: -// case INLINE_BOX: - case INLINE_TABLE: - case LIST_ITEM: - case NONE: - case RUN_IN: - case TABLE: - // The special TABLE > FORM quirk allows the form to sit directly under the table - if (child->element() && child->element()->isHTMLElement() && child->element()->id() == ID_FORM) - wrapInAnonymousSection = !static_cast<HTMLFormElementImpl*>(child->element())->isMalformed(); - else - wrapInAnonymousSection = true; - break; - } - - if (!wrapInAnonymousSection) { - RenderContainer::addChild(child, beforeChild); - return; - } - - if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) { - lastChild()->addChild(child); - return; - } - - RenderObject *lastBox = beforeChild; - RenderObject *nextToLastBox = beforeChild; - while (lastBox && lastBox->parent()->isAnonymous() && - !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION) { - nextToLastBox = lastBox; - lastBox = lastBox->parent(); - } - if (lastBox && lastBox->isAnonymous()) { - lastBox->addChild(child, nextToLastBox); - return; - } - - if (beforeChild && !beforeChild->isTableSection()) - beforeChild = 0; - RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */); - RenderStyle* newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE_ROW_GROUP); - section->setStyle(newStyle); - addChild(section, beforeChild); - section->addChild(child); -} - -void RenderTable::calcWidth() -{ - if ( isPositioned() ) { - calcAbsoluteHorizontal(); - } - - RenderBlock *cb = containingBlock(); - int availableWidth = cb->lineWidth( m_y ); - - LengthType widthType = style()->width().type(); - if(widthType > Relative && style()->width().value() > 0) { - // Percent or fixed table - // Percent is calculated from contentWidth, not available width - m_width = calcBoxWidth(style()->width().minWidth( cb->contentWidth() )); - } else { - // Subtract out any fixed margins from our available width for auto width tables. - int marginTotal = 0; - if (!style()->marginLeft().isVariable()) - marginTotal += style()->marginLeft().width(availableWidth); - if (!style()->marginRight().isVariable()) - marginTotal += style()->marginRight().width(availableWidth); - - // Subtract out our margins to get the available content width. - int availContentWidth = kMax(0, availableWidth - marginTotal); - - // Ensure we aren't bigger than our max width or smaller than our min width. - m_width = kMin(availContentWidth, m_maxWidth); - } - - m_width = kMax (m_width, m_minWidth); - - // Finally, with our true width determined, compute our margins for real. - m_marginRight=0; - m_marginLeft=0; - - calcHorizontalMargins(style()->marginLeft(),style()->marginRight(),availableWidth); -} - -void RenderTable::layout() -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - KHTMLAssert( !needSectionRecalc ); - - if (posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) { - // All we have to is lay out our positioned objects. - layoutPositionedObjects(true); - setNeedsLayout(false); - return; - } - - if (markedForRepaint()) { - repaintDuringLayout(); - setMarkedForRepaint(false); - } - - m_height = 0; - initMaxMarginValues(); - - int oldWidth = m_width; - calcWidth(); - m_overflowWidth = m_width; - - if (tCaption && (oldWidth != m_width || tCaption->style()->height().isPercent())) - tCaption->setChildNeedsLayout(true); - - // the optimization below doesn't work since the internal table - // layout could have changed. we need to add a flag to the table - // layout that tells us if something has changed in the min max - // calculations to do it correctly. -// if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() ) - tableLayout->layout(); - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(Table)::layout1() width=" << width() << ", marginLeft=" << marginLeft() << " marginRight=" << marginRight() << endl; -#endif - - setCellWidths(); - - // layout child objects - int calculatedHeight = 0; - - RenderObject *child = firstChild(); - while( child ) { - // FIXME: What about a form that has a display value that makes it a table section? - if ( child->needsLayout() && !(child->element() && child->element()->id() == ID_FORM) ) - child->layout(); - if ( child->isTableSection() ) { - static_cast<RenderTableSection *>(child)->calcRowHeight(); - calculatedHeight += static_cast<RenderTableSection *>(child)->layoutRows( 0 ); - } - child = child->nextSibling(); - } - - // ### collapse caption margin - if(tCaption && tCaption->style()->captionSide() != CAPBOTTOM) { - tCaption->setPos(tCaption->marginLeft(), tCaption->marginTop()+m_height); - m_height += tCaption->height() + tCaption->marginTop() + tCaption->marginBottom(); - } - - int bpTop = borderTop() + (collapseBorders() ? 0 : paddingTop()); - int bpBottom = borderBottom() + (collapseBorders() ? 0 : paddingBottom()); - - m_height += bpTop; - - int oldHeight = m_height; - if (isPositioned()) - m_height += calculatedHeight + bpBottom; - calcHeight(); - int newHeight = m_height; - m_height = oldHeight; - - Length h = style()->height(); - int th = -(bpTop + bpBottom); // Tables size as though CSS height includes border/padding. - if (isPositioned()) - th += newHeight; - else if (h.isFixed()) - th += h.value(); - else if (h.isPercent()) - th += calcPercentageHeight(h); - - // layout rows - if ( th > calculatedHeight ) { - // we have to redistribute that height to get the constraint correctly - // just force the first body to the height needed - // ### FIXME This should take height constraints on all table sections into account and distribute - // accordingly. For now this should be good enough - if (firstBody) { - firstBody->calcRowHeight(); - firstBody->layoutRows( th - calculatedHeight ); - } - else if (!style()->htmlHacks()) { - // Completely empty tables (with no sections or anything) should at least honor specified height - // in strict mode. - m_height += th; - } - } - - int bl = borderLeft(); - if (!collapseBorders()) - bl += paddingLeft(); - - // position the table sections - if ( head ) { - head->setPos(bl, m_height); - m_height += head->height(); - } - RenderObject *body = firstBody; - while ( body ) { - if ( body != head && body != foot && body->isTableSection() ) { - body->setPos(bl, m_height); - m_height += body->height(); - } - body = body->nextSibling(); - } - if ( foot ) { - foot->setPos(bl, m_height); - m_height += foot->height(); - } - - m_height += bpBottom; - - if(tCaption && tCaption->style()->captionSide()==CAPBOTTOM) { - tCaption->setPos(tCaption->marginLeft(), tCaption->marginTop()+m_height); - m_height += tCaption->height() + tCaption->marginTop() + tCaption->marginBottom(); - } - - if (canvas()->pagedMode()) { - RenderObject *child = firstChild(); - // relayout taking real position into account - while( child ) { - if ( !(child->element() && child->element()->id() == ID_FORM) ) { - child->setNeedsLayout(true); - child->layout(); - if (child->containsPageBreak()) setContainsPageBreak(true); - if (child->needsPageClear()) setNeedsPageClear(true); - } - child = child->nextSibling(); - } - } - - //kdDebug(0) << "table height: " << m_height << endl; - - // table can be containing block of positioned elements. - // ### only pass true if width or height changed. - layoutPositionedObjects( true ); - - m_overflowHeight = m_height; - - setNeedsLayout(false); -} - -void RenderTable::setCellWidths() -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(Table, this=0x" << this << ")::setCellWidths()" << endl; -#endif - - RenderObject *child = firstChild(); - while( child ) { - if ( child->isTableSection() ) - static_cast<RenderTableSection *>(child)->setCellWidths(); - child = child->nextSibling(); - } -} - -void RenderTable::paint( PaintInfo& pI, int _tx, int _ty) -{ - if(needsLayout()) return; - - _tx += xPos(); - _ty += yPos(); - -#ifdef TABLE_PRINT - kdDebug( 6040 ) << "RenderTable::paint() w/h = (" << width() << "/" << height() << ")" << endl; -#endif - if (!overhangingContents() && !isRelPositioned() && !isPositioned()) - { - int os = 2*maximalOutlineSize(pI.phase); - if((_ty > pI.r.y() + pI.r.height() + os) || (_ty + height() < pI.r.y() - os)) return; - if((_tx > pI.r.x() + pI.r.width() + os) || (_tx + width() < pI.r.x() - os)) return; - } - -#ifdef TABLE_PRINT - kdDebug( 6040 ) << "RenderTable::paint(2) " << _tx << "/" << _ty << " (" << _y << "/" << _h << ")" << endl; -#endif - - if (pI.phase == PaintActionOutline) - paintOutline(pI.p, _tx, _ty, width(), height(), style()); - - if(( pI.phase == PaintActionElementBackground || pI.phase == PaintActionChildBackground ) - && shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) - paintBoxDecorations(pI, _tx, _ty); - - if ( pI.phase == PaintActionElementBackground ) - return; - - PaintAction oldphase = pI.phase; - if ( pI.phase == PaintActionChildBackgrounds ) - pI.phase = PaintActionChildBackground; - - for( RenderObject *child = firstChild(); child; child = child->nextSibling()) - if ( child->isTableSection() || child == tCaption ) - child->paint( pI, _tx, _ty ); - - if (collapseBorders() && - (pI.phase == PaintActionElementBackground || pI.phase == PaintActionChildBackground) - && style()->visibility() == VISIBLE) { - // Collect all the unique border styles that we want to paint in a sorted list. Once we - // have all the styles sorted, we then do individual passes, painting each style of border - // from lowest precedence to highest precedence. - pI.phase = PaintActionCollapsedTableBorders; - TQValueList<CollapsedBorderValue> borderStyles; - collectBorders(borderStyles); -#if 0 - TQString m; - for (uint i = 0; i < borderStyles.count(); i++) - m += TQString("%1 ").arg((*borderStyles.at(i)).width()); - kdDebug(6040) << m << endl; -#endif - TQValueListIterator<CollapsedBorderValue> it = borderStyles.begin(); - TQValueListIterator<CollapsedBorderValue> end = borderStyles.end(); - for (; it != end; ++it) { - m_currentBorder = &*it; - for (RenderObject *child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableSection()) - child->paint(pI, _tx, _ty); - } - } - m_currentBorder = 0; - } - - pI.phase = oldphase; -#ifdef BOX_DEBUG - outlineBox(p, _tx, _ty, "blue"); -#endif -} - -void RenderTable::paintBoxDecorations(PaintInfo &pI, int _tx, int _ty) -{ - int w = width(); - int h = height(); - - // Account for the caption. - if (tCaption) { - int captionHeight = (tCaption->height() + tCaption->marginBottom() + tCaption->marginTop()); - h -= captionHeight; - if (tCaption->style()->captionSide() != CAPBOTTOM) - _ty += captionHeight; - } - - int my = kMax(_ty,pI.r.y()); - int mh; - if (_ty<pI.r.y()) - mh= kMax(0,h-(pI.r.y()-_ty)); - else - mh = kMin(pI.r.height(),h); - - paintBackground(pI.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h); - - if (style()->hasBorder() && !collapseBorders()) - paintBorder(pI.p, _tx, _ty, w, h, style()); -} - -void RenderTable::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - if ( needSectionRecalc ) - recalcSections(); - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(Table " << this << ")::calcMinMaxWidth()" << endl; -#endif - - tableLayout->calcMinMaxWidth(); - - if (tCaption) { - tCaption->calcWidth(); - if (tCaption->marginLeft()+tCaption->marginRight()+tCaption->minWidth() > m_minWidth) - m_minWidth = tCaption->marginLeft()+tCaption->marginRight()+tCaption->minWidth(); - } - - setMinMaxKnown(); -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << " END: (Table " << this << ")::calcMinMaxWidth() min = " << m_minWidth << " max = " << m_maxWidth << endl; -#endif -} - -void RenderTable::close() -{ -// kdDebug( 6040 ) << "RenderTable::close()" << endl; - setNeedsLayoutAndMinMaxRecalc(); -} - -void RenderTable::splitColumn( int pos, int firstSpan ) -{ - // we need to add a new columnStruct - int oldSize = columns.size(); - columns.resize( oldSize + 1 ); - int oldSpan = columns[pos].span; -// tqDebug("splitColumn( %d,%d ), oldSize=%d, oldSpan=%d", pos, firstSpan, oldSize, oldSpan ); - KHTMLAssert( oldSpan > firstSpan ); - columns[pos].span = firstSpan; - memmove( columns.data()+pos+1, columns.data()+pos, (oldSize-pos)*sizeof(ColumnStruct) ); - columns[pos+1].span = oldSpan - firstSpan; - - // change width of all rows. - RenderObject *child = firstChild(); - while ( child ) { - if ( child->isTableSection() ) { - RenderTableSection *section = static_cast<RenderTableSection *>(child); - int size = section->grid.size(); - int row = 0; - if ( section->cCol > pos ) - section->cCol++; - while ( row < size ) { - section->grid[row].row->resize( oldSize+1 ); - RenderTableSection::Row &r = *section->grid[row].row; - memmove( r.data()+pos+1, r.data()+pos, (oldSize-pos)*sizeof( RenderTableCell * ) ); -// tqDebug("moving from %d to %d, num=%d", pos, pos+1, (oldSize-pos-1) ); - r[pos+1] = r[pos] ? (RenderTableCell *)-1 : 0; - row++; - } - } - child = child->nextSibling(); - } - columnPos.resize( numEffCols()+1 ); - setNeedsLayoutAndMinMaxRecalc(); -} - -void RenderTable::appendColumn( int span ) -{ - // easy case. - int pos = columns.size(); -// tqDebug("appendColumn( %d ), size=%d", span, pos ); - int newSize = pos + 1; - columns.resize( newSize ); - columns[pos].span = span; - //tqDebug("appending column at %d, span %d", pos, span ); - - // change width of all rows. - RenderObject *child = firstChild(); - while ( child ) { - if ( child->isTableSection() ) { - RenderTableSection *section = static_cast<RenderTableSection *>(child); - int size = section->grid.size(); - int row = 0; - while ( row < size ) { - section->grid[row].row->resize( newSize ); - section->cellAt( row, pos ) = 0; - row++; - } - - } - child = child->nextSibling(); - } - columnPos.resize( numEffCols()+1 ); - setNeedsLayoutAndMinMaxRecalc(); -} - -RenderTableCol *RenderTable::colElement( int col ) { - if ( !has_col_elems ) - return 0; - RenderObject *child = firstChild(); - int cCol = 0; - while ( child ) { - if ( child->isTableCol() ) { - RenderTableCol *colElem = static_cast<RenderTableCol *>(child); - int span = colElem->span(); - if ( !colElem->firstChild() ) { - cCol += span; - if ( cCol > col ) - return colElem; - } - - RenderObject *next = child->firstChild(); - if ( !next ) - next = child->nextSibling(); - if ( !next && child->parent()->isTableCol() ) - next = child->parent()->nextSibling(); - child = next; - } else if (child == tCaption) { - child = child->nextSibling(); - } else - break; - } - return 0; -} - -void RenderTable::recalcSections() -{ - tCaption = 0; - head = foot = firstBody = 0; - has_col_elems = false; - - RenderObject *child = firstChild(); - // We need to get valid pointers to caption, head, foot and firstbody again - while ( child ) { - switch(child->style()->display()) { - case TABLE_CAPTION: - if ( !tCaption && child->isRenderBlock() ) { - tCaption = static_cast<RenderBlock*>(child); - tCaption->setNeedsLayout(true); - } - break; - case TABLE_COLUMN: - case TABLE_COLUMN_GROUP: - has_col_elems = true; - break; - case TABLE_HEADER_GROUP: - if (child->isTableSection()) { - RenderTableSection *section = static_cast<RenderTableSection *>(child); - if (!head) - head = section; - else if (!firstBody) - firstBody = section; - if (section->needCellRecalc) - section->recalcCells(); - } - break; - case TABLE_FOOTER_GROUP: - if (child->isTableSection()) { - RenderTableSection *section = static_cast<RenderTableSection *>(child); - if (!foot) - foot = section; - else if (!firstBody) - firstBody = section; - if (section->needCellRecalc) - section->recalcCells(); - } - break; - case TABLE_ROW_GROUP: - if (child->isTableSection()) { - RenderTableSection *section = static_cast<RenderTableSection *>(child); - if (!firstBody) - firstBody = section; - if (section->needCellRecalc) - section->recalcCells(); - } - break; - default: - break; - } - child = child->nextSibling(); - } - needSectionRecalc = false; - setNeedsLayout(true); -} - -RenderObject* RenderTable::removeChildNode(RenderObject* child) -{ - setNeedSectionRecalc(); - return RenderContainer::removeChildNode( child ); -} - -int RenderTable::borderLeft() const -{ - if (collapseBorders()) { - // FIXME: For strict mode, returning 0 is correct, since the table border half spills into the margin, - // but I'm working to get this changed. For now, follow the spec. - return 0; - } - return RenderBlock::borderLeft(); -} - -int RenderTable::borderRight() const -{ - if (collapseBorders()) { - // FIXME: For strict mode, returning 0 is correct, since the table border half spills into the margin, - // but I'm working to get this changed. For now, follow the spec. - return 0; - } - return RenderBlock::borderRight(); -} - -int RenderTable::borderTop() const -{ - if (collapseBorders()) { - // FIXME: For strict mode, returning 0 is correct, since the table border half spills into the margin, - // but I'm working to get this changed. For now, follow the spec. - return 0; - } - return RenderBlock::borderTop(); -} - -int RenderTable::borderBottom() const -{ - if (collapseBorders()) { - // FIXME: For strict mode, returning 0 is correct, since the table border half spills into the margin, - // but I'm working to get this changed. For now, follow the spec. - return 0; - } - return RenderBlock::borderBottom(); -} - -RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const -{ - if (section == head) - return 0; - RenderObject *prevSection = (section == foot ? lastChild() : const_cast<RenderTableSection *>(section))->previousSibling(); - while (prevSection) { - if (prevSection->isTableSection() && prevSection != head && prevSection != foot && (!skipEmptySections || static_cast<RenderTableSection*>(prevSection)->numRows())) - break; - prevSection = prevSection->previousSibling(); - } - if (!prevSection && head && (!skipEmptySections || head->numRows())) - prevSection = head; - return static_cast<RenderTableSection*>(prevSection); -} - -RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const -{ - if (section == foot) - return 0; - RenderObject *nextSection = (section == head ? firstChild() : const_cast<RenderTableSection *>(section))->nextSibling(); - while (nextSection) { - if (nextSection->isTableSection() && nextSection != head && nextSection != foot && (!skipEmptySections || static_cast<RenderTableSection*>(nextSection)->numRows())) - break; - nextSection = nextSection->nextSibling(); - } - if (!nextSection && foot && (!skipEmptySections || foot->numRows())) - nextSection = foot; - return static_cast<RenderTableSection*>(nextSection); -} - -RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const -{ - // Find the section and row to look in - int r = cell->row(); - RenderTableSection* section = 0; - int rAbove = 0; - if (r > 0) { - // cell is not in the first row, so use the above row in its own section - section = cell->section(); - rAbove = r-1; - } else { - section = sectionAbove(cell->section(), true); - if (section) - rAbove = section->numRows() - 1; - } - - // Look up the cell in the section's grid, which requires effective col index - if (section) { - int effCol = colToEffCol(cell->col()); - RenderTableCell* aboveCell; - // If we hit a span back up to a real cell. - do { - aboveCell = section->cellAt(rAbove, effCol); - effCol--; - } while (aboveCell == (RenderTableCell *)-1 && effCol >=0); - return (aboveCell == (RenderTableCell *)-1) ? 0 : aboveCell; - } else { - return 0; - } -} - -RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const -{ - // Find the section and row to look in - int r = cell->row() + cell->rowSpan() - 1; - RenderTableSection* section = 0; - int rBelow = 0; - if (r < cell->section()->numRows()-1) { - // The cell is not in the last row, so use the next row in the section. - section = cell->section(); - rBelow= r+1; - } else { - section = sectionBelow(cell->section(), true); - if (section) - rBelow = 0; - } - - // Look up the cell in the section's grid, which requires effective col index - if (section) { - int effCol = colToEffCol(cell->col()); - RenderTableCell* belowCell; - // If we hit a colspan back up to a real cell. - do { - belowCell = section->cellAt(rBelow, effCol); - effCol--; - } while (belowCell == (RenderTableCell *)-1 && effCol >=0); - return (belowCell == (RenderTableCell *)-1) ? 0 : belowCell; - } else { - return 0; - } -} - -RenderTableCell* RenderTable::cellLeft(const RenderTableCell* cell) const -{ - RenderTableSection* section = cell->section(); - int effCol = colToEffCol(cell->col()); - if (effCol == 0) - return 0; - - // If we hit a colspan back up to a real cell. - RenderTableCell* prevCell; - do { - prevCell = section->cellAt(cell->row(), effCol-1); - effCol--; - } while (prevCell == (RenderTableCell *)-1 && effCol >=0); - return (prevCell == (RenderTableCell *)-1) ? 0 : prevCell; -} - -RenderTableCell* RenderTable::cellRight(const RenderTableCell* cell) const -{ - int effCol = colToEffCol(cell->col()+cell->colSpan()); - if (effCol >= numEffCols()) - return 0; - RenderTableCell* result = cell->section()->cellAt(cell->row(), effCol); - return (result == (RenderTableCell*)-1) ? 0 : result; -} - -#ifdef ENABLE_DUMP -void RenderTable::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderBlock::dump(stream, ind); - - if (tCaption) - stream << " tCaption"; - if (head) - stream << " head"; - if (foot) - stream << " foot"; - - stream << " [cspans:"; - for ( unsigned int i = 0; i < columns.size(); i++ ) - stream << " " << columns[i].span; - stream << "]"; -} - -#endif - -FindSelectionResult RenderTable::checkSelectionPoint( int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int & offset, SelPointState &state ) -{ - int off = offset; - DOM::NodeImpl* nod = node; - - FindSelectionResult pos; - TableSectionIterator it(this); - for (; *it; ++it) { - pos = (*it)->checkSelectionPoint(_x, _y, _tx + m_x, _ty + m_y, nod, off, state); - switch(pos) { - case SelectionPointBeforeInLine: - case SelectionPointInside: - //kdDebug(6030) << "RenderTable::checkSelectionPoint " << this << " returning SelectionPointInside offset=" << offset << endl; - node = nod; - offset = off; - return SelectionPointInside; - case SelectionPointBefore: - //x,y is before this element -> stop here - if ( state.m_lastNode ) { - node = state.m_lastNode; - offset = state.m_lastOffset; - //kdDebug(6030) << "RenderTable::checkSelectionPoint " << this << " before this child " - // << node << "-> returning SelectionPointInside, offset=" << offset << endl; - return SelectionPointInside; - } else { - node = nod; - offset = off; - //kdDebug(6030) << "RenderTable::checkSelectionPoint " << this << " before us -> returning SelectionPointBefore " << node << "/" << offset << endl; - return SelectionPointBefore; - } - break; - case SelectionPointAfter: - if (state.m_afterInLine) break; - // fall through - case SelectionPointAfterInLine: - if (pos == SelectionPointAfterInLine) state.m_afterInLine = true; - //kdDebug(6030) << "RenderTable::checkSelectionPoint: selection after: " << nod << " offset: " << off << " afterInLine: " << state.m_afterInLine << endl; - state.m_lastNode = nod; - state.m_lastOffset = off; - // No "return" here, obviously. We must keep looking into the children. - break; - } - } - // If we are after the last child, return lastNode/lastOffset - // But lastNode can be 0L if there is no child, for instance. - if ( state.m_lastNode ) - { - node = state.m_lastNode; - offset = state.m_lastOffset; - } - // Fallback - return SelectionPointAfter; -} - -// -------------------------------------------------------------------------- - -RenderTableSection::RenderTableSection(DOM::NodeImpl* node) - : RenderBox(node) -{ - // init RenderObject attributes - setInline(false); // our object is not Inline - cCol = 0; - cRow = -1; - needCellRecalc = false; -} - -RenderTableSection::~RenderTableSection() -{ - clearGrid(); -} - -void RenderTableSection::detach() -{ - // recalc cell info because RenderTable has unguarded pointers - // stored that point to this RenderTableSection. - if (table()) - table()->setNeedSectionRecalc(); - - RenderBox::detach(); -} - -void RenderTableSection::setStyle(RenderStyle* _style) -{ - // we don't allow changing this one - if (style()) - _style->setDisplay(style()->display()); - else if (_style->display() != TABLE_FOOTER_GROUP && _style->display() != TABLE_HEADER_GROUP) - _style->setDisplay(TABLE_ROW_GROUP); - - RenderBox::setStyle(_style); -} - -void RenderTableSection::addChild(RenderObject *child, RenderObject *beforeChild) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(TableSection)::addChild( " << child->renderName() << ", beforeChild=" << - (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; -#endif - if ( !child->isTableRow() ) { - // TBODY > FORM quirk (???) - if (child->element() && child->element()->isHTMLElement() && child->element()->id() == ID_FORM && - static_cast<HTMLFormElementImpl*>(child->element())->isMalformed()) - { - RenderContainer::addChild(child, beforeChild); - return; - } - - RenderObject* last = beforeChild; - if (!last) - last = lastChild(); - if (last && last->isAnonymous()) { - last->addChild(child); - return; - } - - // If beforeChild is inside an anonymous cell/row, insert into the cell or into - // the anonymous row containing it, if there is one. - RenderObject* lastBox = last; - while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow()) - lastBox = lastBox->parent(); - if (lastBox && lastBox->isAnonymous()) { - lastBox->addChild(child, beforeChild); - return; - } - - RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table */); - RenderStyle* newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE_ROW); - row->setStyle(newStyle); - addChild(row, beforeChild); - row->addChild(child); - return; - } - - if (beforeChild) - setNeedCellRecalc(); - - cRow++; - cCol = 0; - - ensureRows( cRow+1 ); - KHTMLAssert( child->isTableRow() ); - grid[cRow].rowRenderer = static_cast<RenderTableRow*>(child); - - if (!beforeChild) { - grid[cRow].height = child->style()->height(); - if ( grid[cRow].height.isRelative() ) - grid[cRow].height = Length(); - } - - - RenderContainer::addChild(child,beforeChild); -} - -void RenderTableSection::ensureRows( int numRows ) -{ - int nRows = grid.size(); - int nCols = table()->numEffCols(); - if ( numRows > nRows ) { - grid.resize( numRows ); - for ( int r = nRows; r < numRows; r++ ) { - grid[r].row = new Row( nCols ); - grid[r].row->fill( 0 ); - grid[r].rowRenderer = 0; - grid[r].baseLine = 0; - grid[r].height = Length(); - } - } - -} - -void RenderTableSection::addCell( RenderTableCell *cell, RenderTableRow *row ) -{ - int rSpan = cell->rowSpan(); - int cSpan = cell->colSpan(); - TQMemArray<RenderTable::ColumnStruct> &columns = table()->columns; - int nCols = columns.size(); - - // ### mozilla still seems to do the old HTML way, even for strict DTD - // (see the annotation on table cell layouting in the CSS specs and the testcase below: - // <TABLE border> - // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4 - // <TR><TD colspan="2">5 - // </TABLE> - while ( cCol < nCols && cellAt( cRow, cCol ) ) - cCol++; - -// tqDebug("adding cell at %d/%d span=(%d/%d)", cRow, cCol, rSpan, cSpan ); - - if ( rSpan == 1 ) { - // we ignore height settings on rowspan cells - Length height = cell->style()->height(); - if ( height.value() > 0 || (height.isRelative() && height.value() >= 0) ) { - Length cRowHeight = grid[cRow].height; - switch( height.type() ) { - case Percent: - if ( !cRowHeight.isPercent() || - (cRowHeight.isPercent() && cRowHeight.value() < height.value() ) ) - grid[cRow].height = height; - break; - case Fixed: - if ( cRowHeight.type() < Percent || - ( cRowHeight.isFixed() && cRowHeight.value() < height.value() ) ) - grid[cRow].height = height; - break; - case Relative: -#if 0 - // we treat this as variable. This is correct according to HTML4, as it only specifies length for the height. - if ( cRowHeight.type == Variable || - ( cRowHeight.type == Relative && cRowHeight.value < height.value ) ) - grid[cRow].height = height; - break; -#endif - default: - break; - } - } - } - - // make sure we have enough rows - ensureRows( cRow + rSpan ); - - grid[cRow].rowRenderer = row; - - int col = cCol; - // tell the cell where it is - RenderTableCell *set = cell; - while ( cSpan ) { - int currentSpan; - if ( cCol >= nCols ) { - table()->appendColumn( cSpan ); - currentSpan = cSpan; - } else { - if ( cSpan < columns[cCol].span ) - table()->splitColumn( cCol, cSpan ); - currentSpan = columns[cCol].span; - } - int r = 0; - while ( r < rSpan ) { - if ( !cellAt( cRow + r, cCol ) ) { -// tqDebug(" adding cell at %d, %d", cRow + r, cCol ); - cellAt( cRow + r, cCol ) = set; - } - r++; - } - cCol++; - cSpan -= currentSpan; - set = (RenderTableCell *)-1; - } - if ( cell ) { - cell->setRow( cRow ); - cell->setCol( table()->effColToCol( col ) ); - } -} - - - -void RenderTableSection::setCellWidths() -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(Table, this=0x" << this << ")::setCellWidths()" << endl; -#endif - TQMemArray<int> &columnPos = table()->columnPos; - - int rows = grid.size(); - for ( int i = 0; i < rows; i++ ) { - Row &row = *grid[i].row; - int cols = row.size(); - for ( int j = 0; j < cols; j++ ) { - RenderTableCell *cell = row[j]; -// tqDebug("cell[%d,%d] = %p", i, j, cell ); - if ( !cell || cell == (RenderTableCell *)-1 ) - continue; - int endCol = j; - int cspan = cell->colSpan(); - while ( cspan && endCol < cols ) { - cspan -= table()->columns[endCol].span; - endCol++; - } - int w = columnPos[endCol] - columnPos[j] - table()->borderHSpacing(); -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "setting width of cell " << cell << " " << cell->row() << "/" << cell->col() << " to " << w << " colspan=" << cell->colSpan() << " start=" << j << " end=" << endCol << endl; -#endif - int oldWidth = cell->width(); - if ( w != oldWidth ) { - cell->setNeedsLayout(true); - cell->setWidth( w ); - } - } - } -} - -short RenderTableSection::width() const -{ - return table()->width(); -} - - -void RenderTableSection::calcRowHeight() -{ - int indx; - RenderTableCell *cell; - - int totalRows = grid.size(); - int vspacing = table()->borderVSpacing(); - - rowPos.resize( totalRows + 1 ); - rowPos[0] = vspacing + borderTop(); - - for ( int r = 0; r < totalRows; r++ ) { - rowPos[r+1] = 0; - - int baseline=0; - int bdesc = 0; -// tqDebug("height of row %d is %d/%d", r, grid[r].height.value, grid[r].height.type ); - int ch = grid[r].height.minWidth( 0 ); - int pos = rowPos[r] + ch + (grid[r].rowRenderer ? vspacing : 0); - - if ( pos > rowPos[r+1] ) - rowPos[r+1] = pos; - - Row *row = grid[r].row; - int totalCols = row->size(); - int totalRows = grid.size(); - bool pagedMode = canvas()->pagedMode(); - - grid[r].needFlex = false; - - for ( int c = 0; c < totalCols; c++ ) { - cell = cellAt(r, c); - if ( !cell || cell == (RenderTableCell *)-1 ) - continue; - if ( r < totalRows - 1 && cellAt(r+1, c) == cell ) - continue; - - if ( ( indx = r - cell->rowSpan() + 1 ) < 0 ) - indx = 0; - - if (cell->cellPercentageHeight() != -1) { - cell->setCellPercentageHeight(-1); - cell->setChildNeedsLayout(true, false); - if (cell->hasFlexedAnonymous()) { - for (RenderObject* o = cell->firstChild(); o ; o = o->nextSibling()) - if (o->isAnonymousBlock()) - o->setChildNeedsLayout(true, false); - } - if (pagedMode) cell->setNeedsLayout(true); - cell->layoutIfNeeded(); - } - - ch = cell->style()->height().width(0); - if ( cell->height() > ch) - ch = cell->height(); - - if (!cell->style()->height().isVariable()) - grid[r].needFlex = true; - - pos = rowPos[indx] + ch + (grid[r].rowRenderer ? vspacing : 0); - - if ( pos > rowPos[r+1] ) - rowPos[r+1] = pos; - - // find out the baseline - EVerticalAlign va = cell->style()->verticalAlign(); - if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP - || va == SUPER || va == SUB) - { - int b=cell->baselinePosition(); - if (b > cell->borderTop() + cell->paddingTop()) { - if (b>baseline) - baseline=b; - - int td = rowPos[ indx ] + ch - b; - if (td>bdesc) - bdesc = td; - } - } - } - - //do we have baseline aligned elements? - if (baseline) { - // increase rowheight if baseline requires - int bRowPos = baseline + bdesc + (grid[r].rowRenderer ? vspacing : 0); - if (rowPos[r+1]<bRowPos) - rowPos[r+1]=bRowPos; - - grid[r].baseLine = baseline; - } - - if ( rowPos[r+1] < rowPos[r] ) - rowPos[r+1] = rowPos[r]; -// tqDebug("rowpos(%d)=%d", r, rowPos[r] ); - } -} - -int RenderTableSection::layoutRows( int toAdd ) -{ - int rHeight; - int rindx; - int totalRows = grid.size(); - int hspacing = table()->borderHSpacing(); - int vspacing = table()->borderVSpacing(); - - // Set the width of our section now. The rows will also be this width. - m_width = table()->contentWidth(); - - if (markedForRepaint()) { - repaintDuringLayout(); - setMarkedForRepaint(false); - } - - if (toAdd && totalRows && (rowPos[totalRows] || !nextSibling())) { - - int totalHeight = rowPos[totalRows] + toAdd; -// tqDebug("layoutRows: totalHeight = %d", totalHeight ); - - int dh = toAdd; - int totalPercent = 0; - int numVariable = 0; - for ( int r = 0; r < totalRows; r++ ) { - if ( grid[r].height.isVariable() && !emptyRow(r)) - numVariable++; - else if ( grid[r].height.isPercent() ) - totalPercent += grid[r].height.value(); - } - if ( totalPercent ) { -// tqDebug("distributing %d over percent rows totalPercent=%d", dh, totalPercent ); - // try to satisfy percent - int add = 0; - if ( totalPercent > 100 ) - totalPercent = 100; - int rh = rowPos[1]-rowPos[0]; - for ( int r = 0; r < totalRows; r++ ) { - if ( totalPercent > 0 && grid[r].height.isPercent() ) { - int toAdd = kMin( dh, (totalHeight * grid[r].height.value() / 100)-rh ); - // If toAdd is negative, then we don't want to shrink the row (this bug - // affected Outlook Web Access). - toAdd = kMax(0, toAdd); - add += toAdd; - dh -= toAdd; - totalPercent -= grid[r].height.value(); -// tqDebug( "adding %d to row %d", toAdd, r ); - } - if ( r < totalRows-1 ) - rh = rowPos[r+2] - rowPos[r+1]; - rowPos[r+1] += add; - } - } - if ( numVariable ) { - // distribute over non-empty variable rows -// tqDebug("distributing %d over variable rows numVariable=%d", dh, numVariable ); - int add = 0; - int toAdd = dh/numVariable; - for ( int r = 0; r < totalRows; r++ ) { - if ( grid[r].height.isVariable() && !emptyRow(r)) { - add += toAdd; - } - rowPos[r+1] += add; - } - dh -= add; - } - if (dh>0 && rowPos[totalRows]) { - // if some left overs, distribute weighted. - int tot=rowPos[totalRows]; - int add=0; - int prev=rowPos[0]; - for ( int r = 0; r < totalRows; r++ ) { - //weight with the original height - add+=dh*(rowPos[r+1]-prev)/tot; - prev=rowPos[r+1]; - rowPos[r+1]+=add; - } - dh -= add; - } - if (dh > totalRows) { - // distribute to tables with all empty rows - int add=0; - int toAdd = dh/totalRows; - for ( int r = 0; r < totalRows; r++ ) { - add += toAdd; - rowPos[r+1] += add; - } - dh -= add; - } - // Finally distribute round-off values - if (dh > 0) { - // There is not enough for every row - int add=0; - for ( int r = 0; r < totalRows; r++ ) { - if (add < dh) add++; - rowPos[r+1] += add; - } - dh -= add; - } - assert (dh == 0); - } - - int leftOffset = borderLeft() + hspacing; - - int nEffCols = table()->numEffCols(); - for ( int r = 0; r < totalRows; r++ ) - { - Row *row = grid[r].row; - int totalCols = row->size(); - -#ifdef APPLE_CHANGES - // in WC, rows and cells share the same coordinate space, so that rows can have - // dimensions in the layer system. This is of dubious value, and a heavy maintenance burden - // (RenderObject's coordinates can't be used deterministically anymore) so we'll consider other options. - - // Set the row's x/y position and width/height. - if (grid[r].rowRenderer) { - grid[r].rowRenderer->setPos(0, rowPos[r]); - grid[r].rowRenderer->setWidth(m_width); - grid[r].rowRenderer->setHeight(rowPos[r+1] - rowPos[r] - vspacing); - } -#endif - - for ( int c = 0; c < nEffCols; c++ ) - { - RenderTableCell *cell = cellAt(r, c); - if (!cell || cell == (RenderTableCell *)-1 ) - continue; - if ( r < totalRows - 1 && cell == cellAt(r+1, c) ) - continue; - - if ( ( rindx = r-cell->rowSpan()+1 ) < 0 ) - rindx = 0; - - rHeight = rowPos[r+1] - rowPos[rindx] - vspacing; - - // Force percent height children to lay themselves out again. - // This will cause, e.g., textareas to grow to - // fill the area. FIXME: <div>s and blocks still don't - // work right. We'll need to have an efficient way of - // invalidating all percent height objects in a render subtree. - // For now, we just handle immediate children. -dwh - - bool flexAllChildren = grid[r].needFlex || (!table()->style()->height().isVariable() && rHeight != cell->height()); - cell->setHasFlexedAnonymous(false); - if ( flexAllChildren && flexCellChildren(cell) ) { - cell->setCellPercentageHeight(kMax(0, - rHeight - cell->borderTop() - cell->paddingTop() - - cell->borderBottom() - cell->paddingBottom())); - cell->layoutIfNeeded(); - - } - { -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << "setting position " << r << "/" << c << ": " - << table()->columnPos[c] /*+ padding */ << "/" << rowPos[rindx] << " height=" << rHeight<< endl; -#endif - - EVerticalAlign va = cell->style()->verticalAlign(); - int te=0; - switch (va) - { - case SUB: - case SUPER: - case TEXT_TOP: - case TEXT_BOTTOM: - case BASELINE: - te = getBaseline(r) - cell->baselinePosition() ; - break; - case TOP: - te = 0; - break; - case MIDDLE: - te = (rHeight - cell->height())/2; - break; - case BOTTOM: - te = rHeight - cell->height(); - break; - default: - break; - } - te = kMax( 0, te ); -#ifdef DEBUG_LAYOUT - // kdDebug( 6040 ) << "CELL " << cell << " te=" << te << ", be=" << rHeight - cell->height() - te << ", rHeight=" << rHeight << ", valign=" << va << endl; -#endif - cell->setCellTopExtra( te ); - cell->setCellBottomExtra( rHeight - cell->height() - te); - } - if (style()->direction()==RTL) { - cell->setPos( - table()->columnPos[(int)totalCols] - - table()->columnPos[table()->colToEffCol(cell->col()+cell->colSpan())] + - leftOffset, - rowPos[rindx] ); - } else { - cell->setPos( table()->columnPos[c] + leftOffset, rowPos[rindx] ); - } - } - } - - m_height = rowPos[totalRows]; - return m_height; -} - -bool RenderTableSection::flexCellChildren(RenderObject* p) const -{ - if (!p) - return false; - RenderObject* o = p->firstChild(); - bool didFlex = false; - while (o) { - if (!o->isText() && o->style()->height().isPercent()) { - if (o->isWidget()) { - // cancel resizes from transitory relayouts - static_cast<RenderWidget *>(o)->cancelPendingResize(); - } - o->setNeedsLayout(true, false); - p->setChildNeedsLayout(true, false); - didFlex = true; - } else if (o->isAnonymousBlock() && flexCellChildren( o )) { - p->setChildNeedsLayout(true, false); - if (p->isTableCell()) - static_cast<RenderTableCell*>(p)->setHasFlexedAnonymous(); - didFlex = true; - } - o = o->nextSibling(); - } - return didFlex; -} - -inline static RenderTableRow *firstTableRow(RenderObject *row) -{ - while (row && !row->isTableRow()) - row = row->nextSibling(); - return static_cast<RenderTableRow *>(row); -} - -inline static RenderTableRow *nextTableRow(RenderObject *row) -{ - row = row ? row->nextSibling() : row; - while (row && !row->isTableRow()) - row = row->nextSibling(); - return static_cast<RenderTableRow *>(row); -} - -int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return bottom; - - for (RenderObject *row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling()) - if (cell->isTableCell()) { - int bp = cell->yPos() + cell->lowestPosition(false); - bottom = kMax(bottom, bp); - } - } - - return bottom; -} - -int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return right; - - for (RenderObject *row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling()) - if (cell->isTableCell()) { - int rp = cell->xPos() + cell->rightmostPosition(false); - right = kMax(right, rp); - } - } - - return right; -} - -int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return left; - - for (RenderObject *row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling()) - if (cell->isTableCell()) { - int lp = cell->xPos() + cell->leftmostPosition(false); - left = kMin(left, lp); - } - } - - return left; -} - -int RenderTableSection::highestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - int top = RenderBox::highestPosition(includeOverflowInterior, includeSelf); - if (!includeOverflowInterior && hasOverflowClip()) - return top; - - for (RenderObject *row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling()) - if (cell->isTableCell()) { - int hp = cell->yPos() + cell->highestPosition(false); - top = kMin(top, hp); - } - } - - return top; -} - -// Search from first_row to last_row for the row containing y -static unsigned int findRow(unsigned int first_row, unsigned int last_row, - const TQMemArray<int> &rowPos, int y) -{ - unsigned int under = first_row; - unsigned int over = last_row; - int offset = (over - under)/2; - while (over-under > 1) { - if (rowPos[under+offset] <= y) - under = under+offset; - else - over = under+offset; - offset = (over - under)/2; - } - - assert(under == first_row || rowPos[under] <= y); - assert(over == last_row || rowPos[over] > y); - - return under; -} - -static void findRowCover(unsigned int &startrow, unsigned int &endrow, - const TQMemArray<int> &rowPos, - int min_y, int max_y) -{ - assert(max_y >= min_y); - unsigned int totalRows = endrow; - - unsigned int index = 0; - // Initial binary search boost: - if (totalRows >= 8) { - int offset = (endrow - startrow)/2; - while (endrow - startrow > 1) { - index = startrow+offset; - if (rowPos[index] <= min_y ) - // index is below both min_y and max_y - startrow = index; - else - if (rowPos[index] > max_y) - // index is above both min_y and max_y - endrow = index; - else - // index is within the selection - break; - offset = (endrow - startrow)/2; - } - } - - // Binary search for startrow - startrow = findRow(startrow, endrow, rowPos, min_y); - // Binary search for endrow - endrow = findRow(startrow, endrow, rowPos, max_y) + 1; - if (endrow > totalRows) endrow = totalRows; -} - -void RenderTableSection::paint( PaintInfo& pI, int tx, int ty ) -{ - unsigned int totalRows = grid.size(); - unsigned int totalCols = table()->columns.size(); - - tx += m_x; - ty += m_y; - - if (pI.phase == PaintActionOutline) - paintOutline(pI.p, tx, ty, width(), height(), style()); - - CollapsedBorderValue *cbs = table()->currentBorderStyle(); - int cbsw2 = cbs ? cbs->width()/2 : 0; - int cbsw21 = cbs ? (cbs->width()+1)/2 : 0; - - int x = pI.r.x(), y = pI.r.y(), w = pI.r.width(), h = pI.r.height(); - // check which rows and cols are visible and only paint these - int os = 2*maximalOutlineSize(pI.phase); - unsigned int startrow = 0; - unsigned int endrow = totalRows; - findRowCover(startrow, endrow, rowPos, y - os - ty - kMax(cbsw21, os), y + h + os - ty + kMax(cbsw2, os)); - - // A binary search is probably not worthwhile for coloumns - unsigned int startcol = 0; - unsigned int endcol = totalCols; - if ( style()->direction() == LTR ) { - for ( ; startcol < totalCols; startcol++ ) { - if ( tx + table()->columnPos[startcol+1] + kMax(cbsw21, os) > x - os ) - break; - } - for ( ; endcol > 0; endcol-- ) { - if ( tx + table()->columnPos[endcol-1] - kMax(cbsw2, os) < x + w + os ) - break; - } - } - if ( startcol < endcol ) { - // draw the cells - for ( unsigned int r = startrow; r < endrow; r++ ) { - // paint the row - if (grid[r].rowRenderer) { - int height = rowPos[r+1] - rowPos[r] - table()->borderVSpacing(); - grid[r].rowRenderer->paintRow(pI, tx, ty + rowPos[r], width(), height); - } - - unsigned int c = startcol; - Row *row = grid[r].row; - Row *nextrow = (r < endrow - 1) ? grid[r+1].row : 0; - // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it - while ( c && (*row)[c] == (RenderTableCell *)-1 ) - c--; - for ( ; c < endcol; c++ ) { - RenderTableCell *cell = (*row)[c]; - if ( !cell || cell == (RenderTableCell *)-1 || nextrow && (*nextrow)[c] == cell ) - continue; -#ifdef TABLE_PRINT - kdDebug( 6040 ) << "painting cell " << r << "/" << c << endl; -#endif - if (pI.phase == PaintActionElementBackground || pI.phase == PaintActionChildBackground) { - // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of - // the column group, column, row group, row, and then the cell. - RenderObject* col = table()->colElement(c); - RenderObject* colGroup = 0; - if (col) { - RenderStyle *style = col->parent()->style(); - if (style->display() == TABLE_COLUMN_GROUP) - colGroup = col->parent(); - } - RenderObject* row = cell->parent(); - - // ### - // Column groups and columns first. - // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in - // the stack, since we have already opened a transparency layer (potentially) for the table row group. - // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the - // cell. - cell->paintBackgroundsBehindCell(pI, tx, ty, colGroup); - cell->paintBackgroundsBehindCell(pI, tx, ty, col); - - // Paint the row group next. - cell->paintBackgroundsBehindCell(pI, tx, ty, this); - - // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for - // painting the row background for the cell. - if (!row->layer()) - cell->paintBackgroundsBehindCell(pI, tx, ty, row); - } - - if ((!cell->layer() && !cell->parent()->layer()) || pI.phase == PaintActionCollapsedTableBorders) - cell->paint(pI, tx, ty); - } - } - } -} - -void RenderTableSection::recalcCells() -{ - cCol = 0; - cRow = -1; - clearGrid(); - grid.resize( 0 ); - - for (RenderObject *row = firstChild(); row; row = row->nextSibling()) { - if (row->isTableRow()) { - cRow++; - cCol = 0; - ensureRows( cRow+1 ); - grid[cRow].rowRenderer = static_cast<RenderTableRow*>(row); - - for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling()) - if (cell->isTableCell()) - addCell( static_cast<RenderTableCell *>(cell), static_cast<RenderTableRow *>(row) ); - } - } - needCellRecalc = false; - setNeedsLayout(true); -} - -void RenderTableSection::clearGrid() -{ - int rows = grid.size(); - while ( rows-- ) { - delete grid[rows].row; - } -} - -bool RenderTableSection::emptyRow(int rowNum) { - Row &r = *grid[rowNum].row; - const int s = r.size(); - RenderTableCell *cell; - for(int i=0; i<s; i++) { - cell = r[i]; - if (!cell || cell==(RenderTableCell*)-1) - continue; - return false; - } - return true; -} - -RenderObject* RenderTableSection::removeChildNode(RenderObject* child) -{ - setNeedCellRecalc(); - return RenderContainer::removeChildNode( child ); -} - -bool RenderTableSection::canClear(RenderObject */*child*/, PageBreakLevel level) -{ - // We cannot clear rows yet. - return parent()->canClear(this, level); -} - -void RenderTableSection::addSpaceAt(int pos, int dy) -{ - const int nEffCols = table()->numEffCols(); - const int totalRows = numRows(); - for ( int r = 0; r < totalRows; r++ ) { - if (rowPos[r] >= pos) { - rowPos[r] += dy; - int rindx; - for ( int c = 0; c < nEffCols; c++ ) - { - RenderTableCell *cell = cellAt(r, c); - if (!cell || cell == (RenderTableCell *)-1 ) - continue; - if ( r > 0 && cell == cellAt(r-1, c) ) - continue; - - if ( ( rindx = r-cell->rowSpan()+1 ) < 0 ) - rindx = 0; - - cell->setPos(cell->xPos(), rowPos[r]); - } - } - } - if (rowPos[totalRows] >= pos) - rowPos[totalRows] += dy; - m_height = rowPos[totalRows]; - - setContainsPageBreak(true); -} - - -#ifdef ENABLE_DUMP -void RenderTableSection::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderContainer::dump(stream,ind); - - stream << " grid=(" << grid.size() << "," << table()->numEffCols() << ")"; - for ( unsigned int r = 0; r < grid.size(); r++ ) { - for ( int c = 0; c < table()->numEffCols(); c++ ) { - if ( cellAt( r, c ) && cellAt( r, c ) != (RenderTableCell *)-1 ) - stream << " (" << cellAt( r, c )->row() << "," << cellAt( r, c )->col() << "," - << cellAt(r, c)->rowSpan() << "," << cellAt(r, c)->colSpan() << ") "; - else - stream << " null cell"; - } - } -} -#endif - -static RenderTableCell *seekCell(RenderTableSection *section, int row, int col) -{ - if (row < 0 || col < 0 || row >= section->numRows()) return 0; - // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it - while ( col && section->cellAt( row, col ) == (RenderTableCell *)-1 ) - col--; - - return section->cellAt(row, col); -} - -/** Looks for the first element suitable for text selection, beginning from - * the last. - * @param base search is restricted within this node. This node must have - * a renderer. - * @return the element or @p base if no suitable element found. - */ -static NodeImpl *findLastSelectableNode(NodeImpl *base) -{ - NodeImpl *last = base; - // Look for last text/cdata node that has a renderer, - // or last childless replaced element - while ( last && !(last->renderer() - && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE) - || (last->renderer()->isReplaced() && !last->renderer()->lastChild())))) - { - NodeImpl *next = last->lastChild(); - if ( !next ) next = last->previousSibling(); - while ( last && last != base && !next ) - { - last = last->parentNode(); - if ( last && last != base ) - next = last->previousSibling(); - } - last = next; - } - - return last ? last : base; -} - -FindSelectionResult RenderTableSection::checkSelectionPoint( int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int & offset, SelPointState &state ) -{ - // Table sections need extra treatment for selections. The rows are scanned - // from top to bottom, and within each row, only the cell that matches - // the given position best is descended into. - - unsigned int totalRows = grid.size(); - unsigned int totalCols = table()->columns.size(); - -// absolutePosition(_tx, _ty, false); - - _tx += m_x; - _ty += m_y; - -// bool save_last = false; // true to save last investigated cell - - if (needsLayout() || _y < _ty) return SelectionPointBefore; -// else if (_y >= _ty + height()) save_last = true; - - // Find the row containing the pointer - int row_idx = findRow(0, totalRows, rowPos, _y - _ty); - - int col_idx; - if ( style()->direction() == LTR ) { - for ( col_idx = (int)totalCols - 1; col_idx >= 0; col_idx-- ) { - if ( _tx + table()->columnPos[col_idx] < _x ) - break; - } - if (col_idx < 0) col_idx = 0; - } else { - for ( col_idx = 0; col_idx < (int)totalCols; col_idx++ ) { - if ( _tx + table()->columnPos[col_idx] > _x ) - break; - } - if (col_idx >= (int)totalCols) col_idx = (int)totalCols + 1; - } - - FindSelectionResult pos = SelectionPointBefore; - - RenderTableCell *cell = seekCell(this, row_idx, col_idx); - // ### dunno why cell can be 0, maybe due to weird spans? (LS) - if (cell) { - SelPointState localState; - pos = cell->checkSelectionPoint(_x, _y, _tx, _ty, node, offset, localState); - } - - if (pos != SelectionPointBefore) return pos; - - // store last column of last line - row_idx--; - col_idx = totalCols - 1; - cell = seekCell(this, row_idx, col_idx); - - // end of section? take previous section - RenderTableSection *sec = this; - if (!cell) { - sec = *--TableSectionIterator(sec); - if (!sec) return pos; - - cell = seekCell(sec, sec->grid.size() - 1, col_idx); - if (!cell) return pos; - } - - // take last child of previous cell, and store this one as last node - NodeImpl *element = cell->element(); - if (!element) return SelectionPointBefore; - - element = findLastSelectableNode(element); - - state.m_lastNode = element; - state.m_lastOffset = element->maxOffset(); - return SelectionPointBefore; -} - -// Hit Testing -bool RenderTableSection::nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action, bool inside) -{ - // Table sections cannot ever be hit tested. Effectively they do not exist. - // Just forward to our children always. - tx += m_x; - ty += m_y; - - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - // FIXME: We have to skip over inline flows, since they can show up inside table rows - // at the moment (a demoted inline <form> for example). If we ever implement a - // table-specific hit-test method (which we should do for performance reasons anyway), - // then we can remove this check. - if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, x, y, tx, ty, action, inside)) { - return true; - } - } - - return false; -} - - -// ------------------------------------------------------------------------- - -RenderTableRow::RenderTableRow(DOM::NodeImpl* node) - : RenderContainer(node) -{ - // init RenderObject attributes - setInline(false); // our object is not Inline -} - -RenderObject* RenderTableRow::removeChildNode(RenderObject* child) -{ - RenderTableSection *s = section(); - if (s) - s->setNeedCellRecalc(); - - return RenderContainer::removeChildNode( child ); -} - -void RenderTableRow::detach() -{ - RenderTableSection *s = section(); - if (s) - s->setNeedCellRecalc(); - - RenderContainer::detach(); -} - -void RenderTableRow::setStyle(RenderStyle* newStyle) -{ - if (section() && style() && style()->height() != newStyle->height()) - section()->setNeedCellRecalc(); - - newStyle->setDisplay(TABLE_ROW); - RenderContainer::setStyle(newStyle); -} - -void RenderTableRow::addChild(RenderObject *child, RenderObject *beforeChild) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(TableRow)::addChild( " << child->renderName() << " )" << ", " << - (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; -#endif - - if ( !child->isTableCell() ) { - // TR > FORM quirk (???) - if (child->element() && child->element()->isHTMLElement() && child->element()->id() == ID_FORM && - static_cast<HTMLFormElementImpl*>(child->element())->isMalformed()) - { - RenderContainer::addChild(child, beforeChild); - return; - } - - RenderObject* last = beforeChild; - if (!last) - last = lastChild(); - if (last && last->isAnonymous() && last->isTableCell()) { - last->addChild(child); - return; - } - - // If beforeChild is inside an anonymous cell, insert into the cell. - if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous()) { - last->parent()->addChild(child, beforeChild); - return; - } - - RenderTableCell* cell = new (renderArena()) RenderTableCell(document() /* anonymous object */); - RenderStyle* newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE_CELL); - cell->setStyle(newStyle); - addChild(cell, beforeChild); - cell->addChild(child); - return; - } - - RenderTableCell* cell = static_cast<RenderTableCell*>(child); - - section()->addCell( cell, this ); - - RenderContainer::addChild(cell,beforeChild); - - if ( beforeChild || nextSibling() ) - section()->setNeedCellRecalc(); -} - -void RenderTableRow::layout() -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - - RenderObject *child = firstChild(); - const bool pagedMode = canvas()->pagedMode(); - while( child ) { - if ( child->isTableCell() ) { - RenderTableCell *cell = static_cast<RenderTableCell *>(child); - if (pagedMode) { - cell->setNeedsLayout(true); - int oldHeight = child->height(); - cell->layout(); - if (oldHeight > 0 && child->containsPageBreak() && child->height() != oldHeight) - section()->addSpaceAt(child->yPos()+1, child->height() - oldHeight); - } else - if ( child->needsLayout() ) { - if (markedForRepaint()) - cell->setMarkedForRepaint( true ); - cell->calcVerticalMargins(); - cell->layout(); - cell->setCellTopExtra(0); - cell->setCellBottomExtra(0); - if (child->containsPageBreak()) setContainsPageBreak(true); - } - } - child = child->nextSibling(); - } - setMarkedForRepaint(false); - setNeedsLayout(false); -} - -int RenderTableRow::offsetLeft() const -{ - RenderObject *child = firstChild(); - while (child && !child->isTableCell()) - child = child->nextSibling(); - - if (!child) - return 0; - - return child->offsetLeft(); -} - -int RenderTableRow::offsetTop() const -{ - RenderObject *child = firstChild(); - while (child && !child->isTableCell()) - child = child->nextSibling(); - - if (!child) - return 0; - - return child->offsetTop() - - static_cast<RenderTableCell*>(child)->cellTopExtra(); -} - -int RenderTableRow::offsetHeight() const -{ - RenderObject *child = firstChild(); - while (child && !child->isTableCell()) - child = child->nextSibling(); - - if (!child) - return 0; - - return child->offsetHeight() + - static_cast<RenderTableCell*>(child)->cellTopExtra() + - static_cast<RenderTableCell*>(child)->cellBottomExtra(); -} - -short RenderTableRow::offsetWidth() const -{ - RenderObject *fc = firstChild(); - RenderObject *lc = lastChild(); - while (fc && !fc->isTableCell()) - fc = fc->nextSibling(); - while (lc && !lc->isTableCell()) - lc = lc->previousSibling(); - if (!lc || !fc) - return 0; - - return lc->xPos()+lc->width()-fc->xPos(); -} - -void RenderTableRow::paintRow( PaintInfo& pI, int tx, int ty, int w, int h ) -{ - if (pI.phase == PaintActionOutline) - paintOutline(pI.p, tx, ty, w, h, style()); -} - -void RenderTableRow::paint(PaintInfo& i, int tx, int ty) -{ - KHTMLAssert(layer()); - if (!layer()) - return; - - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableCell()) { - // Paint the row background behind the cell. - if (i.phase == PaintActionElementBackground || i.phase == PaintActionChildBackground) { - RenderTableCell* cell = static_cast<RenderTableCell*>(child); - cell->paintBackgroundsBehindCell(i, tx, ty, this); - } - if (!child->layer()) - child->paint(i, tx, ty); - } - } -} - -// Hit Testing -bool RenderTableRow::nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action, bool inside) -{ - // Table rows cannot ever be hit tested. Effectively they do not exist. - // Just forward to our children always. - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - // FIXME: We have to skip over inline flows, since they can show up inside table rows - // at the moment (a demoted inline <form> for example). If we ever implement a - // table-specific hit-test method (which we should do for performance reasons anyway), - // then we can remove this check. - if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, x, y, tx, ty, action, inside)) { - return true; - } - } - - return false; -} - -// ------------------------------------------------------------------------- - -RenderTableCell::RenderTableCell(DOM::NodeImpl* _node) - : RenderBlock(_node) -{ - _col = -1; - _row = -1; - updateFromElement(); - setShouldPaintBackgroundOrBorder(true); - _topExtra = 0; - _bottomExtra = 0; - m_percentageHeight = -1; - m_hasFlexedAnonymous = false; - m_widthChanged = false; -} - -void RenderTableCell::detach() -{ - if (parent() && section()) - section()->setNeedCellRecalc(); - - RenderBlock::detach(); -} - -void RenderTableCell::updateFromElement() -{ - DOM::NodeImpl *node = element(); - if ( node && (node->id() == ID_TD || node->id() == ID_TH) ) { - DOM::HTMLTableCellElementImpl *tc = static_cast<DOM::HTMLTableCellElementImpl *>(node); - cSpan = tc->colSpan(); - rSpan = tc->rowSpan(); - } else { - cSpan = rSpan = 1; - } -} - -Length RenderTableCell::styleOrColWidth() -{ - Length w = style()->width(); - if (colSpan() > 1 || !w.isVariable()) - return w; - RenderTableCol* col = table()->colElement(_col); - if (col) - w = col->style()->width(); - return w; -} - -void RenderTableCell::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(TableCell)::calcMinMaxWidth() known=" << minMaxKnown() << endl; -#endif - - if (section()->needCellRecalc) - section()->recalcCells(); - - RenderBlock::calcMinMaxWidth(); - if (element() && style()->whiteSpace() == NORMAL) { - // See if nowrap was set. - Length w = styleOrColWidth(); - DOMString nowrap = static_cast<ElementImpl*>(element())->getAttribute(ATTR_NOWRAP); - if (!nowrap.isNull() && w.isFixed() && - m_minWidth < w.value() ) - // Nowrap is set, but we didn't actually use it because of the - // fixed width set on the cell. Even so, it is a WinIE/Moz trait - // to make the minwidth of the cell into the fixed width. They do this - // even in strict mode, so do not make this a quirk. Affected the top - // of hiptop.com. - m_minWidth = w.value(); - } - - setMinMaxKnown(); -} - -void RenderTableCell::calcWidth() -{ -} - -void RenderTableCell::setWidth( int width ) -{ - if ( width != m_width ) { - m_width = width; - m_widthChanged = true; - } -} - -void RenderTableCell::layout() -{ - layoutBlock( m_widthChanged ); - m_widthChanged = false; -} - -void RenderTableCell::close() -{ - RenderBlock::close(); - -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << renderName() << "(RenderTableCell)::close() total height =" << m_height << endl; -#endif -} - -bool RenderTableCell::requiresLayer() const { - // table-cell display is never positioned (css 2.1-9.7), so the only time a layer is needed - // is when overflow != visible (or when there is opacity when we support it) - return /* style()->opacity() < 1.0f || */ hasOverflowClip() || isRelPositioned(); -} - -void RenderTableCell::repaintRectangle(int x, int y, int w, int h, Priority p, bool f) -{ - RenderBlock::repaintRectangle(x, y, w, h + _topExtra + _bottomExtra, p, f); -} - -bool RenderTableCell::absolutePosition(int &xPos, int &yPos, bool f) const -{ - bool result = RenderBlock::absolutePosition(xPos, yPos, f); - xPos -= parent()->xPos(); // Rows are in the same coordinate space, so don't add their offset in. - yPos -= parent()->yPos(); - return result; -} - -int RenderTableCell::pageTopAfter(int y) const -{ - return section()->pageTopAfter(y+m_y + _topExtra) - (m_y + _topExtra); -} - -short RenderTableCell::baselinePosition( bool ) const -{ - RenderObject* o = firstChild(); - int offset = paddingTop() + borderTop(); - if (!o) return offset + contentHeight(); - while (o->firstChild()) { - if (!o->isInline()) - offset += o->paddingTop() + o->borderTop(); - o = o->firstChild(); - } - - if (!o->isInline()) - return paddingTop() + borderTop() + contentHeight(); - - offset += o->baselinePosition( true ); - return offset; -} - - -void RenderTableCell::setStyle( RenderStyle *newStyle ) -{ - if (parent() && section() && style() && style()->height() != newStyle->height()) - section()->setNeedCellRecalc(); - - newStyle->setDisplay(TABLE_CELL); - RenderBlock::setStyle( newStyle ); - setShouldPaintBackgroundOrBorder(true); - - if (newStyle->whiteSpace() == KHTML_NOWRAP) { - // Figure out if we are really nowrapping or if we should just - // use normal instead. If the width of the cell is fixed, then - // we don't actually use NOWRAP. - if (newStyle->width().isFixed()) - newStyle->setWhiteSpace(NORMAL); - else - newStyle->setWhiteSpace(NOWRAP); - } -} - -bool RenderTableCell::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside) -{ - int tx = _tx + m_x; - int ty = _ty + m_y; - - // also include the top and bottom extra space - inside |= style()->visibility() != HIDDEN - && (_y >= ty) && (_y < ty + height() + _topExtra + _bottomExtra) - && (_x >= tx) && (_x < tx + width()); - - return RenderBlock::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside); -} - -// The following rules apply for resolving conflicts and figuring out which border -// to use. -// (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting -// borders. Any border with this value suppresses all borders at this location. -// (2) Borders with a style of 'none' have the lowest priority. Only if the border properties of all -// the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is -// the default value for the border style.) -// (3) If none of the styles are 'hidden' and at least one of them is not 'none', then narrow borders -// are discarded in favor of wider ones. If several have the same 'border-width' then styles are preferred -// in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'. -// (4) If border styles differ only in color, then a style set on a cell wins over one on a row, -// which wins over a row group, column, column group and, lastly, table. It is undefined which color -// is used when two elements of the same type disagree. -static CollapsedBorderValue compareBorders(const CollapsedBorderValue& border1, - const CollapsedBorderValue& border2) -{ - // Sanity check the values passed in. If either is null, return the other. - if (!border2.exists()) return border1; - if (!border1.exists()) return border2; - - // Rule #1 above. - if (border1.style() == BHIDDEN || border2.style() == BHIDDEN) - return CollapsedBorderValue(); // No border should exist at this location. - - // Rule #2 above. A style of 'none' has lowest priority and always loses to any other border. - if (border2.style() == BNONE) return border1; - if (border1.style() == BNONE) return border2; - - // The first part of rule #3 above. Wider borders win. - if (border1.width() != border2.width()) - return border1.width() > border2.width() ? border1 : border2; - - // The borders have equal width. Sort by border style. - if (border1.style() != border2.style()) - return border1.style() > border2.style() ? border1 : border2; - - // The border have the same width and style. Rely on precedence (cell over row over row group, etc.) - return border1.precedence >= border2.precedence ? border1 : border2; -} - -CollapsedBorderValue RenderTableCell::collapsedLeftBorder() const -{ - // For border left, we need to check, in order of precedence: - // (1) Our left border. - CollapsedBorderValue result(&style()->borderLeft(), BCELL); - - // (2) The previous cell's right border. - RenderTableCell* prevCell = table()->cellLeft(this); - if (prevCell) { - result = compareBorders(result, CollapsedBorderValue(&prevCell->style()->borderRight(), BCELL)); - if (!result.exists()) return result; - } - else if (col() == 0) { - // (3) Our row's left border. - result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderLeft(), BROW)); - if (!result.exists()) return result; - - // (4) Our row group's left border. - result = compareBorders(result, CollapsedBorderValue(§ion()->style()->borderLeft(), BROWGROUP)); - if (!result.exists()) return result; - } - - // (5) Our column's left border. - RenderTableCol* colElt = table()->colElement(col()); - if (colElt) { - result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL)); - if (!result.exists()) return result; - } - - // (6) The previous column's right border. - if (col() > 0) { - colElt = table()->colElement(col()-1); - if (colElt) { - result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), BCOL)); - if (!result.exists()) return result; - } - } - - if (col() == 0) { - // (7) The table's left border. - result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderLeft(), BTABLE)); - if (!result.exists()) return result; - } - - return result; -} - -CollapsedBorderValue RenderTableCell::collapsedRightBorder() const -{ - RenderTable* tableElt = table(); - bool inLastColumn = false; - int effCol = tableElt->colToEffCol(col()+colSpan()-1); - if (effCol == tableElt->numEffCols()-1) - inLastColumn = true; - - // For border right, we need to check, in order of precedence: - // (1) Our right border. - CollapsedBorderValue result = CollapsedBorderValue(&style()->borderRight(), BCELL); - - // (2) The next cell's left border. - if (!inLastColumn) { - RenderTableCell* nextCell = tableElt->cellRight(this); - if (nextCell) { - result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderLeft(), BCELL)); - if (!result.exists()) return result; - } - } - else { - // (3) Our row's right border. - result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderRight(), BROW)); - if (!result.exists()) return result; - - // (4) Our row group's right border. - result = compareBorders(result, CollapsedBorderValue(§ion()->style()->borderRight(), BROWGROUP)); - if (!result.exists()) return result; - } - - // (5) Our column's right border. - RenderTableCol* colElt = table()->colElement(col()+colSpan()-1); - if (colElt) { - result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), BCOL)); - if (!result.exists()) return result; - } - - // (6) The next column's left border. - if (!inLastColumn) { - colElt = tableElt->colElement(col()+colSpan()); - if (colElt) { - result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL)); - if (!result.exists()) return result; - } - } - else { - // (7) The table's right border. - result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderRight(), BTABLE)); - if (!result.exists()) return result; - } - - return result; -} - -CollapsedBorderValue RenderTableCell::collapsedTopBorder() const -{ - // For border top, we need to check, in order of precedence: - // (1) Our top border. - CollapsedBorderValue result = CollapsedBorderValue(&style()->borderTop(), BCELL); - - RenderTableCell* prevCell = table()->cellAbove(this); - if (prevCell) { - // (2) A previous cell's bottom border. - result = compareBorders(result, CollapsedBorderValue(&prevCell->style()->borderBottom(), BCELL)); - if (!result.exists()) return result; - } - - // (3) Our row's top border. - result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderTop(), BROW)); - if (!result.exists()) return result; - - // (4) The previous row's bottom border. - if (prevCell) { - RenderObject* prevRow = 0; - if (prevCell->section() == section()) - prevRow = parent()->previousSibling(); - else - prevRow = prevCell->section()->lastChild(); - - if (prevRow) { - result = compareBorders(result, CollapsedBorderValue(&prevRow->style()->borderBottom(), BROW)); - if (!result.exists()) return result; - } - } - - // Now check row groups. - RenderTableSection* currSection = section(); - if (row() == 0) { - // (5) Our row group's top border. - result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), BROWGROUP)); - if (!result.exists()) return result; - - // (6) Previous row group's bottom border. - currSection = table()->sectionAbove(currSection); - if (currSection) { - result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP)); - if (!result.exists()) - return result; - } - } - - if (!currSection) { - // (8) Our column's top border. - RenderTableCol* colElt = table()->colElement(col()); - if (colElt) { - result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderTop(), BCOL)); - if (!result.exists()) return result; - } - - // (9) The table's top border. - result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderTop(), BTABLE)); - if (!result.exists()) return result; - } - - return result; -} - -CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const -{ - // For border top, we need to check, in order of precedence: - // (1) Our bottom border. - CollapsedBorderValue result = CollapsedBorderValue(&style()->borderBottom(), BCELL); - - RenderTableCell* nextCell = table()->cellBelow(this); - if (nextCell) { - // (2) A following cell's top border. - result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderTop(), BCELL)); - if (!result.exists()) return result; - } - - // (3) Our row's bottom border. (FIXME: Deal with rowspan!) - result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderBottom(), BROW)); - if (!result.exists()) return result; - - // (4) The next row's top border. - if (nextCell) { - result = compareBorders(result, CollapsedBorderValue(&nextCell->parent()->style()->borderTop(), BROW)); - if (!result.exists()) return result; - } - - // Now check row groups. - RenderTableSection* currSection = section(); - if (row()+rowSpan() >= static_cast<RenderTableSection*>(currSection)->numRows()) { - // (5) Our row group's bottom border. - result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP)); - if (!result.exists()) return result; - - // (6) Following row group's top border. - currSection = table()->sectionBelow(currSection); - if (currSection) { - result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), BROWGROUP)); - if (!result.exists()) - return result; - } - } - - if (!currSection) { - // (8) Our column's bottom border. - RenderTableCol* colElt = table()->colElement(col()); - if (colElt) { - result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderBottom(), BCOL)); - if (!result.exists()) return result; - } - - // (9) The table's bottom border. - result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderBottom(), BTABLE)); - if (!result.exists()) return result; - } - - return result; -} - -int RenderTableCell::borderLeft() const -{ - if (table()->collapseBorders()) { - CollapsedBorderValue border = collapsedLeftBorder(); - if (border.exists()) - return (border.width()+1)/2; // Give the extra pixel to top and left. - return 0; - } - return RenderBlock::borderLeft(); -} - -int RenderTableCell::borderRight() const -{ - if (table()->collapseBorders()) { - CollapsedBorderValue border = collapsedRightBorder(); - if (border.exists()) - return border.width()/2; - return 0; - } - return RenderBlock::borderRight(); -} - -int RenderTableCell::borderTop() const -{ - if (table()->collapseBorders()) { - CollapsedBorderValue border = collapsedTopBorder(); - if (border.exists()) - return (border.width()+1)/2; // Give the extra pixel to top and left. - return 0; - } - return RenderBlock::borderTop(); -} - -int RenderTableCell::borderBottom() const -{ - if (table()->collapseBorders()) { - CollapsedBorderValue border = collapsedBottomBorder(); - if (border.exists()) - return border.width()/2; - return 0; - } - return RenderBlock::borderBottom(); -} - -#ifdef BOX_DEBUG -#include <tqpainter.h> - -static void outlineBox(TQPainter *p, int _tx, int _ty, int w, int h) -{ - p->setPen(TQPen(TQColor("yellow"), 3, Qt::DotLine)); - p->setBrush( Qt::NoBrush ); - p->drawRect(_tx, _ty, w, h ); -} -#endif - -void RenderTableCell::paint(PaintInfo& pI, int _tx, int _ty) -{ - -#ifdef TABLE_PRINT - kdDebug( 6040 ) << renderName() << "(RenderTableCell)::paint() w/h = (" << width() << "/" << height() << ")" << " _y/_h=" << pI.r.y() << "/" << pI.r.height() << endl; -#endif - - if (needsLayout()) return; - - _tx += m_x; - _ty += m_y/* + _topExtra*/; - - RenderTable *tbl = table(); - - // check if we need to do anything at all... - int os = kMax(tbl->currentBorderStyle() ? (tbl->currentBorderStyle()->border->width+1)/2 : 0, 2*maximalOutlineSize(pI.phase)); - if (!overhangingContents() && ((_ty >= pI.r.y() + pI.r.height() + os) - || (_ty + _topExtra + m_height + _bottomExtra <= pI.r.y() - os))) return; - - if (pI.phase == PaintActionOutline) { - paintOutline( pI.p, _tx, _ty, width(), height() + borderTopExtra() + borderBottomExtra(), style()); - } - - if (pI.phase == PaintActionCollapsedTableBorders && style()->visibility() == VISIBLE) { - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - paintCollapsedBorder(pI.p, _tx, _ty, w, h); - } - else - RenderBlock::paintObject(pI, _tx, _ty + _topExtra, false); - -#ifdef BOX_DEBUG - ::outlineBox( p, _tx, _ty - _topExtra, width(), height() + borderTopExtra() + borderBottomExtra()); -#endif -} - -static EBorderStyle collapsedBorderStyle(EBorderStyle style) -{ - if (style == OUTSET) - style = GROOVE; - else if (style == INSET) - style = RIDGE; - return style; -} - -struct CollapsedBorder { - CollapsedBorder(){} - - CollapsedBorderValue border; - RenderObject::BorderSide side; - bool shouldPaint; - int x1; - int y1; - int x2; - int y2; - EBorderStyle style; -}; - -class CollapsedBorders -{ -public: - CollapsedBorders() :count(0) {} - - void addBorder(const CollapsedBorderValue& b, RenderObject::BorderSide s, bool paint, - int _x1, int _y1, int _x2, int _y2, - EBorderStyle _style) - { - if (b.exists() && paint) { - borders[count].border = b; - borders[count].side = s; - borders[count].shouldPaint = paint; - borders[count].x1 = _x1; - borders[count].x2 = _x2; - borders[count].y1 = _y1; - borders[count].y2 = _y2; - borders[count].style = _style; - count++; - } - } - - CollapsedBorder* nextBorder() { - for (int i = 0; i < count; i++) { - if (borders[i].border.exists() && borders[i].shouldPaint) { - borders[i].shouldPaint = false; - return &borders[i]; - } - } - - return 0; - } - - CollapsedBorder borders[4]; - int count; -}; - -static void addBorderStyle(TQValueList<CollapsedBorderValue>& borderStyles, CollapsedBorderValue borderValue) -{ - if (!borderValue.exists() || borderStyles.contains(borderValue)) - return; - - TQValueListIterator<CollapsedBorderValue> it = borderStyles.begin(); - TQValueListIterator<CollapsedBorderValue> end = borderStyles.end(); - for (; it != end; ++it) { - CollapsedBorderValue result = compareBorders(*it, borderValue); - if (result == *it) { - borderStyles.insert(it, borderValue); - return; - } - } - - borderStyles.append(borderValue); -} - -void RenderTableCell::collectBorders(TQValueList<CollapsedBorderValue>& borderStyles) -{ - addBorderStyle(borderStyles, collapsedLeftBorder()); - addBorderStyle(borderStyles, collapsedRightBorder()); - addBorderStyle(borderStyles, collapsedTopBorder()); - addBorderStyle(borderStyles, collapsedBottomBorder()); -} - -void RenderTableCell::paintCollapsedBorder(TQPainter* p, int _tx, int _ty, int w, int h) -{ - if (!table()->currentBorderStyle()) - return; - - CollapsedBorderValue leftVal = collapsedLeftBorder(); - CollapsedBorderValue rightVal = collapsedRightBorder(); - CollapsedBorderValue topVal = collapsedTopBorder(); - CollapsedBorderValue bottomVal = collapsedBottomBorder(); - - // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location. - int topWidth = topVal.width(); - int bottomWidth = bottomVal.width(); - int leftWidth = leftVal.width(); - int rightWidth = rightVal.width(); - - _tx -= leftWidth/2; - _ty -= topWidth/2; - w += leftWidth/2 + (rightWidth+1)/2; - h += topWidth/2 + (bottomWidth+1)/2; - - bool tt = topVal.isTransparent(); - bool bt = bottomVal.isTransparent(); - bool rt = rightVal.isTransparent(); - bool lt = leftVal.isTransparent(); - - EBorderStyle ts = collapsedBorderStyle(topVal.style()); - EBorderStyle bs = collapsedBorderStyle(bottomVal.style()); - EBorderStyle ls = collapsedBorderStyle(leftVal.style()); - EBorderStyle rs = collapsedBorderStyle(rightVal.style()); - - bool render_t = ts > BHIDDEN && !tt && (topVal.precedence != BCELL || *topVal.border == style()->borderTop()); - bool render_l = ls > BHIDDEN && !lt && (leftVal.precedence != BCELL || *leftVal.border == style()->borderLeft()); - bool render_r = rs > BHIDDEN && !rt && (rightVal.precedence != BCELL || *rightVal.border == style()->borderRight()); - bool render_b = bs > BHIDDEN && !bt && (bottomVal.precedence != BCELL || *bottomVal.border == style()->borderBottom()); - - // We never paint diagonals at the joins. We simply let the border with the highest - // precedence paint on top of borders with lower precedence. - CollapsedBorders borders; - borders.addBorder(topVal, BSTop, render_t, _tx, _ty, _tx + w, _ty + topWidth, ts); - borders.addBorder(bottomVal, BSBottom, render_b, _tx, _ty + h - bottomWidth, _tx + w, _ty + h, bs); - borders.addBorder(leftVal, BSLeft, render_l, _tx, _ty, _tx + leftWidth, _ty + h, ls); - borders.addBorder(rightVal, BSRight, render_r, _tx + w - rightWidth, _ty, _tx + w, _ty + h, rs); - - for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) { - if (border->border == *table()->currentBorderStyle()) - drawBorder(p, border->x1, border->y1, border->x2, border->y2, border->side, - border->border.color(), style()->color(), border->style, 0, 0); - } -} - -void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& pI, int _tx, int _ty, RenderObject* backgroundObject) -{ - if (!backgroundObject) - return; - - RenderTable* tableElt = table(); - if (backgroundObject != this) { - _tx += m_x; - _ty += m_y + _topExtra; - } - - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - _ty -= borderTopExtra(); - - int my = kMax(_ty,pI.r.y()); - int end = kMin( pI.r.y() + pI.r.height(), _ty + h ); - int mh = end - my; - - TQColor c = backgroundObject->style()->backgroundColor(); - const BackgroundLayer* bgLayer = backgroundObject->style()->backgroundLayers(); - - if (bgLayer->hasImage() || c.isValid()) { - // We have to clip here because the background would paint - // on top of the borders otherwise. This only matters for cells and rows. - bool hasLayer = backgroundObject->layer() && (backgroundObject == this || backgroundObject == parent()); - if (hasLayer && tableElt->collapseBorders()) { - pI.p->save(); - TQRect clipRect(_tx + borderLeft(), _ty + borderTop(), w - borderLeft() - borderRight(), h - borderTop() - borderBottom()); - clipRect = pI.p->xForm(clipRect); - TQRegion creg(clipRect); - TQRegion old = pI.p->clipRegion(); - if (!old.isNull()) - creg = old.intersect(creg); - pI.p->setClipRegion(creg); - } - paintBackground(pI.p, c, bgLayer, my, mh, _tx, _ty, w, h); - if (hasLayer && tableElt->collapseBorders()) - pI.p->restore(); - } -} - -void RenderTableCell::paintBoxDecorations(PaintInfo& pI, int _tx, int _ty) -{ - RenderTable* tableElt = table(); - bool drawBorders = true; - // Moz paints bgcolor/bgimage on <td>s in quirks mode even if - // empty-cells are on. Fixes regression on #43426, attachment #354 - if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild()) - drawBorders = false; - if (!style()->htmlHacks() && !drawBorders) return; - - // Paint our cell background. - paintBackgroundsBehindCell(pI, _tx, _ty, this); - - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - _ty -= borderTopExtra(); - - if (drawBorders && style()->hasBorder() && !tableElt->collapseBorders()) - paintBorder(pI.p, _tx, _ty, w, h, style()); -} - - -#ifdef ENABLE_DUMP -void RenderTableCell::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderFlow::dump(stream,ind); - stream << " row=" << _row; - stream << " col=" << _col; - stream << " rSpan=" << rSpan; - stream << " cSpan=" << cSpan; -// *stream << " nWrap=" << nWrap; -} -#endif - -// ------------------------------------------------------------------------- - -RenderTableCol::RenderTableCol(DOM::NodeImpl* node) - : RenderContainer(node), m_span(1) -{ - // init RenderObject attributes - setInline(true); // our object is not Inline - updateFromElement(); -} - -void RenderTableCol::updateFromElement() -{ - DOM::NodeImpl *node = element(); - if ( node && (node->id() == ID_COL || node->id() == ID_COLGROUP) ) { - DOM::HTMLTableColElementImpl *tc = static_cast<DOM::HTMLTableColElementImpl *>(node); - m_span = tc->span(); - } else - m_span = ! ( style() && style()->display() == TABLE_COLUMN_GROUP ); -} - -#ifdef ENABLE_DUMP -void RenderTableCol::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderContainer::dump(stream,ind); - stream << " _span=" << m_span; -} -#endif - -// ------------------------------------------------------------------------- - -TableSectionIterator::TableSectionIterator(RenderTable *table, bool fromEnd) -{ - if (fromEnd) { - sec = table->foot; - if (sec) return; - - sec = static_cast<RenderTableSection *>(table->lastChild()); - while (sec && (!sec->isTableSection() - || sec == table->head || sec == table->foot)) - sec = static_cast<RenderTableSection *>(sec->previousSibling()); - if (sec) return; - - sec = table->head; - } else { - sec = table->head; - if (sec) return; - - sec = static_cast<RenderTableSection *>(table->firstChild()); - while (sec && (!sec->isTableSection() - || sec == table->head || sec == table->foot)) - sec = static_cast<RenderTableSection *>(sec->nextSibling()); - if (sec) return; - - sec = table->foot; - }/*end if*/ - -} - -TableSectionIterator &TableSectionIterator::operator ++() -{ - RenderTable *table = sec->table(); - if (sec == table->head) { - - sec = static_cast<RenderTableSection *>(table->firstChild()); - while (sec && (!sec->isTableSection() - || sec == table->head || sec == table->foot)) - sec = static_cast<RenderTableSection *>(sec->nextSibling()); - if (sec) return *this; - - } else if (sec == table->foot) { - sec = 0; - return *this; - - } else { - - do { - sec = static_cast<RenderTableSection *>(sec->nextSibling()); - } while (sec && (!sec->isTableSection() || sec == table->head || sec == table->foot)); - if (sec) return *this; - - }/*end if*/ - - sec = table->foot; - return *this; -} - -TableSectionIterator &TableSectionIterator::operator --() -{ - RenderTable *table = sec->table(); - if (sec == table->foot) { - - sec = static_cast<RenderTableSection *>(table->lastChild()); - while (sec && (!sec->isTableSection() - || sec == table->head || sec == table->foot)) - sec = static_cast<RenderTableSection *>(sec->previousSibling()); - if (sec) return *this; - - } else if (sec == table->head) { - sec = 0; - return *this; - - } else { - - do { - sec = static_cast<RenderTableSection *>(sec->previousSibling()); - } while (sec && (!sec->isTableSection() || sec == table->head || sec == table->foot)); - if (sec) return *this; - - }/*end if*/ - - sec = table->foot; - return *this; -} - -#undef TABLE_DEBUG -#undef DEBUG_LAYOUT -#undef BOX_DEBUG diff --git a/khtml/rendering/render_table.h b/khtml/rendering/render_table.h deleted file mode 100644 index a6de6cfaf..000000000 --- a/khtml/rendering/render_table.h +++ /dev/null @@ -1,524 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1997 Martin Jones (mjones@kde.org) - * (C) 1997 Torben Weis (weis@kde.org) - * (C) 1998 Waldo Bastian (bastian@kde.org) - * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -#ifndef RENDER_TABLE_H -#define RENDER_TABLE_H - -#include <tqcolor.h> -#include <tqptrvector.h> - -#include "rendering/render_box.h" -#include "rendering/render_block.h" -#include "rendering/render_style.h" - -#include "misc/khtmllayout.h" - -namespace DOM { - class DOMString; -} - -namespace khtml { - -class RenderTable; -class RenderTableSection; -class RenderTableRow; -class RenderTableCell; -class RenderTableCol; -class TableLayout; - -class RenderTable : public RenderBlock -{ -public: - - RenderTable(DOM::NodeImpl* node); - ~RenderTable(); - - virtual const char *renderName() const { return "RenderTable"; } - - virtual void setStyle(RenderStyle *style); - - virtual bool isTable() const { return true; } - - int getColumnPos(int col) const - { return columnPos[col]; } - - int borderHSpacing() const { return hspacing; } - int borderVSpacing() const { return vspacing; } - - bool collapseBorders() const { return style()->borderCollapse(); } - int borderLeft() const; - int borderRight() const; - int borderTop() const; - int borderBottom() const; - int paddingLeft() const { return collapseBorders() ? 0 : RenderBlock::paddingLeft(); } - int paddingRight() const { return collapseBorders() ? 0 : RenderBlock::paddingRight(); } - int paddingTop() const { return collapseBorders() ? 0 : RenderBlock::paddingTop(); } - int paddingBottom() const { return collapseBorders() ? 0 : RenderBlock::paddingBottom(); } - - const TQColor &bgColor() const { return style()->backgroundColor(); } - - uint cellPadding() const { return padding; } - void setCellPadding( uint p ) { padding = p; } - - // overrides - virtual void addChild(RenderObject *child, RenderObject *beforeChild = 0); - virtual void paint( PaintInfo&, int tx, int ty); - virtual void paintBoxDecorations(PaintInfo&, int _tx, int _ty); - virtual void layout(); - virtual void calcMinMaxWidth(); - virtual void close(); - - virtual short lineHeight(bool b) const; - virtual short baselinePosition(bool b) const; - - virtual void setCellWidths( ); - - virtual void calcWidth(); - - virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty, - DOM::NodeImpl*& node, int & offset, - SelPointState & ); - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - struct ColumnStruct { - enum { - WidthUndefined = 0xffff - }; - ColumnStruct() { - span = 1; - width = WidthUndefined; - } - ushort span; - ushort width; // the calculated position of the column - }; - - TQMemArray<int> columnPos; - TQMemArray<ColumnStruct> columns; - - void splitColumn( int pos, int firstSpan ); - void appendColumn( int span ); - int numEffCols() const { return columns.size(); } - int spanOfEffCol( int effCol ) const { return columns[effCol].span; } - int colToEffCol( int col ) const { - int c = 0; - int i = 0; - while ( c < col && i < (int)columns.size() ) { - c += columns[i].span; - i++; - } - return i; - } - int effColToCol( int effCol ) const { - int c = 0; - for ( int i = 0; i < effCol; i++ ) - c += columns[i].span; - return c; - } - - int bordersPaddingAndSpacing() const { - return borderLeft() + borderRight() + - (collapseBorders() ? 0 : (paddingLeft() + paddingRight() + (numEffCols()+1) * borderHSpacing())); - } - - RenderTableCol *colElement( int col ); - - void setNeedSectionRecalc() { needSectionRecalc = true; } - - virtual RenderObject* removeChildNode(RenderObject* child); - - RenderTableSection* sectionAbove(const RenderTableSection*, bool skipEmptySections = false) const; - RenderTableSection* sectionBelow(const RenderTableSection*, bool skipEmptySections = false) const; - - RenderTableCell* cellAbove(const RenderTableCell* cell) const; - RenderTableCell* cellBelow(const RenderTableCell* cell) const; - RenderTableCell* cellLeft(const RenderTableCell* cell) const; - RenderTableCell* cellRight(const RenderTableCell* cell) const; - - CollapsedBorderValue* currentBorderStyle() { return m_currentBorder; } - - RenderTableSection *firstBodySection() const { return firstBody; } - RenderFlow* caption() const { return tCaption; } - -protected: - - void recalcSections(); - - friend class AutoTableLayout; - friend class FixedTableLayout; - - RenderFlow *tCaption; - RenderTableSection *head; - RenderTableSection *foot; - RenderTableSection *firstBody; - - TableLayout *tableLayout; - - CollapsedBorderValue* m_currentBorder; - - bool has_col_elems : 1; - uint needSectionRecalc : 1; - uint padding : 22; - - ushort hspacing; - ushort vspacing; - - friend class TableSectionIterator; -}; - -// ------------------------------------------------------------------------- - -class RenderTableSection : public RenderBox -{ -public: - RenderTableSection(DOM::NodeImpl* node); - ~RenderTableSection(); - virtual void detach(); - - virtual void setStyle(RenderStyle *style); - - virtual const char *renderName() const { return "RenderTableSection"; } - - // overrides - virtual void addChild(RenderObject *child, RenderObject *beforeChild = 0); - virtual bool isTableSection() const { return true; } - - virtual short lineHeight(bool) const { return 0; } - virtual void position(InlineBox*, int, int, bool) {} - - virtual short width() const; - - virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty, - DOM::NodeImpl*& node, int & offset, - SelPointState & ); - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - - void addCell( RenderTableCell *cell, RenderTableRow *row ); - - void setCellWidths(); - void calcRowHeight(); - int layoutRows( int height ); - - RenderTable *table() const { return static_cast<RenderTable *>(parent()); } - - typedef TQMemArray<RenderTableCell *> Row; - struct RowStruct { - Row *row; - RenderTableRow* rowRenderer; - int baseLine; - Length height; - bool needFlex; - }; - - RenderTableCell *&cellAt( int row, int col ) { - return (*(grid[row].row))[col]; - } - RenderTableCell *cellAt( int row, int col ) const { - return (*(grid[row].row))[col]; - } - - virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf) const; - virtual int rightmostPosition(bool includeOverflowInterior, bool includeSelf) const; - virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf) const; - virtual int highestPosition(bool includeOverflowInterior, bool includeSelf) const; - - int borderLeft() const { return table()->collapseBorders() ? 0 : RenderBox::borderLeft(); } - int borderRight() const { return table()->collapseBorders() ? 0 : RenderBox::borderRight(); } - int borderTop() const { return table()->collapseBorders() ? 0 : RenderBox::borderTop(); } - int borderBottom() const { return table()->collapseBorders() ? 0 : RenderBox::borderBottom(); } - - virtual void paint( PaintInfo& i, int tx, int ty); - - int numRows() const { return grid.size(); } - int getBaseline(int row) {return grid[row].baseLine;} - - void setNeedCellRecalc() { - needCellRecalc = true; - table()->setNeedSectionRecalc(); - } - - virtual RenderObject* removeChildNode(RenderObject* child); - - virtual bool canClear(RenderObject *child, PageBreakLevel level); - void addSpaceAt(int pos, int dy); - - virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action, bool inside); - - // this gets a cell grid data structure. changing the number of - // columns is done by the table - TQMemArray<RowStruct> grid; - TQMemArray<int> rowPos; - - signed short cRow; - ushort cCol; - bool needCellRecalc; - - void recalcCells(); -protected: - void ensureRows( int numRows ); - void clearGrid(); - bool emptyRow(int rowNum); - bool flexCellChildren(RenderObject* p) const; - - - friend class TableSectionIterator; -}; - -// ------------------------------------------------------------------------- - -class RenderTableRow : public RenderContainer -{ -public: - RenderTableRow(DOM::NodeImpl* node); - - virtual void detach(); - - virtual void setStyle( RenderStyle* ); - virtual const char *renderName() const { return "RenderTableRow"; } - virtual bool isTableRow() const { return true; } - virtual void addChild(RenderObject *child, RenderObject *beforeChild = 0); - - virtual short offsetWidth() const; - virtual int offsetHeight() const; - virtual int offsetLeft() const; - virtual int offsetTop() const; - - virtual short lineHeight( bool ) const { return 0; } - virtual void position(InlineBox*, int, int, bool) {} - - virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action, bool inside); - - virtual void layout(); - - virtual RenderObject* removeChildNode(RenderObject* child); - - // The only time rows get a layer is when they have transparency. - virtual bool requiresLayer() const { return /* style()->opacity() < 1.0f; */ false ; } - virtual void paint(PaintInfo& i, int tx, int ty); - - void paintRow( PaintInfo& i, int tx, int ty, int w, int h); - - RenderTable *table() const { return static_cast<RenderTable *>(parent()->parent()); } - RenderTableSection *section() const { return static_cast<RenderTableSection *>(parent()); } -}; - -// ------------------------------------------------------------------------- - -class RenderTableCell : public RenderBlock -{ -public: - RenderTableCell(DOM::NodeImpl* node); - - virtual void layout(); - virtual void detach(); - - virtual const char *renderName() const { return "RenderTableCell"; } - virtual bool isTableCell() const { return true; } - - // ### FIX these two... - long cellIndex() const { return 0; } - void setCellIndex( long ) { } - - unsigned short colSpan() const { return cSpan; } - void setColSpan( unsigned short c ) { cSpan = c; } - - unsigned short rowSpan() const { return rSpan; } - void setRowSpan( unsigned short r ) { rSpan = r; } - - int col() const { return _col; } - void setCol(int col) { _col = col; } - int row() const { return _row; } - void setRow(int r) { _row = r; } - - Length styleOrColWidth(); - - // overrides - virtual void calcMinMaxWidth(); - virtual void calcWidth(); - virtual void setWidth( int width ); - virtual void setStyle( RenderStyle *style ); - virtual bool requiresLayer() const; - - int borderLeft() const; - int borderRight() const; - int borderTop() const; - int borderBottom() const; - - CollapsedBorderValue collapsedLeftBorder() const; - CollapsedBorderValue collapsedRightBorder() const; - CollapsedBorderValue collapsedTopBorder() const; - CollapsedBorderValue collapsedBottomBorder() const; - virtual void collectBorders(TQValueList<CollapsedBorderValue>& borderStyles); - - virtual void updateFromElement(); - - void setCellTopExtra(int p) { _topExtra = p; } - void setCellBottomExtra(int p) { _bottomExtra = p; } - int cellTopExtra() const { return _topExtra; } - int cellBottomExtra() const { return _bottomExtra; } - - int pageTopAfter(int x) const; - - virtual void paint( PaintInfo& i, int tx, int ty); - - void paintCollapsedBorder(TQPainter* p, int x, int y, int w, int h); - void paintBackgroundsBehindCell(PaintInfo& i, int _tx, int _ty, RenderObject* backgroundObject); - - virtual void close(); - - // lie position to outside observers - virtual int yPos() const { return m_y + _topExtra; } - - virtual void repaintRectangle(int x, int y, int w, int h, Priority p=NormalPriority, bool f=false); - virtual bool absolutePosition(int &xPos, int &yPos, bool f = false) const; - - virtual short baselinePosition( bool = false ) const; - - virtual bool nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside); - - RenderTable *table() const { return static_cast<RenderTable *>(parent()->parent()->parent()); } - RenderTableSection *section() const { return static_cast<RenderTableSection *>(parent()->parent()); } - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - - bool widthChanged() { - bool retval = m_widthChanged; - m_widthChanged = false; - return retval; - } - - int cellPercentageHeight() const - { return m_percentageHeight; } - void setCellPercentageHeight(int h) - { m_percentageHeight = h; } - bool hasFlexedAnonymous() const - { return m_hasFlexedAnonymous; } - void setHasFlexedAnonymous(bool b=true) - { m_hasFlexedAnonymous = b; } - -protected: - virtual void paintBoxDecorations(PaintInfo& p, int _tx, int _ty); - virtual int borderTopExtra() const { return _topExtra; } - virtual int borderBottomExtra() const { return _bottomExtra; } - - short _row; - short _col; - ushort rSpan; - ushort cSpan; - int _topExtra; - signed int _bottomExtra : 30; - bool m_widthChanged : 1; - bool m_hasFlexedAnonymous : 1; - int m_percentageHeight; -}; - - -// ------------------------------------------------------------------------- - -class RenderTableCol : public RenderContainer -{ -public: - RenderTableCol(DOM::NodeImpl* node); - - virtual const char *renderName() const { return "RenderTableCol"; } - - virtual bool isTableCol() const { return true; } - - virtual short lineHeight( bool ) const { return 0; } - virtual void position(InlineBox*, int, int, bool) {} - virtual void layout() {} - virtual bool requiresLayer() const { return false; } - - virtual void updateFromElement(); - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString& ind) const; -#endif - - int span() const { return m_span; } - void setSpan( int s ) { m_span = s; } - -private: - int m_span; -}; - -// ------------------------------------------------------------------------- - -/** This class provides an iterator to iterate through the sections of a - * render table in their visual order. - * - * In HTML, sections are specified in the order of THEAD, TFOOT, and TBODY. - * Visually, TBODY sections appear between THEAD and TFOOT, which this iterator - * takes into regard. - * @author Leo Savernik - * @internal - * @since 3.2 - */ -class TableSectionIterator { -public: - - /** - * Initializes a new iterator - * @param table table whose sections to iterate - * @param fromEnd @p true, begin with last section, @p false, begin with - * first section. - */ - TableSectionIterator(RenderTable *table, bool fromEnd = false); - - /** - * Initializes a new iterator - * @param start table section to start with. - */ - TableSectionIterator(RenderTableSection *start) : sec(start) {} - - /** - * Uninitialized iterator. - */ - TableSectionIterator() {} - - /** Returns the current section, or @p 0 if the end has been reached. - */ - RenderTableSection *operator *() const { return sec; } - - /** Moves to the next section in visual order. */ - TableSectionIterator &operator ++(); - - /** Moves to the previous section in visual order. */ - TableSectionIterator &operator --(); - -private: - RenderTableSection *sec; -}; - -} -#endif - diff --git a/khtml/rendering/render_text.cpp b/khtml/rendering/render_text.cpp deleted file mode 100644 index 770e8cd4d..000000000 --- a/khtml/rendering/render_text.cpp +++ /dev/null @@ -1,1546 +0,0 @@ -/** - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, Inc. - * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) - * - * 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. - * - */ - -//#define DEBUG_LAYOUT -//#define BIDI_DEBUG - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "rendering/render_text.h" -#include "rendering/render_canvas.h" -#include "rendering/break_lines.h" -#include "rendering/render_arena.h" -#include "xml/dom_nodeimpl.h" - -#include "misc/loader.h" -#include "misc/helper.h" - -#include <tqbitmap.h> -#include <tqimage.h> -#include <tqpainter.h> -#include <kdebug.h> -#include <kglobal.h> -#include <assert.h> -#include <limits.h> -#include <math.h> - -#ifdef HAVE_ALLOCA_H -// explicitly included for systems that don't provide it in stdlib.h -#include <alloca.h> -#else -#include <stdlib.h> -#endif - -using namespace khtml; -using namespace DOM; - -#ifndef NDEBUG -static bool inInlineTextBoxDetach; -#endif - -void InlineTextBox::detach(RenderArena* renderArena) -{ - if (m_parent) - m_parent->removeFromLine(this); - -#ifndef NDEBUG - inInlineTextBoxDetach = true; -#endif - delete this; -#ifndef NDEBUG - inInlineTextBoxDetach = false; -#endif - - // Recover the size left there for us by operator delete and free the memory. - renderArena->free(*(size_t *)this, this); -} - -void* InlineTextBox::operator new(size_t sz, RenderArena* renderArena) throw() -{ - return renderArena->allocate(sz); -} - -void InlineTextBox::operator delete(void* ptr, size_t sz) -{ - assert(inInlineTextBoxDetach); - - // Stash size where detach can find it. - *(size_t *)ptr = sz; -} - -void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) -{ - int startPos, endPos; - if (object()->selectionState() == RenderObject::SelectionInside) { - startPos = 0; - endPos = renderText()->string()->l; - } else { - renderText()->selectionStartEnd(startPos, endPos); - if (object()->selectionState() == RenderObject::SelectionStart) - endPos = renderText()->string()->l; - else if (object()->selectionState() == RenderObject::SelectionEnd) - startPos = 0; - } - - sPos = kMax(startPos - m_start, 0); - ePos = kMin(endPos - m_start, (int)m_len); -} - -RenderObject::SelectionState InlineTextBox::selectionState() -{ - RenderObject::SelectionState state = object()->selectionState(); - if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || - state == RenderObject::SelectionBoth) { - int startPos, endPos; - renderText()->selectionStartEnd(startPos, endPos); - - bool start = (state != RenderObject::SelectionEnd && startPos >= m_start && startPos < m_start + m_len); - bool end = (state != RenderObject::SelectionStart && endPos > m_start && endPos <= m_start + m_len); - if (start && end) - state = RenderObject::SelectionBoth; - else if (start) - state = RenderObject::SelectionStart; - else if (end) - state = RenderObject::SelectionEnd; - else if ((state == RenderObject::SelectionEnd || startPos < m_start) && - (state == RenderObject::SelectionStart || endPos > m_start + m_len)) - state = RenderObject::SelectionInside; - } - return state; -} - -void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - if (object()->isBR() || object()->style()->visibility() != VISIBLE || - m_truncation == cFullTruncation || i.phase == PaintActionOutline) - return; - - if (i.phase == PaintActionSelection && object()->selectionState() == RenderObject::SelectionNone) - // When only painting the selection, don't bother to paint if there is none. - return; - - int xPos = tx + m_x; - int w = width(); - if ((xPos >= i.r.x() + i.r.width()) || (xPos + w <= i.r.x())) - return; - - // Set our font. - RenderStyle* styleToUse = object()->style(m_firstLine); - int d = styleToUse->textDecorationsInEffect(); - if (styleToUse->font() != i.p->font()) - i.p->setFont(styleToUse->font()); - const Font *font = &styleToUse->htmlFont(); - bool haveSelection = selectionState() != RenderObject::SelectionNone; - - // Now calculate startPos and endPos, for painting selection. - // We paint selection while endPos > 0 - int ePos = 0, sPos = 0; - if (haveSelection && !object()->canvas()->staticMode()) { - selectionStartEnd(sPos, ePos); - } - if (styleToUse->color() != i.p->pen().color()) - i.p->setPen(styleToUse->color()); - - if (m_len > 0 && i.phase != PaintActionSelection) { - int endPoint = m_len; - if (m_truncation != cNoTruncation) - endPoint = m_truncation - m_start; - if (styleToUse->textShadow()) - paintShadow(i.p, font, tx, ty, styleToUse->textShadow()); - if (!haveSelection || sPos != 0 || ePos != m_len) { - font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, renderText()->string()->s, renderText()->string()->l, m_start, endPoint, - m_toAdd, m_reversed ? TQPainter::RTL : TQPainter::LTR); - } - } - - if (d != TDNONE && i.phase != PaintActionSelection && styleToUse->htmlHacks()) { - i.p->setPen(styleToUse->color()); - paintDecoration(i.p, font, tx, ty, d); - } - - if (haveSelection && i.phase == PaintActionSelection) { - //kdDebug(6040) << this << " paintSelection with startPos=" << sPos << " endPos=" << ePos << endl; - if ( sPos < ePos ) - paintSelection(font, renderText(), i.p, styleToUse, tx, ty, sPos, ePos, d); - } -} - -/** returns the proper ::selection pseudo style for the given element - * @return the style or 0 if no ::selection pseudo applies. - */ -inline const RenderStyle *retrieveSelectionPseudoStyle(const RenderObject *obj) -{ - // http://www.w3.org/Style/CSS/Test/CSS3/Selectors/20021129/html/tests/css3-modsel-162.html - // is of the opinion that ::selection of parent elements is also to be applied - // to children, so let's do it. - while (obj) { - const RenderStyle *style = obj->style()->getPseudoStyle(RenderStyle::SELECTION); - if (style) return style; - - obj = obj->parent(); - }/*wend*/ - return 0; -} - -void InlineTextBox::paintSelection(const Font *f, RenderText *text, TQPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos, int deco) -{ - if(startPos > m_len) return; - if(startPos < 0) startPos = 0; - - TQColor hc; - TQColor hbg; - const RenderStyle* pseudoStyle = retrieveSelectionPseudoStyle(text); - if (pseudoStyle) { - // ### support outline (mandated by CSS3) - // ### support background-image? (optional by CSS3) - if (pseudoStyle->backgroundColor().isValid()) - hbg = pseudoStyle->backgroundColor(); - hc = pseudoStyle->color(); - } else { - const TQColorGroup &grp = style->palette().active(); - hc = grp.highlightedText(); - hbg = grp.highlight(); - // ### should be at most retrieved once per render text - TQColor bg = khtml::retrieveBackgroundColor(text); - // It may happen that the contrast is -- well -- virtually non existent. - // In this case, simply swap the colors, thus in compliance with - // NN4 (win32 only), IE, and Mozilla. - if (!khtml::hasSufficientContrast(hbg, bg)) - tqSwap(hc, hbg); - } - - p->setPen(hc); - - //kdDebug( 6040 ) << "textRun::painting(" << TQConstString(text->str->s + m_start, m_len).string().left(30) << ") at(" << m_x+tx << "/" << m_y+ty << ")" << endl; - - const bool needClipping = startPos != 0 || endPos != m_len; - - if (needClipping) { - p->save(); - - int visualSelectionStart = f->width(text->str->s, text->str->l, m_start, startPos, m_start, m_start + m_len, m_toAdd); - int visualSelectionEnd = f->width(text->str->s, text->str->l, m_start, endPos, m_start, m_start + m_len, m_toAdd); - int visualSelectionWidth = visualSelectionEnd - visualSelectionStart; - if (m_reversed) { - visualSelectionStart = f->width(text->str->s, text->str->l, m_start, m_len) - visualSelectionEnd; - } - - TQRect selectionRect(m_x + tx + visualSelectionStart, m_y + ty, visualSelectionWidth, height()); - TQRegion r(selectionRect); - if (p->hasClipping()) - r &= p->clipRegion(TQPainter::CoordPainter); - p->setClipRegion(r, TQPainter::CoordPainter); - } - - f->drawText(p, m_x + tx, m_y + ty + m_baseline, text->str->s, text->str->l, - m_start, m_len, m_toAdd, - m_reversed ? TQPainter::RTL : TQPainter::LTR, - needClipping ? 0 : startPos, needClipping ? m_len : endPos, - hbg, m_y + ty, height(), deco); - - if (needClipping) p->restore(); -} - -void InlineTextBox::paintDecoration( TQPainter *pt, const Font *f, int _tx, int _ty, int deco) -{ - _tx += m_x; - _ty += m_y; - - if (m_truncation == cFullTruncation) - return; - - int width = m_width - 1; - if (m_truncation != cNoTruncation) { - width = static_cast<RenderText*>(m_object)->width(m_start, m_truncation - m_start, m_firstLine); - } - - RenderObject *p = object(); - - TQColor underline, overline, linethrough; - p->getTextDecorationColors(deco, underline, overline, linethrough, p->style()->htmlHacks()); - - if(deco & UNDERLINE){ - pt->setPen(underline); - f->drawDecoration(pt, _tx, _ty, baseline(), width, height(), Font::UNDERLINE); - } - if (deco & OVERLINE) { - pt->setPen(overline); - f->drawDecoration(pt, _tx, _ty, baseline(), width, height(), Font::OVERLINE); - } - if(deco & LINE_THROUGH) { - pt->setPen(linethrough); - f->drawDecoration(pt, _tx, _ty, baseline(), width, height(), Font::LINE_THROUGH); - } - // NO! Do NOT add BLINK! It is the most annouing feature of Netscape, and IE has a reason not to - // support it. Lars -} - -void InlineTextBox::paintShadow(TQPainter *pt, const Font *f, int _tx, int _ty, const ShadowData *shadow ) -{ - int x = m_x + _tx + shadow->x; - int y = m_y + _ty + shadow->y; - const RenderText* text = renderText(); - - if (shadow->blur <= 0) { - TQColor c = pt->pen().color(); - pt->setPen(shadow->color); - f->drawText(pt, x, y+m_baseline, text->str->s, text->str->l, - m_start, m_len, m_toAdd, - m_reversed ? TQPainter::RTL : TQPainter::LTR); - pt->setPen(c); - - } - else { - const int thickness = shadow->blur; - const int w = m_width+2*thickness; - const int h = m_height+2*thickness; - const TQRgb color = shadow->color.rgb(); - const int gray = tqGray(color); - const bool inverse = (gray < 100); - const TQRgb bgColor = (inverse) ? tqRgb(255,255,255) : tqRgb(0,0,0); - TQPixmap pixmap(w, h); - pixmap.fill(bgColor); - TQPainter p; - - p.begin(&pixmap); - p.setPen(shadow->color); - p.setFont(pt->font()); - f->drawText(&p, thickness, thickness+m_baseline, text->str->s, text->str->l, - m_start, m_len, m_toAdd, - m_reversed ? TQPainter::RTL : TQPainter::LTR); - - p.end(); - TQImage img = TQT_TQIMAGE_OBJECT(pixmap.convertToImage()).convertDepth(32); - - int md = thickness*thickness; // max-dist^2 - - // blur map (division cache) - float *bmap = (float*)alloca(sizeof(float)*(md+1)); - for(int n=0; n<=md; n++) { - float f; - f = n/(float)(md+1); - f = 1.0 - f*f; - bmap[n] = f; - } - - float factor = 0.0; // maximal potential opacity-sum - for(int n=-thickness; n<=thickness; n++) - for(int m=-thickness; m<=thickness; m++) { - int d = n*n+m*m; - if (d<=md) - factor += bmap[d]; - } - - // arbitratry factor adjustment to make shadows solid. - factor = factor/1.333; - - // alpha map - float* amap = (float*)alloca(sizeof(float)*(h*w)); - memset(amap, 0, h*w*(sizeof(float))); - for(int j=thickness; j<h-thickness; j++) { - for(int i=thickness; i<w-thickness; i++) { - TQRgb col= img.pixel(i,j); - if (col == bgColor) continue; - float g = tqGray(col); - if (inverse) - g = (255-g)/(255-gray); - else - g = g/gray; - for(int n=-thickness; n<=thickness; n++) { - for(int m=-thickness; m<=thickness; m++) { - int d = n*n+m*m; - if (d>md) continue; - float f = bmap[d]; - amap[(i+m)+(j+n)*w] += (g*f); - } - } - } - } - - TQImage res(w,h,32); - res.setAlphaBuffer(true); - int r = tqRed(color); - int g = tqGreen(color); - int b = tqBlue(color); - - // divide by factor - factor = 1.0/factor; - - for(int j=0; j<h; j++) { - for(int i=0; i<w; i++) { - int a = (int)(amap[i+j*w] * factor * 255.0); - if (a > 255) a = 255; - res.setPixel(i,j, tqRgba(r,g,b,a)); - } - } - - pt->drawImage(x-thickness, y-thickness, res, 0, 0, -1, -1, Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::PreferDither); - } - // Paint next shadow effect - if (shadow->next) paintShadow(pt, f, _tx, _ty, shadow->next); -} - -/** - * Distributes pixels to justify text. - * @param numSpaces spaces left, will be decremented by one - * @param toAdd number of pixels left to be distributed, will have the - * amount of pixels distributed during this call subtracted. - * @return number of pixels to distribute - */ -static inline int justifyWidth(int &numSpaces, int &toAdd) { - int a = 0; - if ( numSpaces ) { - a = toAdd/numSpaces; - toAdd -= a; - numSpaces--; - }/*end if*/ - return a; -} - -FindSelectionResult InlineTextBox::checkSelectionPoint(int _x, int _y, int _tx, int _ty, const Font *f, RenderText *text, int & offset, short lineHeight) -{ -// kdDebug(6040) << "InlineTextBox::checkSelectionPoint " << this << " _x=" << _x << " _y=" << _y -// << " _tx+m_x=" << _tx+m_x << " _ty+m_y=" << _ty+m_y << endl; - offset = 0; - - if ( _y < _ty + m_y ) - return SelectionPointBefore; // above -> before - - if ( _y > _ty + m_y + lineHeight ) { - // below -> after - // Set the offset to the max - offset = m_len; - return SelectionPointAfter; - } - if ( _x > _tx + m_x + m_width ) { - // to the right - return SelectionPointAfterInLine; - } - - // The Y matches, check if we're on the left - if ( _x < _tx + m_x ) { - return SelectionPointBeforeInLine; - } - - // consider spacing for justified text - int toAdd = m_toAdd; - bool justified = text->style()->textAlign() == JUSTIFY && toAdd > 0; - int numSpaces = 0; - if (justified) { - - for( int i = 0; i < m_len; i++ ) - if ( text->str->s[m_start+i].category() == TQChar::Separator_Space ) - numSpaces++; - - }/*end if*/ - - int delta = _x - (_tx + m_x); - //kdDebug(6040) << "InlineTextBox::checkSelectionPoint delta=" << delta << endl; - int pos = 0; - if ( m_reversed ) { - delta -= m_width; - while(pos < m_len) { - int w = f->width( text->str->s, text->str->l, m_start + pos); - if (justified && text->str->s[m_start + pos].category() == TQChar::Separator_Space) - w += justifyWidth(numSpaces, toAdd); - int w2 = w/2; - w -= w2; - delta += w2; - if(delta >= 0) break; - pos++; - delta += w; - } - } else { - while(pos < m_len) { - int w = f->width( text->str->s, text->str->l, m_start + pos); - if (justified && text->str->s[m_start + pos].category() == TQChar::Separator_Space) - w += justifyWidth(numSpaces, toAdd); - int w2 = w/2; - w -= w2; - delta -= w2; - if(delta <= 0) break; - pos++; - delta -= w; - } - } -// kdDebug( 6040 ) << " Text --> inside at position " << pos << endl; - offset = pos; - return SelectionPointInside; -} - -int InlineTextBox::offsetForPoint(int _x, int &ax) const -{ - // Do binary search for finding out offset, saves some time for long - // runs. - int start = 0; - int end = m_len; - ax = m_x; - int offset = (start + end) / 2; - while (end - start > 0) { - // always snap to the right column. This makes up for "jumpy" vertical - // navigation. - if (end - start == 1) start = end; - - offset = (start + end) / 2; - ax = m_x + widthFromStart(offset); - if (ax > _x) end = offset; - else if (ax < _x) start = offset; - else break; - } - return m_start + offset; -} - -int InlineTextBox::widthFromStart(int pos) const -{ - // gasp! sometimes pos is i < 0 which crashes Font::width - pos = kMax(pos, 0); - - const RenderText *t = renderText(); - Q_ASSERT(t->isText()); - const Font *f = t->htmlFont(m_firstLine); - const TQFontMetrics &fm = t->fontMetrics(m_firstLine); - - int numSpaces = 0; - // consider spacing for justified text - bool justified = t->style()->textAlign() == JUSTIFY; - //kdDebug(6000) << "InlineTextBox::width(int)" << endl; - if (justified && m_toAdd > 0) do { - //kdDebug(6000) << "justify" << endl; - -// TQConstString cstr = TQConstString(t->str->s + m_start, m_len); - for( int i = 0; i < m_len; i++ ) - if ( t->str->s[m_start+i].category() == TQChar::Separator_Space ) - numSpaces++; - if (numSpaces == 0) break; - - int toAdd = m_toAdd; - int w = 0; // accumulated width - int start = 0; // start of non-space sequence - int current = 0; // current position - while (current < pos) { - // add spacing - while (current < pos && t->str->s[m_start + current].category() == TQChar::Separator_Space) { - w += f->getWordSpacing(); - w += f->getLetterSpacing(); - w += justifyWidth(numSpaces, toAdd); - w += fm.width(' '); // ### valid assumption? (LS) - current++; start++; - }/*wend*/ - if (current >= pos) break; - - // seek next space - while (current < pos && t->str->s[m_start + current].category() != TQChar::Separator_Space) - current++; - - // check run without spaces - if ( current > start ) { - w += f->width(t->str->s + m_start, m_len, start, current - start); - start = current; - } - } - - return w; - - } while(false);/*end if*/ - - //kdDebug(6000) << "default" << endl; - // else use existing width function - return f->width(t->str->s + m_start, m_len, 0, pos); - -} - -long InlineTextBox::minOffset() const -{ - return m_start; -} - -long InlineTextBox::maxOffset() const -{ - return m_start + m_len; -} - -int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) -{ - if (foundBox) { - m_truncation = cFullTruncation; - return -1; - } - - int ellipsisX = ltr ? blockEdge - ellipsisWidth : blockEdge + ellipsisWidth; - - // For LTR, if the left edge of the ellipsis is to the left of our text run, then we are the run that will get truncated. - if (ltr) { - if (ellipsisX <= m_x) { - // Too far. Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box. - m_truncation = cFullTruncation; - foundBox = true; - return -1; - } - - if (ellipsisX < m_x + m_width) { - if (m_reversed) - return -1; // FIXME: Support LTR truncation when the last run is RTL someday. - - foundBox = true; - - int ax; - int offset = offsetForPoint(ellipsisX, ax) - 1; - if (offset <= m_start) { - // No characters should be rendered. Set ourselves to full truncation and place the ellipsis at the min of our start - // and the ellipsis edge. - m_truncation = cFullTruncation; - return kMin(ellipsisX, (int)m_x); - } - - // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character. - m_truncation = offset; - return widthFromStart(offset - m_start); - } - } - else { - // FIXME: Support RTL truncation someday, including both modes (when the leftmost run on the line is either RTL or LTR) - } - return -1; -} - -// ----------------------------------------------------------------------------- - -InlineTextBoxArray::InlineTextBoxArray() -{ - setAutoDelete(false); -} - -int InlineTextBoxArray::compareItems( Item d1, Item d2 ) -{ - assert(d1); - assert(d2); - - return static_cast<InlineTextBox*>(d1)->m_y - static_cast<InlineTextBox*>(d2)->m_y; -} - -// remove this once TQVector::bsearch is fixed -int InlineTextBoxArray::findFirstMatching(Item d) const -{ - int len = count(); - - if ( !len ) - return -1; - if ( !d ) - return -1; - int n1 = 0; - int n2 = len - 1; - int mid = 0; - bool found = false; - while ( n1 <= n2 ) { - int res; - mid = (n1 + n2)/2; - if ( (*this)[mid] == 0 ) // null item greater - res = -1; - else - res = ((TQGVector*)this)->compareItems( d, (*this)[mid] ); - if ( res < 0 ) - n2 = mid - 1; - else if ( res > 0 ) - n1 = mid + 1; - else { // found it - found = true; - break; - } - } - /* if ( !found ) - return -1; */ - // search to first one equal or bigger - while ( found && (mid > 0) && !((TQGVector*)this)->compareItems(d, (*this)[mid-1]) ) - mid--; - return mid; -} - -// ------------------------------------------------------------------------------------- - -RenderText::RenderText(DOM::NodeImpl* node, DOMStringImpl *_str) - : RenderObject(node) -{ - // init RenderObject attributes - setRenderText(); // our object inherits from RenderText - - m_minWidth = -1; - m_maxWidth = -1; - str = _str; - if(str) str->ref(); - KHTMLAssert(!str || !str->l || str->s); - - m_selectionState = SelectionNone; - m_hasReturn = true; - -#ifdef DEBUG_LAYOUT - TQConstString cstr(str->s, str->l); - kdDebug( 6040 ) << "RenderText ctr( "<< cstr.string().length() << " ) '" << cstr.string() << "'" << endl; -#endif -} - -void RenderText::setStyle(RenderStyle *_style) -{ - if ( style() != _style ) { - bool changedText = ((!style() && ( _style->textTransform() != TTNONE || - !_style->preserveLF() || !_style->preserveWS() )) || - (style() && (style()->textTransform() != _style->textTransform() || - style()->whiteSpace() != _style->whiteSpace()))); - - RenderObject::setStyle( _style ); - m_lineHeight = RenderObject::lineHeight(false); - - if (!isBR() && changedText) { - DOM::DOMStringImpl* textToTransform = originalString(); - if (textToTransform) - setText(textToTransform, true); - } - } -} - -RenderText::~RenderText() -{ - KHTMLAssert(m_lines.count() == 0); - if(str) str->deref(); -} - -void RenderText::deleteInlineBoxes(RenderArena* arena) -{ - // this is a slight variant of TQArray::clear(). - // We don't delete the array itself here because its - // likely to be used in the same size later again, saves - // us resize() calls - unsigned int len = m_lines.size(); - if (len) { - if (!arena) - arena = renderArena(); - for(unsigned int i=0; i < len; i++) { - InlineTextBox* s = m_lines.at(i); - if (s) - s->detach(arena); - m_lines.remove(i); - } - } - - KHTMLAssert(m_lines.count() == 0); -} - -bool RenderText::isTextFragment() const -{ - return false; -} - -DOM::DOMStringImpl* RenderText::originalString() const -{ - return element() ? element()->string() : 0; -} - -InlineTextBox * RenderText::findInlineTextBox( int offset, int &pos, bool checkFirstLetter ) -{ - // The text boxes point to parts of the rendertext's str string - // (they don't include '\n') - // Find the text box that includes the character at @p offset - // and return pos, which is the position of the char in the run. - - // FIXME: make this use binary search? Dirk says it won't work :-( (LS) - (void)checkFirstLetter; -#if 0 - if (checkFirstLetter && forcedMinOffset()) { -// kdDebug(6040) << "checkFirstLetter: forcedMinOffset: " << forcedMinOffset() << endl; - RenderFlow *firstLetter = static_cast<RenderFlow *>(previousSibling()); - if (firstLetter && firstLetter->isFlow() && firstLetter->isFirstLetter()) { - RenderText *letterText = static_cast<RenderText *>(firstLetter->firstChild()); - //kdDebug(6040) << "lettertext: " << letterText << " minOfs: " << letterText->minOffset() << " maxOfs: " << letterText->maxOffset() << endl; - if (offset >= letterText->minOffset() && offset <= letterText->maxOffset()) { - InlineTextBox *result = letterText->findInlineTextBox(offset, pos, false); - //kdDebug(6040) << "result: " << result << endl; - if (result) return result; - } - } - } -#endif - - if ( m_lines.isEmpty() ) - return 0L; - - // The text boxes don't resemble a contiguous coverage of the text, there - // may be holes. Therefore, we snap to the nearest previous text box if - // the given offset happens to point to such a hole. - - InlineTextBox* s = m_lines[0]; - uint count = m_lines.count(); - uint si = 0; - uint nearest_idx = 0; // index of nearest text box - int nearest = INT_MAX; // nearest distance -//kdDebug(6040) << "s[" << si << "] m_start " << s->m_start << " m_end " << (s->m_start + s->m_len) << endl; - while(!(offset >= s->m_start && offset <= s->m_start + s->m_len) - && ++si < count) - { - int dist = offset - (s->m_start + s->m_len); -//kdDebug(6040) << "dist " << dist << " nearest " << nearest << endl; - if (dist >= 0 && dist <= nearest) { - nearest = dist; - nearest_idx = si - 1; - }/*end if*/ - s = m_lines[si]; -//kdDebug(6040) << "s[" << si << "] m_start " << s->m_start << " m_end " << (s->m_start + s->m_len) << endl; - } -//kdDebug(6040) << "nearest_idx " << nearest_idx << " count " << count << endl; - if (si >= count) s = m_lines[nearest_idx]; - // we are now in the correct text box - pos = kMin(offset - s->m_start, int( s->m_len )); - //kdDebug(6040) << "offset=" << offset << " s->m_start=" << s->m_start << endl; - return s; -} - -bool RenderText::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction /*hitTestAction*/, bool /*inBox*/) -{ - assert(parent()); - - bool inside = false; - if (style()->visibility() != HIDDEN) { - InlineTextBox *s = m_lines.count() ? m_lines[0] : 0; - int si = 0; - while(s) { - if((_y >=_ty + s->m_y) && (_y < _ty + s->m_y + s->m_height) && - (_x >= _tx + s->m_x) && (_x <_tx + s->m_x + s->m_width) ) { - inside = true; - break; - } - - s = si < (int) m_lines.count()-1 ? m_lines[++si] : 0; - } - } - - // #### ported over from Safari. Can this happen at all? (lars) - - if (inside && element()) { - if (info.innerNode() && info.innerNode()->renderer() && - !info.innerNode()->renderer()->isInline()) { - // Within the same layer, inlines are ALWAYS fully above blocks. Change inner node. - info.setInnerNode(element()); - - // Clear everything else. - info.setInnerNonSharedNode(0); - info.setURLElement(0); - } - - if (!info.innerNode()) - info.setInnerNode(element()); - - if(!info.innerNonSharedNode()) - info.setInnerNonSharedNode(element()); - } - - return inside; -} - -FindSelectionResult RenderText::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset, SelPointState &) -{ -// kdDebug(6040) << "RenderText::checkSelectionPoint " << this << " _x=" << _x << " _y=" << _y -// << " _tx=" << _tx << " _ty=" << _ty << endl; -//kdDebug(6040) << renderName() << "::checkSelectionPoint x=" << xPos() << " y=" << yPos() << " w=" << width() << " h=" << height() << " m_lines.count=" << m_lines.count() << endl; - - NodeImpl *lastNode = 0; - int lastOffset = 0; - FindSelectionResult lastResult = SelectionPointAfter; - - for(unsigned int si = 0; si < m_lines.count(); si++) - { - InlineTextBox* s = m_lines[si]; - FindSelectionResult result; - const Font *f = htmlFont( si==0 ); - result = s->checkSelectionPoint(_x, _y, _tx, _ty, f, this, offset, m_lineHeight); - -// kdDebug(6040) << "RenderText::checkSelectionPoint " << this << " line " << si << " result=" << result << " offset=" << offset << endl; - if ( result == SelectionPointInside ) // x,y is inside the textrun - { - offset += s->m_start; // add the offset from the previous lines -// kdDebug(6040) << "RenderText::checkSelectionPoint inside -> " << offset << endl; - node = element(); - return SelectionPointInside; - } else if ( result == SelectionPointBefore ) { - if (!lastNode) { - // x,y is before the textrun -> stop here - offset = 0; -// kdDebug(6040) << "RenderText::checkSelectionPoint " << this << "before us -> returning Before" << endl; - node = element(); - return SelectionPointBefore; - } - } else if ( result == SelectionPointBeforeInLine ) { - offset = s->m_start; - node = element(); - return SelectionPointInside; - } else if ( result == SelectionPointAfterInLine ) { - lastOffset = s->m_start + s->m_len; - lastNode = element(); - lastResult = result; - // no return here - } - - } - - if (lastNode) { - offset = lastOffset; - node = lastNode; -// kdDebug(6040) << "RenderText::checkSelectionPoint: lastNode " << lastNode << " lastOffset " << lastOffset << endl; - return lastResult; - } - - // set offset to max - offset = str->l; - //tqDebug("setting node to %p", element()); - node = element(); -// kdDebug(6040) << "RenderText::checkSelectionPoint: node " << node << " offset " << offset << endl; - return SelectionPointAfter; -} - -void RenderText::caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) -{ - if (!m_lines.count()) { - _x = _y = height = -1; - width = 1; - return; - } - - int pos; - InlineTextBox * s = findInlineTextBox( offset, pos, true ); - RenderText *t = s->renderText(); -// kdDebug(6040) << "offset="<<offset << " pos="<<pos << endl; - - const TQFontMetrics &fm = t->metrics( s->m_firstLine ); - height = fm.height(); // s->m_height; - - _x = s->m_x + s->widthFromStart(pos); - _y = s->m_y + s->baseline() - fm.ascent(); - width = 1; - if (flags & CFOverride) { - width = offset < maxOffset() ? fm.width(str->s[offset]) : 1; - }/*end if*/ -#if 0 - kdDebug(6040) << "_x="<<_x << " s->m_x="<<s->m_x - << " s->m_start"<<s->m_start - << " s->m_len" << s->m_len << " _y=" << _y << endl; -#endif - - int absx, absy; - - if (absolutePosition(absx,absy)) - { - //kdDebug(6040) << "absx=" << absx << " absy=" << absy << endl; - _x += absx; - _y += absy; - } else { - // we don't know our absolute position, and there is no point returning - // just a relative one - _x = _y = -1; - } -} - -long RenderText::minOffset() const -{ - if (!m_lines.count()) return 0; - // FIXME: it is *not* guaranteed that the first run contains the lowest offset - // Either make this a linear search (slow), - // or maintain an index (needs much mem), - // or calculate and store it in bidi.cpp (needs calculation even if not needed) - // (LS) - return m_lines[0]->m_start; -} - -long RenderText::maxOffset() const -{ - int count = m_lines.count(); - if (!count) return str->l; - // FIXME: it is *not* guaranteed that the last run contains the highest offset - // Either make this a linear search (slow), - // or maintain an index (needs much mem), - // or calculate and store it in bidi.cpp (needs calculation even if not needed) - // (LS) - return m_lines[count - 1]->m_start + m_lines[count - 1]->m_len; -} - -bool RenderText::absolutePosition(int &xPos, int &yPos, bool) const -{ - return RenderObject::absolutePosition(xPos, yPos, false); -} - -bool RenderText::posOfChar(int chr, int &x, int &y) -{ - if (!parent()) - return false; - parent()->absolutePosition( x, y, false ); - - int pos; - InlineTextBox * s = findInlineTextBox( chr, pos ); - - if ( s ) { - // s is the line containing the character - x += s->m_x; // this is the x of the beginning of the line, but it's good enough for now - y += s->m_y; - return true; - } - - return false; -} - -void RenderText::paint( PaintInfo& /*pI*/, int /*tx*/, int /*ty*/) -{ - KHTMLAssert( false ); -} - -void RenderText::calcMinMaxWidth() -{ - KHTMLAssert( !minMaxKnown() ); - - // ### calc Min and Max width... - m_minWidth = m_beginMinWidth = m_endMinWidth = 0; - m_maxWidth = 0; - - if (isBR()) - return; - - int currMinWidth = 0; - int currMaxWidth = 0; - m_hasBreakableChar = m_hasBreak = m_hasBeginWS = m_hasEndWS = false; - - // ### not 100% correct for first-line - const Font *f = htmlFont( false ); - int wordSpacing = style()->wordSpacing(); - int len = str->l; - bool isSpace = false; - bool firstWord = true; - bool firstLine = true; - for(int i = 0; i < len; i++) - { - unsigned short c = str->s[i].unicode(); - bool isNewline = false; - - // If line-breaks survive to here they are preserved - if ( c == '\n' ) { - m_hasBreak = true; - isNewline = true; - isSpace = false; - } else - isSpace = c == ' '; - - if ((isSpace || isNewline) && i == 0) - m_hasBeginWS = true; - if ((isSpace || isNewline) && i == len-1) - m_hasEndWS = true; - - if (i && c == SOFT_HYPHEN) - continue; - - int wordlen = 0; - while( i+wordlen < len && (i+wordlen == 0 || str->s[i+wordlen].unicode() != SOFT_HYPHEN) && - !(isBreakable( str->s, i+wordlen, str->l )) ) - wordlen++; - - if (wordlen) - { -#ifndef APPLE_CHANGES - int w = f->width(str->s, str->l, i, wordlen); -#else - int w = widthFromCache(f, i, wordlen); -#endif - currMinWidth += w; - currMaxWidth += w; - - // Add in wordspacing to our maxwidth, but not if this is the last word. - if (wordSpacing && !containsOnlyWhitespace(i+wordlen, len-(i+wordlen))) - currMaxWidth += wordSpacing; - - if (firstWord) { - firstWord = false; - m_beginMinWidth = w; - } - m_endMinWidth = w; - - if(currMinWidth > m_minWidth) m_minWidth = currMinWidth; - currMinWidth = 0; - - i += wordlen-1; - } - else { - // Nowrap can never be broken, so don't bother setting the - // breakable character boolean. Pre can only be broken if we encounter a newline. - if (style()->autoWrap() || isNewline) - m_hasBreakableChar = true; - - if(currMinWidth > m_minWidth) m_minWidth = currMinWidth; - currMinWidth = 0; - - if (isNewline) // Only set if isPre was true and we saw a newline. - { - if ( firstLine ) { - firstLine = false; - m_beginMinWidth = currMaxWidth; - } - - if(currMaxWidth > m_maxWidth) m_maxWidth = currMaxWidth; - currMaxWidth = 0; - } - else - { - currMaxWidth += f->width( str->s, str->l, i + wordlen ); - } - } - } - - if(currMinWidth > m_minWidth) m_minWidth = currMinWidth; - if(currMaxWidth > m_maxWidth) m_maxWidth = currMaxWidth; - - if (!style()->autoWrap()) { - m_minWidth = m_maxWidth; - if (style()->preserveLF()) { - if (firstLine) - m_beginMinWidth = m_maxWidth; - m_endMinWidth = currMaxWidth; - } - } - - setMinMaxKnown(); - //kdDebug( 6040 ) << "Text::calcMinMaxWidth(): min = " << m_minWidth << " max = " << m_maxWidth << endl; - -} - -int RenderText::minXPos() const -{ - if (!m_lines.count()) - return 0; - int retval=6666666; - for (unsigned i=0;i < m_lines.count(); i++) - { - retval = kMin ( retval, int( m_lines[i]->m_x )); - } - return retval; -} - -int RenderText::inlineXPos() const -{ - return minXPos(); -} - -int RenderText::inlineYPos() const -{ - return m_lines.isEmpty() ? 0 : m_lines[0]->yPos(); -} - -const TQFont &RenderText::font() -{ - return style()->font(); -} - -void RenderText::setText(DOMStringImpl *text, bool force) -{ - if( !force && str == text ) return; - - DOMStringImpl *oldstr = str; - if(text && style()) - str = text->collapseWhiteSpace(style()->preserveLF(), style()->preserveWS()); - else - str = text; - if(str) str->ref(); - if(oldstr) oldstr->deref(); - - if ( str && style() ) { - oldstr = str; - switch(style()->textTransform()) { - case CAPITALIZE: - { - RenderObject *o; - bool runOnString = false; - - // find previous non-empty text renderer if one exists - for (o = previousRenderer(); o; o = o->previousRenderer()) { - if (!o->isInlineFlow()) { - if (!o->isText()) - break; - - DOMStringImpl *prevStr = static_cast<RenderText*>(o)->string(); - // !prevStr can happen with css like "content:open-quote;" - if (!prevStr) - break; - - if (prevStr->length() == 0) - continue; - TQChar c = (*prevStr)[prevStr->length() - 1]; - if (!c.isSpace()) - runOnString = true; - - break; - } - } - - str = str->capitalize(runOnString); - } - break; - - - - case UPPERCASE: str = str->upper(); break; - case LOWERCASE: str = str->lower(); break; - case NONE: - default:; - } - str->ref(); - oldstr->deref(); - } - - // ### what should happen if we change the text of a - // RenderBR object ? - KHTMLAssert(!isBR() || (str->l == 1 && (*str->s) == '\n')); - KHTMLAssert(!str->l || str->s); - - setNeedsLayoutAndMinMaxRecalc(); -#ifdef BIDI_DEBUG - TQConstString cstr(str->s, str->l); - kdDebug( 6040 ) << "RenderText::setText( " << cstr.string().length() << " ) '" << cstr.string() << "'" << endl; -#endif -} - -int RenderText::height() const -{ - int retval; - if ( m_lines.count() ) - retval = m_lines[m_lines.count()-1]->m_y + m_lineHeight - m_lines[0]->m_y; - else - retval = metrics( false ).height(); - - return retval; -} - -short RenderText::lineHeight( bool firstLine ) const -{ - if ( firstLine ) - return RenderObject::lineHeight( firstLine ); - - return m_lineHeight; -} - -short RenderText::baselinePosition( bool firstLine ) const -{ - const TQFontMetrics &fm = metrics( firstLine ); - return fm.ascent() + - ( lineHeight( firstLine ) - fm.height() ) / 2; -} - -InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox) -{ - KHTMLAssert( !isRootLineBox ); - return new (renderArena()) InlineTextBox(this); -} - -void RenderText::position(InlineBox* box, int from, int len, bool reverse) -{ -//kdDebug(6040) << "position: from="<<from<<" len="<<len<<endl; - // ### should not be needed!!! - // asserts sometimes with pre (that unibw-hamburg testcase). ### find out why - //KHTMLAssert(!(len == 0 || (str->l && len == 1 && *(str->s+from) == '\n') )); - // It is now needed. BRs need text boxes too otherwise caret navigation - // gets stuck (LS) - // if (len == 0 || (str->l && len == 1 && *(str->s+from) == '\n') ) return; - - reverse = reverse && !style()->visuallyOrdered(); - -#ifdef DEBUG_LAYOUT - TQChar *ch = str->s+from; - TQConstString cstr(ch, len); -#endif - - KHTMLAssert(box->isInlineTextBox()); - InlineTextBox *s = static_cast<InlineTextBox *>(box); - s->m_start = from; - s->m_len = len; - s->m_reversed = reverse; - //kdDebug(6040) << "m_start: " << s->m_start << " m_len: " << s->m_len << endl; - - if(m_lines.count() == m_lines.size()) - m_lines.resize(m_lines.size()*2+1); - - m_lines.insert(m_lines.count(), s); - //kdDebug(6040) << this << " " << renderName() << "::position inserted" << endl; -} - -unsigned int RenderText::width(unsigned int from, unsigned int len, bool firstLine) const -{ - if(!str->s || from > str->l ) return 0; - if ( from + len > str->l ) len = str->l - from; - - const Font *f = htmlFont( firstLine ); - return width( from, len, f ); -} - -unsigned int RenderText::width(unsigned int from, unsigned int len, const Font *f) const -{ - if(!str->s || from > str->l ) return 0; - if ( from + len > str->l ) len = str->l - from; - - if ( f == &style()->htmlFont() && from == 0 && len == str->l ) - return m_maxWidth; - - int w = f->width(str->s, str->l, from, len ); - - //kdDebug( 6040 ) << "RenderText::width(" << from << ", " << len << ") = " << w << endl; - return w; -} - -short RenderText::width() const -{ - int w; - int minx = 100000000; - int maxx = 0; - // slooow - for(unsigned int si = 0; si < m_lines.count(); si++) { - InlineTextBox* s = m_lines[si]; - if(s->m_x < minx) - minx = s->m_x; - if(s->m_x + s->m_width > maxx) - maxx = s->m_x + s->m_width; - } - - w = kMax(0, maxx-minx); - - return w; -} - -void RenderText::repaint(Priority p) -{ - RenderObject *cb = containingBlock(); - if(cb) - cb->repaint(p); -} - -bool RenderText::isFixedWidthFont() const -{ - return TQFontInfo(style()->font()).fixedPitch(); -} - -short RenderText::verticalPositionHint( bool firstLine ) const -{ - return parent()->verticalPositionHint( firstLine ); -} - -const TQFontMetrics &RenderText::metrics(bool firstLine) const -{ - if( firstLine && hasFirstLine() ) { - RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LINE); - if ( pseudoStyle ) - return pseudoStyle->fontMetrics(); - } - return style()->fontMetrics(); -} - -const Font *RenderText::htmlFont(bool firstLine) const -{ - const Font *f = 0; - if( firstLine && hasFirstLine() ) { - RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LINE); - if ( pseudoStyle ) - f = &pseudoStyle->htmlFont(); - } else { - f = &style()->htmlFont(); - } - return f; -} - -bool RenderText::containsOnlyWhitespace(unsigned int from, unsigned int len) const -{ - unsigned int currPos; - for (currPos = from; - currPos < from+len && (str->s[currPos] == '\n' || str->s[currPos].direction() == TQChar::DirWS); - currPos++); - return currPos >= (from+len); -} - -void RenderText::trimmedMinMaxWidth(short& beginMinW, bool& beginWS, - short& endMinW, bool& endWS, - bool& hasBreakableChar, bool& hasBreak, - short& beginMaxW, short& endMaxW, - short& minW, short& maxW, bool& stripFrontSpaces) -{ - bool preserveWS = style()->preserveWS(); - bool preserveLF = style()->preserveLF(); - bool autoWrap = style()->autoWrap(); - if (preserveWS) - stripFrontSpaces = false; - - int len = str->l; - if (len == 0 || (stripFrontSpaces && str->containsOnlyWhitespace())) { - maxW = 0; - hasBreak = false; - return; - } - - minW = m_minWidth; - maxW = m_maxWidth; - beginWS = stripFrontSpaces ? false : m_hasBeginWS; - endWS = m_hasEndWS; - - beginMinW = m_beginMinWidth; - endMinW = m_endMinWidth; - - hasBreakableChar = m_hasBreakableChar; - hasBreak = m_hasBreak; - - if (stripFrontSpaces && (str->s[0].direction() == TQChar::DirWS || (!preserveLF && str->s[0] == '\n'))) { - const Font *f = htmlFont( false ); - TQChar space[1]; space[0] = ' '; - int spaceWidth = f->width(space, 1, 0); - maxW -= spaceWidth; - } - - stripFrontSpaces = !preserveWS && m_hasEndWS; - - if (!autoWrap) - minW = maxW; - else if (minW > maxW) - minW = maxW; - - // Compute our max widths by scanning the string for newlines. - if (hasBreak) { - const Font *f = htmlFont( false ); - bool firstLine = true; - beginMaxW = endMaxW = maxW; - for(int i = 0; i < len; i++) - { - int linelen = 0; - while( i+linelen < len && str->s[i+linelen] != '\n') - linelen++; - - if (linelen) - { -#ifndef APPLE_CHANGES - endMaxW = f->width(str->s, str->l, i, linelen); -#else - endMaxW = widthFromCache(f, i, linelen); -#endif - if (firstLine) { - firstLine = false; - beginMaxW = endMaxW; - } - i += linelen; - } - else if (firstLine) { - beginMaxW = 0; - firstLine = false; - } - if (i == len-1) - // A <pre> run that ends with a newline, as in, e.g., - // <pre>Some text\n\n<span>More text</pre> - endMaxW = 0; - } - } -} - -#ifdef ENABLE_DUMP - -static TQString quoteAndEscapeNonPrintables(const TQString &s) -{ - TQString result; - result += '"'; - for (uint i = 0; i != s.length(); ++i) { - TQChar c = s.at(i); - if (c == '\\') { - result += "\\\\"; - } else if (c == '"') { - result += "\\\""; - } else { - ushort u = c.unicode(); - if (u >= 0x20 && u < 0x7F) { - result += c; - } else { - TQString hex; - hex.sprintf("\\x{%X}", u); - result += hex; - } - } - } - result += '"'; - return result; -} - -static void writeTextRun(TQTextStream &ts, const RenderText &o, const InlineTextBox &run) -{ - ts << "text run at (" << run.m_x << "," << run.m_y << ") width " << run.m_width << ": " - << quoteAndEscapeNonPrintables(o.data().string().mid(run.m_start, run.m_len)); -} - -void RenderText::dump(TQTextStream &stream, const TQString &ind) const -{ - RenderObject::dump( stream, ind ); - - for (unsigned int i = 0; i < m_lines.count(); i++) { - stream << endl << ind << " "; - writeTextRun(stream, *this, *m_lines[i]); - } -} -#endif - -RenderTextFragment::RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str, - int startOffset, int endOffset) -:RenderText(_node, _str->substring(startOffset, endOffset)), -m_start(startOffset), m_end(endOffset), m_generatedContentStr(0) -{} - -RenderTextFragment::RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str) -:RenderText(_node, _str), m_start(0) -{ - m_generatedContentStr = _str; - if (_str) { - _str->ref(); - m_end = _str->l; - } - else - m_end = 0; -} - -RenderTextFragment::~RenderTextFragment() -{ - if (m_generatedContentStr) - m_generatedContentStr->deref(); -} - -bool RenderTextFragment::isTextFragment() const -{ - return true; -} - -DOM::DOMStringImpl* RenderTextFragment::originalString() const -{ - DOM::DOMStringImpl* result = 0; - if (element()) - result = element()->string(); - else - result = contentString(); - if (result && (start() > 0 || start() < result->l)) - result = result->substring(start(), end()); - return result; -} - -#undef BIDI_DEBUG -#undef DEBUG_LAYOUT diff --git a/khtml/rendering/render_text.h b/khtml/rendering/render_text.h deleted file mode 100644 index 50132fbc7..000000000 --- a/khtml/rendering/render_text.h +++ /dev/null @@ -1,345 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2003 Apple Computer, 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., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ -#ifndef RENDERTEXT_H -#define RENDERTEXT_H - -#include "dom/dom_string.h" -#include "xml/dom_stringimpl.h" -#include "xml/dom_textimpl.h" -#include "rendering/render_object.h" -#include "rendering/render_line.h" - -#include <tqptrvector.h> -#include <assert.h> - -class TQPainter; -class TQFontMetrics; - -// Define a constant for soft hyphen's unicode value. -#define SOFT_HYPHEN 173 - -const int cNoTruncation = -1; -const int cFullTruncation = -2; - -namespace khtml -{ - class RenderText; - class RenderStyle; - -class InlineTextBox : public InlineBox -{ -public: - InlineTextBox(RenderObject *obj) - :InlineBox(obj), - // ### necessary as some codepaths (<br>) do *not* initialize these (LS) - m_start(0), m_len(0), m_truncation(cNoTruncation), m_reversed(false), m_toAdd(0) - { - } - - void detach(RenderArena* renderArena); - - virtual void clearTruncation() { m_truncation = cNoTruncation; } - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox); - - // Overloaded new operator. Derived classes must override operator new - // in order to allocate out of the RenderArena. - void* operator new(size_t sz, RenderArena* renderArena) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* ptr, size_t sz); - -private: - // The normal operator new is disallowed. - void* operator new(size_t sz) throw(); - -public: - void setSpaceAdd(int add) { m_width -= m_toAdd; m_toAdd = add; m_width += m_toAdd; } - int spaceAdd() { return m_toAdd; } - - virtual bool isInlineTextBox() const { return true; } - - void paint(RenderObject::PaintInfo& i, int tx, int ty); - void paintDecoration(TQPainter *pt, const Font *f, int _tx, int _ty, int decoration); - void paintShadow(TQPainter *pt, const Font* f, int _tx, int _ty, const ShadowData *shadow ); - void paintSelection(const Font *f, RenderText *text, TQPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos, int deco); - - void selectionStartEnd(int& sPos, int& ePos); - RenderObject::SelectionState selectionState(); - - // Return before, after (offset set to max), or inside the text, at @p offset - FindSelectionResult checkSelectionPoint(int _x, int _y, int _tx, int _ty, const Font *f, RenderText *text, int & offset, short lineheight); - - bool checkVerticalPoint(int _y, int _ty, int _h, int height) - { if((_ty + m_y > _y + _h) || (_ty + m_y + m_baseline + height < _y)) return false; return true; } - - /** - * determines the offset into the DOMString of the character the given - * coordinate points to. - * The returned offset is never out of range. - * @param _x given coordinate (relative to containing block) - * @param ax returns exact coordinate the offset corresponds to - * (relative to containing block) - * @return the offset (relative to the RenderText object, not to this run) - */ - int offsetForPoint(int _x, int &ax) const; - - /** - * calculates the with of the specified chunk in this text box. - * @param pos zero-based position within the text box up to which - * the width is to be determined - * @return the width in pixels - */ - int widthFromStart(int pos) const; - - /** returns the lowest possible value the caret offset may have to - * still point to a valid position. - */ - virtual long minOffset() const; - /** returns the highest possible value the caret offset may have to - * still point to a valid position. - */ - virtual long maxOffset() const; - - /** returns the associated render text - */ - const RenderText *renderText() const; - RenderText *renderText(); - - int m_start; - unsigned short m_len; - - int m_truncation; // Where to truncate when text overflow is applied. - // We use special constants to denote no truncation (the whole run paints) - // and full truncation (nothing paints at all). - - bool m_reversed : 1; - unsigned m_toAdd : 14; // for justified text -private: - // this is just for TQVector::bsearch. Don't use it otherwise - InlineTextBox(int _x, int _y) - :InlineBox(0) - { - m_x = _x; - m_y = _y; - m_reversed = false; - }; - friend class RenderText; -}; - -class InlineTextBoxArray : public TQPtrVector<InlineTextBox> -{ -public: - InlineTextBoxArray(); - - InlineTextBox* first(); - - int findFirstMatching( Item ) const; - virtual int compareItems( Item, Item ); -}; - -class RenderText : public RenderObject -{ - friend class InlineTextBox; - -public: - RenderText(DOM::NodeImpl* node, DOM::DOMStringImpl *_str); - virtual ~RenderText(); - - virtual bool isTextFragment() const; - virtual DOM::DOMStringImpl* originalString() const; - - virtual const char *renderName() const { return "RenderText"; } - - virtual void setStyle(RenderStyle *style); - - - virtual void paint( PaintInfo& i, int tx, int ty ); - - virtual void deleteInlineBoxes(RenderArena* arena=0); - - DOM::DOMString data() const { return str; } - DOM::DOMStringImpl *string() const { return str; } - - virtual InlineBox* createInlineBox(bool, bool); - - virtual void layout() {assert(false);} - - virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction hitTestAction, bool inBox); - - // Return before, after (offset set to max), or inside the text, at @p offset - virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty, - DOM::NodeImpl*& node, int & offset, - SelPointState & ); - - unsigned int length() const { if (str) return str->l; else return 0; } - TQChar *text() const { if (str) return str->s; else return 0; } - unsigned int stringLength() const { return str->l; } // non virtual implementation of length() - virtual void position(InlineBox* box, int from, int len, bool reverse); - - virtual unsigned int width(unsigned int from, unsigned int len, const Font *f) const; - virtual unsigned int width(unsigned int from, unsigned int len, bool firstLine = false) const; - virtual short width() const; - virtual int height() const; - - // height of the contents (without paddings, margins and borders) - virtual short lineHeight( bool firstLine ) const; - virtual short baselinePosition( bool firstLine ) const; - - // overrides - virtual void calcMinMaxWidth(); - virtual short minWidth() const { return m_minWidth; } - virtual int maxWidth() const { return m_maxWidth; } - - void trimmedMinMaxWidth(short& beginMinW, bool& beginWS, - short& endMinW, bool& endWS, - bool& hasBreakableChar, bool& hasBreak, - short& beginMaxW, short& endMaxW, - short& minW, short& maxW, bool& stripFrontSpaces); - - bool containsOnlyWhitespace(unsigned int from, unsigned int len) const; - - ushort startMin() const { return m_startMin; } - ushort endMin() const { return m_endMin; } - - // returns the minimum x position of all runs relative to the parent. - // defaults to 0. - int minXPos() const; - - virtual int inlineXPos() const; - virtual int inlineYPos() const; - - bool hasReturn() const { return m_hasReturn; } - - virtual const TQFont &font(); - virtual short verticalPositionHint( bool firstLine ) const; - - bool isFixedWidthFont() const; - - void setText(DOM::DOMStringImpl *text, bool force=false); - - virtual SelectionState selectionState() const {return m_selectionState;} - virtual void setSelectionState(SelectionState s) {m_selectionState = s; } - virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height); - virtual bool absolutePosition(int &/*xPos*/, int &/*yPos*/, bool f = false) const; - bool posOfChar(int ch, int &x, int &y); - - virtual short marginLeft() const { return style()->marginLeft().minWidth(0); } - virtual short marginRight() const { return style()->marginRight().minWidth(0); } - - virtual void repaint(Priority p=NormalPriority); - - bool hasBreakableChar() const { return m_hasBreakableChar; } - const TQFontMetrics &metrics(bool firstLine) const; - const Font *htmlFont(bool firstLine) const; - - DOM::TextImpl *element() const - { return static_cast<DOM::TextImpl*>(RenderObject::element()); } - - /** returns the lowest possible value the caret offset may have to - * still point to a valid position. - */ - virtual long minOffset() const; - - /** returns the highest possible value the caret offset may have to - * still point to a valid position. - */ - virtual long maxOffset() const; - - /** returns the number of inline text boxes - */ - unsigned inlineTextBoxCount() const { return m_lines.count(); } - /** returns the array of inline text boxes for this render text. - */ - const InlineTextBoxArray &inlineTextBoxes() const { return m_lines; } - -#ifdef ENABLE_DUMP - virtual void dump(TQTextStream &stream, const TQString &ind) const; -#endif - - /** Find the text box that includes the character at @p offset - * and return pos, which is the position of the char in the run. - * @param offset zero-based offset into DOM string - * @param pos returns relative position within text box - * @param checkFirstLetter passing @p true will also regard :first-letter - * boxes, if available. - * @return the text box, or 0 if no match has been found - */ - InlineTextBox * findInlineTextBox( int offset, int &pos, - bool checkFirstLetter = false ); - -protected: // members - InlineTextBoxArray m_lines; - DOM::DOMStringImpl *str; // - - short m_lineHeight; - short m_minWidth; - int m_maxWidth; - short m_beginMinWidth; - short m_endMinWidth; - - SelectionState m_selectionState : 3 ; - bool m_hasReturn : 1; - bool m_hasBreakableChar : 1; - bool m_hasBreak : 1; - bool m_hasBeginWS : 1; - bool m_hasEndWS : 1; - - ushort m_startMin : 8; - ushort m_endMin : 8; -}; - -inline const RenderText* InlineTextBox::renderText() const -{ return static_cast<RenderText*>( object() ); } - -inline RenderText* InlineTextBox::renderText() -{ return static_cast<RenderText*>( object() ); } - -// Used to represent a text substring of an element, e.g., for text runs that are split because of -// first letter and that must therefore have different styles (and positions in the render tree). -// We cache offsets so that text transformations can be applied in such a way that we can recover -// the original unaltered string from our corresponding DOM node. -class RenderTextFragment : public RenderText -{ -public: - RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str, - int startOffset, int endOffset); - RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str); - ~RenderTextFragment(); - - virtual bool isTextFragment() const; - virtual const char *renderName() const { return "RenderTextFragment"; } - - uint start() const { return m_start; } - uint end() const { return m_end; } - - DOM::DOMStringImpl* contentString() const { return m_generatedContentStr; } - virtual DOM::DOMStringImpl* originalString() const; - -private: - uint m_start; - uint m_end; - DOM::DOMStringImpl* m_generatedContentStr; -}; -} // end namespace -#endif diff --git a/khtml/rendering/table_layout.cpp b/khtml/rendering/table_layout.cpp deleted file mode 100644 index f745640e7..000000000 --- a/khtml/rendering/table_layout.cpp +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2002 Lars Knoll (knoll@kde.org) - * (C) 2002 Dirk Mueller (mueller@kde.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. - * - * 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 "table_layout.h" -#include "render_table.h" - -#include <kglobal.h> - -using namespace khtml; - -// #define DEBUG_LAYOUT - -/* - The text below is from the CSS 2.1 specs. - - Fixed table layout - ------------------ - - With this (fast) algorithm, the horizontal layout of the table does - not depend on the contents of the cells; it only depends on the - table's width, the width of the columns, and borders or cell - spacing. - - The table's width may be specified explicitly with the 'width' - property. A value of 'auto' (for both 'display: table' and 'display: - inline-table') means use the automatic table layout algorithm. - - In the fixed table layout algorithm, the width of each column is - determined as follows: - - 1. A column element with a value other than 'auto' for the 'width' - property sets the width for that column. - - 2. Otherwise, a cell in the first row with a value other than - 'auto' for the 'width' property sets the width for that column. If - the cell spans more than one column, the width is divided over the - columns. - - 3. Any remaining columns equally divide the remaining horizontal - table space (minus borders or cell spacing). - - The width of the table is then the greater of the value of the - 'width' property for the table element and the sum of the column - widths (plus cell spacing or borders). If the table is wider than - the columns, the extra space should be distributed over the columns. - - - In this manner, the user agent can begin to lay out the table once - the entire first row has been received. Cells in subsequent rows do - not affect column widths. Any cell that has content that overflows - uses the 'overflow' property to determine whether to clip the - overflow content. - -_____________________________________________________ - - This is not quite true when comparing to IE. IE always honors - table-layout:fixed and treats a variable table width as 100%. Makes - a lot of sense, and is implemented here the same way. - -*/ - -FixedTableLayout::FixedTableLayout( RenderTable *table ) - : TableLayout ( table ) -{ -} - -FixedTableLayout::~FixedTableLayout() -{ -} - -int FixedTableLayout::calcWidthArray() -{ - int usedWidth = 0; - - // iterate over all <col> elements - RenderObject *child = table->firstChild(); - int cCol = 0; - int nEffCols = table->numEffCols(); - width.resize( nEffCols ); - width.fill( Length( Variable ) ); - -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::calcWidthArray()" ); - tqDebug(" col elements:"); -#endif - - Length grpWidth; - while ( child ) { - if ( child->isTableCol() ) { - RenderTableCol *col = static_cast<RenderTableCol *>(child); - int span = col->span(); - if ( col->firstChild() ) { - grpWidth = col->style()->width(); - } else { - Length w = col->style()->width(); - if ( w.isVariable() ) - w = grpWidth; - int effWidth = 0; - if ( w.isFixed() && w.value() > 0 ) { - effWidth = w.value(); - effWidth = KMIN( effWidth, 32760 ); - } -#ifdef DEBUG_LAYOUT - tqDebug(" col element: effCol=%d, span=%d: %d w=%d type=%d", - cCol, span, effWidth, w.value(), w.type()); -#endif - int usedSpan = 0; - int i = 0; - while ( usedSpan < span ) { - if( cCol + i >= nEffCols ) { - table->appendColumn( span - usedSpan ); - nEffCols++; - width.resize( nEffCols ); - width[nEffCols-1] = Length(); - } - int eSpan = table->spanOfEffCol( cCol+i ); - if ( (w.isFixed() || w.isPercent()) && w.value() > 0 ) { - width[cCol+i] = Length( w.value() * eSpan, w.type() ); - usedWidth += effWidth * eSpan; -#ifdef DEBUG_LAYOUT - tqDebug(" setting effCol %d (span=%d) to width %d(type=%d)", - cCol+i, eSpan, width[cCol+i].value(), width[cCol+i].type() ); -#endif - } - usedSpan += eSpan; - i++; - } - cCol += i; - } - } else { - break; - } - - RenderObject *next = child->firstChild(); - if ( !next ) - next = child->nextSibling(); - if ( !next && child->parent()->isTableCol() ) { - next = child->parent()->nextSibling(); - grpWidth = Length(); - } - child = next; - } - -#ifdef DEBUG_LAYOUT - tqDebug(" first row:"); -#endif - // iterate over the first row in case some are unspecified. - RenderTableSection *section = table->head; - if ( !section ) - section = table->firstBody; - if ( !section ) - section = table->foot; - if ( section && section->firstChild() ) { - cCol = 0; - // get the first cell in the first row - child = section->firstChild()->firstChild(); - while ( child ) { - if ( child->isTableCell() ) { - RenderTableCell *cell = static_cast<RenderTableCell *>(child); - Length w = cell->styleOrColWidth(); - int span = cell->colSpan(); - int effWidth = 0; - if ( (w.isFixed() || w.isPercent()) && w.value() > 0 ) { - effWidth = w.value(); - effWidth = kMin( effWidth, 32760 ); - } -#ifdef DEBUG_LAYOUT - tqDebug(" table cell: effCol=%d, span=%d: %d", cCol, span, effWidth); -#endif - int usedSpan = 0; - int i = 0; - while ( usedSpan < span ) { - Q_ASSERT( cCol + i < nEffCols ); - int eSpan = table->spanOfEffCol( cCol+i ); - // only set if no col element has already set it. - if ( width[cCol+i].isVariable() && !w.isVariable() ) { - width[cCol+i] = Length( w.value()*eSpan, w.type() ); - usedWidth += effWidth*eSpan; -#ifdef DEBUG_LAYOUT - tqDebug(" setting effCol %d (span=%d) to width %d(type=%d)", - cCol+i, eSpan, width[cCol+i].value(), width[cCol+i].type() ); -#endif - } -#ifdef DEBUG_LAYOUT - else { - tqDebug(" width of col %d already defined (span=%d)", cCol, table->spanOfEffCol( cCol ) ); - } -#endif - usedSpan += eSpan; - i++; - } - cCol += i; - } else { - Q_ASSERT( false ); - } - child = child->nextSibling(); - } - } - - return usedWidth; - -} - -void FixedTableLayout::calcMinMaxWidth() -{ - // we might want to wait until we have all of the first row before - // layouting for the first time. - - // only need to calculate the minimum width as the sum of the - // cols/cells with a fixed width. - // - // The maximum width is kMax( minWidth, tableWidth ) if table - // width is fixed. If table width is percent, we set maxWidth to - // unlimited. - - int bs = table->bordersPaddingAndSpacing(); - int tableWidth = 0; - if (table->style()->width().isFixed()) { - tableWidth = table->calcBoxWidth(table->style()->width().value()); - } - - int mw = calcWidthArray() + bs; - table->m_minWidth = kMin( kMax( mw, tableWidth ), 0x7fff ); - table->m_maxWidth = table->m_minWidth; - - if ( !tableWidth ) { - bool haveNonFixed = false; - for ( unsigned int i = 0; i < width.size(); i++ ) { - if ( !width[i].isFixed() ) { - haveNonFixed = true; - break; - } - } - if ( haveNonFixed ) - table->m_maxWidth = 0x7fff; - } -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::calcMinMaxWidth: minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth ); -#endif -} - -void FixedTableLayout::layout() -{ - int tableWidth = table->width() - table->bordersPaddingAndSpacing(); - int available = tableWidth; - int nEffCols = table->numEffCols(); -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::layout: tableWidth=%d, numEffCols=%d", tableWidth, nEffCols); -#endif - - - TQMemArray<int> calcWidth; - calcWidth.resize( nEffCols ); - calcWidth.fill( -1 ); - - // first assign fixed width - for ( int i = 0; i < nEffCols; i++ ) { - if ( width[i].isFixed() ) { - calcWidth[i] = width[i].value(); - available -= width[i].value(); - } - } - - // assign percent width - if ( available > 0 ) { - int totalPercent = 0; - for ( int i = 0; i < nEffCols; i++ ) - if ( width[i].isPercent() ) - totalPercent += width[i].value(); - - // calculate how much to distribute to percent cells. - int base = tableWidth * totalPercent / 100; - if ( base > available ) - base = available; - -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::layout: assigning percent width, base=%d, totalPercent=%d", base, totalPercent); -#endif - for ( int i = 0; available > 0 && i < nEffCols; i++ ) { - if ( width[i].isPercent() ) { - // totalPercent may be 0 below if all %-width specifed are 0%. (#172557) - int w = totalPercent ? base * width[i].value() / totalPercent : 0; - available -= w; - calcWidth[i] = w; - } - } - } - - // assign variable width - if ( available > 0 ) { - int totalVariable = 0; - for ( int i = 0; i < nEffCols; i++ ) - if ( width[i].isVariable() ) - totalVariable++; - - for ( int i = 0; available > 0 && i < nEffCols; i++ ) { - if ( width[i].isVariable() ) { - // totalVariable may be 0 below if all the variable widths specified are 0. - int w = totalVariable ? available / totalVariable : 0; - available -= w; - calcWidth[i] = w; - totalVariable--; - } - } - } - - for ( int i = 0; i < nEffCols; i++ ) - if ( calcWidth[i] < 0 ) - calcWidth[i] = 0; // IE gives min 1 px... - - // spread extra space over columns - if ( available > 0 ) { - int total = nEffCols; - // still have some width to spread - int i = nEffCols; - while ( i-- ) { - int w = available / total; - available -= w; - total--; - calcWidth[i] += w; - } - } - - int pos = 0; - int hspacing = table->borderHSpacing(); - for ( int i = 0; i < nEffCols; i++ ) { -#ifdef DEBUG_LAYOUT - tqDebug("col %d: %d (width %d)", i, pos, calcWidth[i] ); -#endif - table->columnPos[i] = pos; - pos += calcWidth[i] + hspacing; - } - table->columnPos[table->columnPos.size()-1] = pos; -} - -// ------------------------------------------------------------------------- -// ------------------------------------------------------------------------- - - -AutoTableLayout::AutoTableLayout( RenderTable* table ) - : TableLayout( table ) -{ - percentagesDirty = true; - effWidthDirty = true; - total_percent = 0; - hasPercent = false; -} - -AutoTableLayout::~AutoTableLayout() -{ -} - -/* recalculates the full structure needed to do layouting and minmax calculations. - This is usually calculated on the fly, but needs to be done fully when table cells change - dynamically -*/ -void AutoTableLayout::recalcColumn( int effCol ) -{ - Layout &l = layoutStruct[effCol]; - - RenderObject *child = table->firstChild(); - // first we iterate over all rows. - - RenderTableCell *fixedContributor = 0; - RenderTableCell *maxContributor = 0; - - while ( child ) { - if ( child->isTableSection() ) { - RenderTableSection *section = static_cast<RenderTableSection *>(child); - int numRows = section->numRows(); - RenderTableCell *last = 0; - for ( int i = 0; i < numRows; i++ ) { - RenderTableCell *cell = section->cellAt( i, effCol ); - if ( cell == (RenderTableCell *)-1 ) - continue; - if ( cell && cell->colSpan() == 1 ) { - // A cell originates in this column. Ensure we have - // a min/max width of at least 1px for this column now. - l.minWidth = kMax(int( l.minWidth ), 1); - l.maxWidth = kMax(int( l.maxWidth ), 1); - - if ( !cell->minMaxKnown() ) - cell->calcMinMaxWidth(); - if ( cell->minWidth() > l.minWidth ) - l.minWidth = cell->minWidth(); - if ( cell->maxWidth() > l.maxWidth ) { - l.maxWidth = cell->maxWidth(); - maxContributor = cell; - } - - Length w = cell->styleOrColWidth(); - w.l.value = kMin( 32767, kMax( 0, w.value() ) ); - switch( w.type() ) { - case Fixed: - // ignore width=0 - if ( w.value() > 0 && !l.width.isPercent() ) { - int wval = cell->calcBoxWidth(w.value()); - if ( l.width.isFixed() ) { - // Nav/IE weirdness - if ((wval > l.width.value()) || - ((l.width.value() == wval) && (maxContributor == cell))) { - l.width.l.value = wval; - fixedContributor = cell; - } - } else { - l.width = Length( wval, Fixed ); - fixedContributor = cell; - } - } - break; - case Percent: - hasPercent = true; - if ( w.value() > 0 && (!l.width.isPercent() || w.value() > l.width.value() ) ) - l.width = w; - break; - case Relative: - if ( w.isVariable() || (w.isRelative() && w.value() > l.width.value() ) ) - l.width = w; - default: - break; - } - } else { - if ( cell && (!effCol || section->cellAt( i, effCol-1 ) != cell) ) { - // This spanning cell originates in this column. Ensure we have - // a min/max width of at least 1px for this column now. - l.minWidth = kMax(int( l.minWidth ), 1); - l.maxWidth = kMax(int( l.maxWidth ), 1); - insertSpanCell( cell ); - } - last = cell; - } - } - } - child = child->nextSibling(); - } - - // Nav/IE weirdness - if ( l.width.isFixed() ) { - if ( table->style()->htmlHacks() - && (l.maxWidth > l.width.value()) && (fixedContributor != maxContributor)) { - l.width = Length(); - fixedContributor = 0; - } - } - - l.maxWidth = kMax(l.maxWidth, int(l.minWidth)); -#ifdef DEBUG_LAYOUT - tqDebug("col %d, final min=%d, max=%d, width=%d(%d)", effCol, l.minWidth, l.maxWidth, l.width.value(), l.width.type() ); -#endif - - // ### we need to add col elements aswell -} - - -void AutoTableLayout::fullRecalc() -{ - percentagesDirty = true; - hasPercent = false; - effWidthDirty = true; - - int nEffCols = table->numEffCols(); - layoutStruct.resize( nEffCols ); - layoutStruct.fill( Layout() ); - spanCells.fill( 0 ); - - RenderObject *child = table->firstChild(); - Length grpWidth; - int cCol = 0; - while ( child ) { - if ( child->isTableCol() ) { - RenderTableCol *col = static_cast<RenderTableCol *>(child); - int span = col->span(); - if ( col->firstChild() ) { - grpWidth = col->style()->width(); - } else { - Length w = col->style()->width(); - if ( w.isVariable() ) - w = grpWidth; - if ( (w.isFixed() && w.value() == 0) || - (w.isPercent() && w.value() == 0) ) - w = Length(); - int cEffCol = table->colToEffCol( cCol ); -#ifdef DEBUG_LAYOUT - tqDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.value(), w.type(), span, table->spanOfEffCol(cEffCol ) ); -#endif - if ( !w.isVariable() && span == 1 && cEffCol < nEffCols ) { - if ( table->spanOfEffCol( cEffCol ) == 1 ) { - layoutStruct[cEffCol].width = w; - if (w.isFixed() && layoutStruct[cEffCol].maxWidth < w.value()) - layoutStruct[cEffCol].maxWidth = w.value(); - } - } - cCol += span; - } - } else { - break; - } - - RenderObject *next = child->firstChild(); - if ( !next ) - next = child->nextSibling(); - if ( !next && child->parent()->isTableCol() ) { - next = child->parent()->nextSibling(); - grpWidth = Length(); - } - child = next; - } - - - for ( int i = 0; i < nEffCols; i++ ) - recalcColumn( i ); -} - -static bool shouldScaleColumns(RenderTable* table) -{ - // A special case. If this table is not fixed width and contained inside - // a cell, then don't bloat the maxwidth by examining percentage growth. - bool scale = true; - while (table) { - Length tw = table->style()->width(); - if ((tw.isVariable() || tw.isPercent()) && !table->isPositioned()) { - RenderBlock* cb = table->containingBlock(); - while (cb && !cb->isCanvas() && !cb->isTableCell() && - cb->style()->width().isVariable() && !cb->isPositioned()) - cb = cb->containingBlock(); - - table = 0; - if (cb && cb->isTableCell() && - (cb->style()->width().isVariable() || cb->style()->width().isPercent())) { - if (tw.isPercent()) - scale = false; - else { - RenderTableCell* cell = static_cast<RenderTableCell*>(cb); - if (cell->colSpan() > 1 || cell->table()->style()->width().isVariable()) - scale = false; - else - table = cell->table(); - } - } - } - else - table = 0; - } - return scale; -} - -void AutoTableLayout::calcMinMaxWidth() -{ -#ifdef DEBUG_LAYOUT - tqDebug("AutoTableLayout::calcMinMaxWidth"); -#endif - fullRecalc(); - - int spanMaxWidth = calcEffectiveWidth(); - int minWidth = 0; - int maxWidth = 0; - int maxPercent = 0; - int maxNonPercent = 0; - - int remainingPercent = 100; - for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) { - minWidth += layoutStruct[i].effMinWidth; - maxWidth += layoutStruct[i].effMaxWidth; - if ( layoutStruct[i].effWidth.isPercent() ) { - int percent = kMin(layoutStruct[i].effWidth.value(), remainingPercent); - int pw = ( layoutStruct[i].effMaxWidth * 100) / kMax(percent, 1); - remainingPercent -= percent; - maxPercent = kMax( pw, maxPercent ); - } else { - maxNonPercent += layoutStruct[i].effMaxWidth; - } - } - - if (shouldScaleColumns(table)) { - maxNonPercent = (maxNonPercent * 100 + 50) / kMax(remainingPercent, 1); - maxWidth = kMax( maxNonPercent, maxWidth ); - maxWidth = kMax( maxWidth, maxPercent ); - } - - maxWidth = kMax( maxWidth, spanMaxWidth ); - - int bs = table->bordersPaddingAndSpacing(); - minWidth += bs; - maxWidth += bs; - - Length tw = table->style()->width(); - if ( tw.isFixed() && tw.value() > 0 ) { - int width = table->calcBoxWidth(tw.value()); - minWidth = kMax( minWidth, width ); - maxWidth = minWidth; - } - - table->m_maxWidth = kMin(maxWidth, 0x7fff); - table->m_minWidth = kMin(minWidth, 0x7fff); -#ifdef DEBUG_LAYOUT - tqDebug(" minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth ); -#endif -} - -/* - This method takes care of colspans. - effWidth is the same as width for cells without colspans. If we have colspans, they get modified. - */ -int AutoTableLayout::calcEffectiveWidth() -{ - int tMaxWidth = 0; - - unsigned int nEffCols = layoutStruct.size(); - int hspacing = table->borderHSpacing(); -#ifdef DEBUG_LAYOUT - tqDebug("AutoTableLayout::calcEffectiveWidth for %d cols", nEffCols ); -#endif - for ( unsigned int i = 0; i < nEffCols; i++ ) { - layoutStruct[i].effWidth = layoutStruct[i].width; - layoutStruct[i].effMinWidth = layoutStruct[i].minWidth; - layoutStruct[i].effMaxWidth = layoutStruct[i].maxWidth; - } - - for ( unsigned int i = 0; i < spanCells.size(); i++ ) { - RenderTableCell *cell = spanCells[i]; - if ( !cell || cell == (RenderTableCell *)-1 ) - break; - int span = cell->colSpan(); - - Length w = cell->styleOrColWidth(); - if ( !w.isRelative() && w.value() == 0 ) - w = Length(); // make it Variable - - int col = table->colToEffCol( cell->col() ); - unsigned int lastCol = col; - int cMinWidth = cell->minWidth() + hspacing; - int cMaxWidth = cell->maxWidth() + hspacing; - int totalPercent = 0; - int minWidth = 0; - int maxWidth = 0; - bool allColsArePercent = true; - bool allColsAreFixed = true; - bool haveVariable = false; - int fixedWidth = 0; -#ifdef DEBUG_LAYOUT - int cSpan = span; -#endif - while ( lastCol < nEffCols && span > 0 ) { - switch( layoutStruct[lastCol].width.type() ) { - case Percent: - totalPercent += layoutStruct[lastCol].width.value(); - allColsAreFixed = false; - break; - case Fixed: - if (layoutStruct[lastCol].width.value() > 0) { - fixedWidth += layoutStruct[lastCol].width.value(); - allColsArePercent = false; - // IE resets effWidth to Variable here, but this breaks the konqueror about page and seems to be some bad - // legacy behavior anyway. mozilla doesn't do this so I decided we don't either. - break; - } - // fall through - case Variable: - haveVariable = true; - // fall through - default: - // If the column is a percentage width, do not let the spanning cell overwrite the - // width value. This caused a mis-rendering on amazon.com. - // Sample snippet: - // <table border=2 width=100%>< - // <tr><td>1</td><td colspan=2>2-3</tr> - // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr> - // </table> - if (!layoutStruct[lastCol].effWidth.isPercent()) { - layoutStruct[lastCol].effWidth = Length(); - allColsArePercent = false; - } - else - totalPercent += layoutStruct[lastCol].effWidth.value(); - allColsAreFixed = false; - } - span -= table->spanOfEffCol( lastCol ); - minWidth += layoutStruct[lastCol].effMinWidth; - maxWidth += layoutStruct[lastCol].effMaxWidth; - lastCol++; - cMinWidth -= hspacing; - cMaxWidth -= hspacing; - } -#ifdef DEBUG_LAYOUT - tqDebug(" colspan cell %p at effCol %d, span %d, type %d, value %d cmin=%d min=%d fixedwidth=%d", cell, col, cSpan, w.type(), w.value(), cMinWidth, minWidth, fixedWidth ); -#endif - - // adjust table max width if needed - if ( w.isPercent() ) { - if ( totalPercent > w.value() || allColsArePercent ) { - // can't satify this condition, treat as variable - w = Length(); - } else { - int spanMax = kMax( maxWidth, cMaxWidth ); -#ifdef DEBUG_LAYOUT - tqDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.value(), totalPercent ); -#endif - tMaxWidth = kMax( tMaxWidth, spanMax * 100 / w.value() ); - - // all non percent columns in the span get percent values to sum up correctly. - int percentMissing = w.value() - totalPercent; - int totalWidth = 0; - for ( unsigned int pos = col; pos < lastCol; pos++ ) { - if ( !(layoutStruct[pos].width.isPercent() ) ) - totalWidth += layoutStruct[pos].effMaxWidth; - } - - for ( unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++ ) { - if ( !(layoutStruct[pos].width.isPercent() ) ) { - int percent = percentMissing * layoutStruct[pos].effMaxWidth / totalWidth; -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: setting percent value %d effMaxWidth=%d totalWidth=%d", pos, percent, layoutStruct[pos].effMaxWidth, totalWidth ); -#endif - totalWidth -= layoutStruct[pos].effMaxWidth; - percentMissing -= percent; - if ( percent > 0 ) - layoutStruct[pos].effWidth = Length( percent, Percent ); - else - layoutStruct[pos].effWidth = Length(); - } - } - - } - } - - // make sure minWidth and maxWidth of the spanning cell are honoured - if ( cMinWidth > minWidth ) { - if ( allColsAreFixed ) { -#ifdef DEBUG_LAYOUT - tqDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d accroding to fixed sum %d", col, lastCol-1, cMinWidth, minWidth, fixedWidth ); -#endif - for ( unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++ ) { - int w = kMax( int( layoutStruct[pos].effMinWidth ), cMinWidth * layoutStruct[pos].width.value() / fixedWidth ); -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - fixedWidth -= layoutStruct[pos].width.value(); - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - - } else if ( allColsArePercent ) { - int maxw = maxWidth; - int minw = minWidth; - int cminw = cMinWidth; - - for ( unsigned int pos = col; maxw > 0 && pos < lastCol; pos++ ) { - if ( layoutStruct[pos].effWidth.isPercent() && layoutStruct[pos].effWidth.value()>0 && fixedWidth <= cMinWidth) { - int w = layoutStruct[pos].effMinWidth; - w = kMax( w, cminw*layoutStruct[pos].effWidth.value()/totalPercent ); - w = kMin(layoutStruct[pos].effMinWidth+(cMinWidth-minw), w); -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - maxw -= layoutStruct[pos].effMaxWidth; - minw -= layoutStruct[pos].effMinWidth; - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - } - } else { -#ifdef DEBUG_LAYOUT - tqDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d", col, lastCol-1, cMinWidth, minWidth ); -#endif - int maxw = maxWidth; - int minw = minWidth; - - // Give min to variable first, to fixed second, and to others third. - for ( unsigned int pos = col; maxw > 0 && pos < lastCol; pos++ ) { - if ( layoutStruct[pos].width.isFixed() && haveVariable && fixedWidth <= cMinWidth ) { - int w = kMax( int( layoutStruct[pos].effMinWidth ), layoutStruct[pos].width.value() ); - fixedWidth -= layoutStruct[pos].width.value(); - minw -= layoutStruct[pos].effMinWidth; -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - maxw -= layoutStruct[pos].effMaxWidth; - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - } - - for ( unsigned int pos = col; maxw > 0 && pos < lastCol && minw < cMinWidth; pos++ ) { - if ( !(layoutStruct[pos].width.isFixed() && haveVariable && fixedWidth <= cMinWidth) ) { - int w = kMax( int( layoutStruct[pos].effMinWidth ), cMinWidth * layoutStruct[pos].effMaxWidth / maxw ); - w = kMin(layoutStruct[pos].effMinWidth+(cMinWidth-minw), w); - -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - maxw -= layoutStruct[pos].effMaxWidth; - minw -= layoutStruct[pos].effMinWidth; - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - } - } - } - if ( !w.isPercent() ) { - if ( cMaxWidth > maxWidth ) { -#ifdef DEBUG_LAYOUT - tqDebug("extending maxWidth of cols %d-%d to %dpx", col, lastCol-1, cMaxWidth ); -#endif - for ( unsigned int pos = col; maxWidth > 0 && pos < lastCol; pos++ ) { - int w = kMax( int( layoutStruct[pos].effMaxWidth ), cMaxWidth * layoutStruct[pos].effMaxWidth / maxWidth ); -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: max=%d, effMax=%d, new=%d", pos, layoutStruct[pos].effMaxWidth, layoutStruct[pos].effMaxWidth, w ); -#endif - maxWidth -= layoutStruct[pos].effMaxWidth; - cMaxWidth -= w; - layoutStruct[pos].effMaxWidth = w; - } - } - } else { - for ( unsigned int pos = col; pos < lastCol; pos++ ) - layoutStruct[pos].maxWidth = kMax(layoutStruct[pos].maxWidth, int(layoutStruct[pos].minWidth) ); - } - } - effWidthDirty = false; - -// tqDebug("calcEffectiveWidth: tMaxWidth=%d", tMaxWidth ); - return tMaxWidth; -} - -/* gets all cells that originate in a column and have a cellspan > 1 - Sorts them by increasing cellspan -*/ -void AutoTableLayout::insertSpanCell( RenderTableCell *cell ) -{ - if ( !cell || cell == (RenderTableCell *)-1 || cell->colSpan() == 1 ) - return; - -// tqDebug("inserting span cell %p with span %d", cell, cell->colSpan() ); - int size = spanCells.size(); - if ( !size || spanCells[size-1] != 0 ) { - spanCells.resize( size + 10 ); - for ( int i = 0; i < 10; i++ ) - spanCells[size+i] = 0; - size += 10; - } - - // add them in sort. This is a slow algorithm, and a binary search or a fast sorting after collection would be better - unsigned int pos = 0; - int span = cell->colSpan(); - while ( pos < spanCells.size() && spanCells[pos] && span > spanCells[pos]->colSpan() ) - pos++; - memmove( spanCells.data()+pos+1, spanCells.data()+pos, (size-pos-1)*sizeof( RenderTableCell * ) ); - spanCells[pos] = cell; -} - - -void AutoTableLayout::layout() -{ - // table layout based on the values collected in the layout structure. - int tableWidth = table->width() - table->bordersPaddingAndSpacing(); - int available = tableWidth; - int nEffCols = table->numEffCols(); - - if ( nEffCols != (int)layoutStruct.size() ) { - tqWarning("WARNING: nEffCols is not equal to layoutstruct!" ); - fullRecalc(); - nEffCols = table->numEffCols(); - } -#ifdef DEBUG_LAYOUT - tqDebug("AutoTableLayout::layout()"); -#endif - - if ( effWidthDirty ) - calcEffectiveWidth(); - -#ifdef DEBUG_LAYOUT - tqDebug(" tableWidth=%d, nEffCols=%d", tableWidth, nEffCols ); - for ( int i = 0; i < nEffCols; i++ ) { - tqDebug(" effcol %d is of type %d value %d, minWidth=%d, maxWidth=%d", - i, layoutStruct[i].width.type(), layoutStruct[i].width.value(), - layoutStruct[i].minWidth, layoutStruct[i].maxWidth ); - tqDebug(" effective: type %d value %d, minWidth=%d, maxWidth=%d", - layoutStruct[i].effWidth.type(), layoutStruct[i].effWidth.value(), - layoutStruct[i].effMinWidth, layoutStruct[i].effMaxWidth ); - } -#endif - - bool havePercent = false; - bool haveRelative = false; - int totalRelative = 0; - int numVariable = 0; - int numFixed = 0; - int totalVariable = 0; - int totalFixed = 0; - int totalPercent = 0; - int allocVariable = 0; - - // fill up every cell with it's minWidth - for ( int i = 0; i < nEffCols; i++ ) { - int w = layoutStruct[i].effMinWidth; - layoutStruct[i].calcWidth = w; - available -= w; - Length& width = layoutStruct[i].effWidth; - switch( width.type()) { - case Percent: - havePercent = true; - totalPercent += width.value(); - break; - case Relative: - haveRelative = true; - totalRelative += width.value(); - break; - case Fixed: - numFixed++; - totalFixed += layoutStruct[i].effMaxWidth; - // fall through - break; - case Variable: - case Static: - numVariable++; - totalVariable += layoutStruct[i].effMaxWidth; - allocVariable += w; - } - } - - // allocate width to percent cols - if ( available > 0 && havePercent ) { - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isPercent() ) { - int w = kMax ( int( layoutStruct[i].effMinWidth ), width.minWidth( tableWidth ) ); - available += layoutStruct[i].calcWidth - w; - layoutStruct[i].calcWidth = w; - } - } - if ( totalPercent > 100 ) { - // remove overallocated space from the last columns - int excess = tableWidth*(totalPercent-100)/100; - for ( int i = nEffCols-1; i >= 0; i-- ) { - if ( layoutStruct[i].effWidth.isPercent() ) { - int w = layoutStruct[i].calcWidth; - int reduction = kMin( w, excess ); - // the lines below might look inconsistent, but that's the way it's handled in mozilla - excess -= reduction; - int newWidth = kMax( int (layoutStruct[i].effMinWidth), w - reduction ); - available += w - newWidth; - layoutStruct[i].calcWidth = newWidth; - //tqDebug("col %d: reducing to %d px (reduction=%d)", i, newWidth, reduction ); - } - } - } - } -#ifdef DEBUG_LAYOUT - tqDebug("percent satisfied: available is %d", available); -#endif - - // then allocate width to fixed cols - if ( available > 0 ) { - for ( int i = 0; i < nEffCols; ++i ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isFixed() && width.value() > layoutStruct[i].calcWidth ) { - available += layoutStruct[i].calcWidth - width.value(); - layoutStruct[i].calcWidth = width.value(); - } - } - } -#ifdef DEBUG_LAYOUT - tqDebug("fixed satisfied: available is %d", available); -#endif - - // now satisfy relative - if ( available > 0 ) { - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isRelative() && width.value() ) { - // width=0* gets effMinWidth. - int w = width.value()*tableWidth/totalRelative; - available += layoutStruct[i].calcWidth - w; - layoutStruct[i].calcWidth = w; - } - } - } - - // now satisfy variable - if ( available > 0 && numVariable ) { - available += allocVariable; // this gets redistributed - //tqDebug("redistributing %dpx to %d variable columns. totalVariable=%d", available, numVariable, totalVariable ); - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isVariable() && totalVariable != 0 ) { - int w = kMax( int ( layoutStruct[i].calcWidth ), - available * layoutStruct[i].effMaxWidth / totalVariable ); - available -= w; - totalVariable -= layoutStruct[i].effMaxWidth; - layoutStruct[i].calcWidth = w; - } - } - } -#ifdef DEBUG_LAYOUT - tqDebug("variable satisfied: available is %d", available ); -#endif - - // spread over fixed colums - if ( available > 0 && numFixed) { - // still have some width to spread, distribute to fixed columns - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isFixed() ) { - int w = available * layoutStruct[i].effMaxWidth / totalFixed; - available -= w; - totalFixed -= layoutStruct[i].effMaxWidth; - layoutStruct[i].calcWidth += w; - } - } - } - -#ifdef DEBUG_LAYOUT - tqDebug("after fixed distribution: available=%d", available ); -#endif - - // spread over percent colums - if ( available > 0 && hasPercent && totalPercent < 100) { - // still have some width to spread, distribute weighted to percent columns - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isPercent() ) { - int w = available * width.value() / totalPercent; - available -= w; - totalPercent -= width.value(); - layoutStruct[i].calcWidth += w; - if (!available || !totalPercent) break; - } - } - } - -#ifdef DEBUG_LAYOUT - tqDebug("after percent distribution: available=%d", available ); -#endif - - // spread over the rest - if ( available > 0 ) { - int total = nEffCols; - // still have some width to spread - int i = nEffCols; - while ( i-- ) { - int w = available / total; - available -= w; - total--; - layoutStruct[i].calcWidth += w; - } - } - -#ifdef DEBUG_LAYOUT - tqDebug("after equal distribution: available=%d", available ); -#endif - // if we have overallocated, reduce every cell according to the difference between desired width and minwidth - // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing. - if ( available < 0 ) { - // Need to reduce cells with the following prioritization: - // (1) Variable - // (2) Relative - // (3) Fixed - // (4) Percent - // This is basically the reverse of how we grew the cells. - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isVariable()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isVariable()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isRelative()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isRelative()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isFixed()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isFixed()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isPercent()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isPercent()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - } - - //tqDebug( " final available=%d", available ); - - int pos = 0; - for ( int i = 0; i < nEffCols; i++ ) { -#ifdef DEBUG_LAYOUT - tqDebug("col %d: %d (width %d)", i, pos, layoutStruct[i].calcWidth ); -#endif - table->columnPos[i] = pos; - pos += layoutStruct[i].calcWidth + table->borderHSpacing(); - } - table->columnPos[table->columnPos.size()-1] = pos; - -} - - -void AutoTableLayout::calcPercentages() const -{ - total_percent = 0; - for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) { - if ( layoutStruct[i].width.isPercent() ) - total_percent += layoutStruct[i].width.value(); - } - percentagesDirty = false; -} - -#undef DEBUG_LAYOUT diff --git a/khtml/rendering/table_layout.h b/khtml/rendering/table_layout.h deleted file mode 100644 index cbaf6d3a7..000000000 --- a/khtml/rendering/table_layout.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2002 Lars Knoll (knoll@kde.org) - * (C) 2002 Dirk Mueller (mueller@kde.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. - * - * 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. - * - */ -#ifndef TABLE_LAYOUT_H -#define TABLE_LAYOUT_H - -#include <tqmemarray.h> -#include <misc/khtmllayout.h> - -namespace khtml { - -class RenderTable; -class RenderTableCell; - -// ------------------------------------------------------------------------- - -class TableLayout -{ -public: - TableLayout( RenderTable *t ) : table( t ) {} - virtual ~TableLayout() {} - - virtual void calcMinMaxWidth() = 0; - virtual void layout() = 0; - -protected: - RenderTable *table; -}; - -// ------------------------------------------------------------------------- - -class FixedTableLayout : public TableLayout -{ -public: - FixedTableLayout( RenderTable *table ); - ~FixedTableLayout(); - - void calcMinMaxWidth(); - void layout(); - -protected: - int calcWidthArray(); - - TQMemArray<Length> width; -}; - -// ------------------------------------------------------------------------- - -class AutoTableLayout : public TableLayout -{ -public: - AutoTableLayout( RenderTable *table ); - ~AutoTableLayout(); - - void calcMinMaxWidth(); - void layout(); - - -protected: - void fullRecalc(); - void recalcColumn( int effCol ); - int totalPercent() const { - if ( percentagesDirty ) - calcPercentages(); - return total_percent; - } - void calcPercentages() const; - int calcEffectiveWidth(); - void insertSpanCell( RenderTableCell *cell ); - - struct Layout { - Layout() : minWidth( 1 ), maxWidth( 1 ), - effMinWidth( 0 ), effMaxWidth( 0 ), - calcWidth( 0 ) {} - Length width; - Length effWidth; - short minWidth; - int maxWidth; - short effMinWidth; - int effMaxWidth; - short calcWidth; - }; - - TQMemArray<Layout> layoutStruct; - TQMemArray<RenderTableCell *>spanCells; - bool hasPercent : 1; - mutable bool percentagesDirty : 1; - mutable bool effWidthDirty : 1; - mutable unsigned short total_percent; -}; - -} -#endif diff --git a/khtml/rendering/table_layout.txt b/khtml/rendering/table_layout.txt deleted file mode 100644 index 14a74bd1e..000000000 --- a/khtml/rendering/table_layout.txt +++ /dev/null @@ -1,74 +0,0 @@ -CSS describes two ways of layouting tables. Auto layout (the NS4 -compliant HTML table layout) and fixed layout. The fixed layout -strategy is described in detail in the CSS specs and will not be -repeated here. - -Due to the fact that two layout strategies exist, it is rather natural -to encapsulate the layouting process in a TableLayout class. Two types -(FixedTableLayout and AutoTableLayout) exist. AutoTableLayout is the -default and also need a quirks flags for NS compatibility -mode. FixedTableLayout will be used if a style rule sets the -table-layout property to fixed. - -The grid of table cells is stored in each table section, as spans -can't pass section borders. Changing the number of cols in the grid -has to be done by the table to keep all grids (for all sections) in -sync. The grid only stores effective columns. The table below would -only result in one column being allocated in the grid: - -<table><tr><td colspan=1000>foo</td></tr></table> - -Once a colspan get's used, the column is split into its subparts. To -do this, the table has to store the colspans of effective columns in a -structure. - - - - -NS & Mozilla compliant table layouting algorithm (AutoTableLayout) ------------------------------------------------------------------- - -The table layout algorithm computes a set of layout hints from the -informations in the table cells, <col> elements and style -sheets. Hints from different sources are treated a bit differently in -the collection stage. - -In addition certain operations are only done in quirks (NS4 compat) -mode. - -Resizing the table doesn't require you to build up this information -again. All that is needed is a list of layout hints for each column. - -The algorithm below describes to the best of our knowledge the way -table alyouting is handled in a NS compatible way. - -There are two stages, the collection stage (assocaited with -calcMinMaxWidth() in khtml) and the stage assigning width to cells -(associated with layout()). - -A set of hinted widths are used to determine the final table layout in -the layouting stage. - -enum hintType { - MinWidth, - DesiredWidth, - FixedWidth, - MinWidthAdjusted, - DesiredWidthAdjusted, - FixedWidthAdjusted, - PercentWidth, - PercentWidthAdjusted, - ProportionalWidth -}; - -One width (in pixels) for each hintType describes how the column -wishes to be layouted. The layouting stage operates only on an array -of hints for each column. - -An additional totalCellSpacing variable is used to know about the -remaining width to distribute. - -Collection stage: ------------------ - - |