9563312da6929203815b53cb2eb32ce41b704685
[WebKit-https.git] / WebCore / khtml / rendering / render_frames.cpp
1 /**
2  * This file is part of the KDE project.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 2000 Simon Hausmann <hausmann@kde.org>
6  *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
7  * Copyright (C) 2003 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25 //#define DEBUG_LAYOUT
26
27 #include "rendering/render_frames.h"
28
29 #include "css/cssproperties.h"
30 #include "rendering/render_canvas.h"
31 #include "html/html_baseimpl.h"
32 #include "html/html_objectimpl.h"
33 #include "html/htmltokenizer.h"
34 #include "misc/htmlattrs.h"
35 #include "xml/dom2_eventsimpl.h"
36 #include "xml/dom_docimpl.h"
37 #include "misc/htmltags.h"
38 #include "khtmlview.h"
39 #include "khtml_part.h"
40 #include "render_arena.h"
41
42 #include <kapplication.h>
43 #include <kcursor.h>
44 #include <kmessagebox.h>
45 #include <kmimetype.h>
46 #include <klocale.h>
47 #include <kdebug.h>
48 #include <kglobal.h>
49 #include <qtimer.h>
50 #include <qpainter.h>
51 #include "qdict.h"
52
53 using namespace khtml;
54 using namespace DOM;
55
56 RenderFrameSet::RenderFrameSet( HTMLFrameSetElementImpl *frameSet)
57     : RenderContainer(frameSet)
58 {
59   // init RenderObject attributes
60     setInline(false);
61
62   for (int k = 0; k < 2; ++k) {
63       m_gridLen[k] = -1;
64       m_gridDelta[k] = 0;
65       m_gridLayout[k] = 0;
66   }
67
68   m_resizing = m_clientresizing= false;
69
70   m_hSplit = -1;
71   m_vSplit = -1;
72
73   m_hSplitVar = 0;
74   m_vSplitVar = 0;
75 }
76
77 RenderFrameSet::~RenderFrameSet()
78 {
79     for (int k = 0; k < 2; ++k) {
80         if (m_gridLayout[k]) delete [] m_gridLayout[k];
81         if (m_gridDelta[k]) delete [] m_gridDelta[k];
82     }
83   if (m_hSplitVar)
84       delete [] m_hSplitVar;
85   if (m_vSplitVar)
86       delete [] m_vSplitVar;
87 }
88
89 bool RenderFrameSet::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
90                                  HitTestAction hitTestAction, bool inside)
91 {
92     RenderContainer::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside);
93
94     inside = m_resizing || canResize(_x, _y);
95
96     if ( inside && element() && !element()->noResize() && !info.readonly()){
97         info.setInnerNode(element());
98         info.setInnerNonSharedNode(element());
99     }
100
101     return inside || m_clientresizing;
102 }
103
104 void RenderFrameSet::layout( )
105 {
106     KHTMLAssert( needsLayout() );
107     KHTMLAssert( minMaxKnown() );
108
109     if ( !parent()->isFrameSet() ) {
110         KHTMLView* view = canvas()->view();
111         m_width = view->visibleWidth();
112         m_height = view->visibleHeight();
113     }
114
115 #ifdef DEBUG_LAYOUT
116     kdDebug( 6040 ) << renderName() << "(FrameSet)::layout( ) width=" << width() << ", height=" << height() << endl;
117 #endif
118
119     int remainingLen[2];
120     remainingLen[1] = m_width - (element()->totalCols()-1)*element()->border();
121     if(remainingLen[1]<0) remainingLen[1]=0;
122     remainingLen[0] = m_height - (element()->totalRows()-1)*element()->border();
123     if(remainingLen[0]<0) remainingLen[0]=0;
124
125     int availableLen[2];
126     availableLen[0] = remainingLen[0];
127     availableLen[1] = remainingLen[1];
128
129     if (m_gridLen[0] != element()->totalRows() || m_gridLen[1] != element()->totalCols()) {
130         // number of rows or cols changed
131         // need to zero out the deltas
132         m_gridLen[0] = element()->totalRows();
133         m_gridLen[1] = element()->totalCols();
134         for (int k = 0; k < 2; ++k) {
135             if (m_gridDelta[k]) delete [] m_gridDelta[k];
136             m_gridDelta[k] = new int[m_gridLen[k]];
137             if (m_gridLayout[k]) delete [] m_gridLayout[k];
138             m_gridLayout[k] = new int[m_gridLen[k]];
139             for (int i = 0; i < m_gridLen[k]; ++i)
140                 m_gridDelta[k][i] = 0;
141         }
142     }
143
144     for (int k = 0; k < 2; ++k) {
145         int totalRelative = 0;
146         int totalFixed = 0;
147         int totalPercent = 0;
148         int countRelative = 0;
149         int countPercent = 0;
150         int gridLen = m_gridLen[k];
151         int* gridDelta = m_gridDelta[k];
152         khtml::Length* grid =  k ? element()->m_cols : element()->m_rows;
153         int* gridLayout = m_gridLayout[k];
154
155         if (grid) {
156             // first distribute the available width for fixed rows, then handle the
157             // percentage ones and distribute remaining over relative
158             for(int i = 0; i< gridLen; ++i) {
159                 if (grid[i].isFixed()) {
160                     gridLayout[i] = kMin(grid[i].value > 0 ? grid[i].value : 0, remainingLen[k]);
161                     remainingLen[k] -= gridLayout[i];
162                     totalFixed += gridLayout[i];
163                 }
164                 else if(grid[i].isRelative()) {
165                     totalRelative += grid[i].value > 1 ? grid[i].value : 1;
166                     countRelative++;
167                 }
168                 else if (grid[i].isPercent()) {
169                     totalPercent += grid[i].value >= 0 ? grid[i].value : 0;
170                     countPercent++;
171                 }
172             }
173
174             int currPercent = totalPercent;
175             int percentLen = (countRelative && currPercent < 100) ? currPercent * remainingLen[k] / 100 : remainingLen[k];
176             for(int i = 0; i < gridLen; i++)
177                 if (grid[i].isPercent() && grid[i].value >= 0 && currPercent) {
178                     gridLayout[i] = grid[i].value * percentLen / currPercent;
179                     remainingLen[k] -= gridLayout[i];
180                     percentLen -= gridLayout[i];
181                     currPercent -= grid[i].value;
182                 }
183
184             assert(remainingLen[k] >= 0);
185
186             if (countRelative) {
187                 int remaining = remainingLen[k];
188                 for (int i = 0; i < gridLen; ++i)
189                     if (grid[i].isRelative()) {
190                         gridLayout[i] = ((grid[i].value > 1 ? grid[i].value : 1) * remaining) / totalRelative;
191                         remainingLen[k] -= gridLayout[i];
192                     }
193             }
194
195             // distribute the rest
196             if (remainingLen[k]) {
197                 LengthType distributeType = countPercent ? Percent : Fixed;
198                 int total = countPercent ? totalPercent : totalFixed;
199                 if (!total) total = 1;
200                 for (int i = 0; i < gridLen; ++i)
201                     if (grid[i].type == distributeType) {
202                         int toAdd = (remainingLen[k] * grid[i].value) / total;
203                         gridLayout[i] += toAdd;
204                     }
205             }
206
207             // now we have the final layout, distribute the delta over it
208             bool worked = true;
209             for (int i = 0; i < gridLen; ++i) {
210                 if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
211                     worked = false;
212                 gridLayout[i] += gridDelta[i];
213             }
214             // now the delta's broke something, undo it and reset deltas
215             if (!worked)
216                 for (int i = 0; i < gridLen; ++i) {
217                     gridLayout[i] -= gridDelta[i];
218                     gridDelta[i] = 0;
219                 }
220         }
221         else
222             gridLayout[0] = remainingLen[k];
223     }
224
225     positionFrames();
226
227     RenderObject *child = firstChild();
228     if ( !child )
229         goto end2;
230
231     if(!m_hSplitVar && !m_vSplitVar)
232     {
233 #ifdef DEBUG_LAYOUT
234         kdDebug( 6031 ) << "calculationg fixed Splitters" << endl;
235 #endif
236         if(!m_vSplitVar && element()->totalCols() > 1)
237         {
238             m_vSplitVar = new bool[element()->totalCols()];
239             for(int i = 0; i < element()->totalCols(); i++) m_vSplitVar[i] = true;
240         }
241         if(!m_hSplitVar && element()->totalRows() > 1)
242         {
243             m_hSplitVar = new bool[element()->totalRows()];
244             for(int i = 0; i < element()->totalRows(); i++) m_hSplitVar[i] = true;
245         }
246
247         for(int r = 0; r < element()->totalRows(); r++)
248         {
249             for(int c = 0; c < element()->totalCols(); c++)
250             {
251                 bool fixed = false;
252
253                 if ( child->isFrameSet() )
254                   fixed = static_cast<RenderFrameSet *>(child)->element()->noResize();
255                 else
256                   fixed = static_cast<RenderFrame *>(child)->element()->noResize();
257
258                 if(fixed)
259                 {
260 #ifdef DEBUG_LAYOUT
261                     kdDebug( 6031 ) << "found fixed cell " << r << "/" << c << "!" << endl;
262 #endif
263                     if( element()->totalCols() > 1)
264                     {
265                         if(c>0) m_vSplitVar[c-1] = false;
266                         m_vSplitVar[c] = false;
267                     }
268                     if( element()->totalRows() > 1)
269                     {
270                         if(r>0) m_hSplitVar[r-1] = false;
271                         m_hSplitVar[r] = false;
272                     }
273                     child = child->nextSibling();
274                     if(!child) goto end2;
275                 }
276 #ifdef DEBUG_LAYOUT
277                 else
278                     kdDebug( 6031 ) << "not fixed: " << r << "/" << c << "!" << endl;
279 #endif
280             }
281         }
282
283     }
284     RenderContainer::layout();
285  end2:
286     setNeedsLayout(false);
287 }
288
289 void RenderFrameSet::positionFrames()
290 {
291   int r;
292   int c;
293
294   RenderObject *child = firstChild();
295   if ( !child )
296     return;
297
298   //  NodeImpl *child = _first;
299   //  if(!child) return;
300
301   int yPos = 0;
302
303   for(r = 0; r < element()->totalRows(); r++)
304   {
305     int xPos = 0;
306     for(c = 0; c < element()->totalCols(); c++)
307     {
308       child->setPos( xPos, yPos );
309 #ifdef DEBUG_LAYOUT
310       kdDebug(6040) << "child frame at (" << xPos << "/" << yPos << ") size (" << m_gridLayout[1][c] << "/" << m_gridLayout[0][r] << ")" << endl;
311 #endif
312       // has to be resized and itself resize its contents
313       if ((m_gridLayout[1][c] != child->width()) || (m_gridLayout[0][r] != child->height())) {
314           child->setWidth( m_gridLayout[1][c] );
315           child->setHeight( m_gridLayout[0][r] );
316           child->setNeedsLayout(true);
317           child->layout();
318       }
319
320       xPos += m_gridLayout[1][c] + element()->border();
321       child = child->nextSibling();
322
323       if ( !child )
324         return;
325
326     }
327
328     yPos += m_gridLayout[0][r] + element()->border();
329   }
330
331   // all the remaining frames are hidden to avoid ugly
332   // spurious unflowed frames
333   while ( child ) {
334       child->setWidth( 0 );
335       child->setHeight( 0 );
336       child->setNeedsLayout(false);
337
338       child = child->nextSibling();
339   }
340 }
341
342 bool RenderFrameSet::userResize( MouseEventImpl *evt )
343 {
344     if (needsLayout()) return false;
345     
346     bool res = false;
347     int _x = evt->clientX();
348     int _y = evt->clientY();
349     
350     if ( !m_resizing && evt->id() == EventImpl::MOUSEMOVE_EVENT || evt->id() == EventImpl::MOUSEDOWN_EVENT )
351     {
352 #ifdef DEBUG_LAYOUT
353         kdDebug( 6031 ) << "mouseEvent:check" << endl;
354 #endif
355         
356         m_hSplit = -1;
357         m_vSplit = -1;
358         //bool resizePossible = true;
359         
360         // check if we're over a horizontal or vertical boundary
361         int pos = m_gridLayout[1][0] + xPos();
362         for(int c = 1; c < element()->totalCols(); c++)
363         {
364             if(_x >= pos && _x <= pos+element()->border())
365             {
366             if(m_vSplitVar && m_vSplitVar[c-1] == true) m_vSplit = c-1;
367 #ifdef DEBUG_LAYOUT
368             kdDebug( 6031 ) << "vsplit!" << endl;
369 #endif
370             res = true;
371             break;
372             }
373             pos += m_gridLayout[1][c] + element()->border();
374         }
375         
376         pos = m_gridLayout[0][0] + yPos();
377         for(int r = 1; r < element()->totalRows(); r++)
378         {
379             if( _y >= pos && _y <= pos+element()->border())
380             {
381             if(m_hSplitVar && m_hSplitVar[r-1] == true) m_hSplit = r-1;
382 #ifdef DEBUG_LAYOUT
383             kdDebug( 6031 ) << "hsplitvar = " << m_hSplitVar << endl;
384             kdDebug( 6031 ) << "hsplit!" << endl;
385 #endif
386             res = true;
387             break;
388             }
389             pos += m_gridLayout[0][r] + element()->border();
390         }
391 #ifdef DEBUG_LAYOUT
392         kdDebug( 6031 ) << m_hSplit << "/" << m_vSplit << endl;
393 #endif
394         
395         QCursor cursor;
396         if(m_hSplit != -1 && m_vSplit != -1)
397         {
398             cursor = KCursor::sizeAllCursor();
399         }
400         else if( m_vSplit != -1 )
401         {
402             cursor = KCursor::sizeHorCursor();
403         }
404         else if( m_hSplit != -1 )
405         {
406             cursor = KCursor::sizeVerCursor();
407         }
408         
409         if(evt->id() == EventImpl::MOUSEDOWN_EVENT)
410         {
411             setResizing(true);
412             KApplication::setOverrideCursor(cursor);
413             m_vSplitPos = _x;
414             m_hSplitPos = _y;
415             m_oldpos = -1;
416         }
417         else
418             canvas()->view()->viewport()->setCursor(cursor);
419         
420     }
421     
422     // ### check the resize is not going out of bounds.
423     if(m_resizing && evt->id() == EventImpl::MOUSEUP_EVENT)
424     {
425         setResizing(false);
426         KApplication::restoreOverrideCursor();
427         
428         if(m_vSplit != -1 )
429         {
430         #ifdef DEBUG_LAYOUT
431             kdDebug( 6031 ) << "split xpos=" << _x << endl;
432 #endif
433             int delta = m_vSplitPos - _x;
434             m_gridDelta[1][m_vSplit] -= delta;
435             m_gridDelta[1][m_vSplit+1] += delta;
436         }
437         if(m_hSplit != -1 )
438         {
439 #ifdef DEBUG_LAYOUT
440             kdDebug( 6031 ) << "split ypos=" << _y << endl;
441 #endif
442             int delta = m_hSplitPos - _y;
443             m_gridDelta[0][m_hSplit] -= delta;
444             m_gridDelta[0][m_hSplit+1] += delta;
445         }
446         
447         // this just schedules the relayout
448         // important, otherwise the moving indicator is not correctly erased
449         setNeedsLayout(true);
450     }
451     
452     else if (m_resizing || evt->id() == EventImpl::MOUSEUP_EVENT) {
453 #if APPLE_CHANGES
454         KHTMLView *v = canvas()->view();
455         QPainter paint;
456         
457         v->disableFlushDrawing();
458         v->lockDrawingFocus();
459 #else
460         QPainter paint( canvas()->view() );
461 #endif
462         paint.setPen( Qt::gray );
463         paint.setBrush( Qt::gray );
464         
465 #if !APPLE_CHANGES
466         paint.setRasterOp( Qt::XorROP );
467 #endif
468         QRect r(xPos(), yPos(), width(), height());
469         const int rBord = 3;
470         int sw = element()->border();
471         int p = m_resizing ? (m_vSplit > -1 ? _x : _y) : -1;
472         if (m_vSplit > -1) {
473             if ( m_oldpos >= 0 )
474 #if APPLE_CHANGES
475                 v->updateContents( m_oldpos + sw/2 - rBord , r.y(), 2*rBord, r.height(), true );
476 #else
477                 paint.drawRect( m_oldpos + sw/2 - rBord , r.y(),
478                                 2*rBord, r.height() );
479 #endif
480             if ( p >= 0 ){
481 #if APPLE_CHANGES
482                 paint.setPen( Qt::NoPen );
483                 paint.setBrush( Qt::gray );
484                 v->setDrawingAlpha((float)0.25);
485                 paint.drawRect( p  + sw/2 - rBord, r.y(), 2*rBord, r.height() );
486                 v->setDrawingAlpha((float)1.0);
487 #else
488                 paint.drawRect( p  + sw/2 - rBord, r.y(), 2*rBord, r.height() );
489 #endif
490             }
491         } else {
492             if ( m_oldpos >= 0 )
493 #if APPLE_CHANGES
494                 v->updateContents( r.x(), m_oldpos + sw/2 - rBord, r.width(), 2*rBord, true );
495 #else
496                 paint.drawRect( r.x(), m_oldpos + sw/2 - rBord,
497                                 r.width(), 2*rBord );
498 #endif
499             if ( p >= 0 ){
500 #if APPLE_CHANGES
501                 paint.setPen( Qt::NoPen );
502                 paint.setBrush( Qt::gray );
503                 v->setDrawingAlpha((float)0.25);
504                 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
505                 v->setDrawingAlpha((float)1.0);
506 #else
507                 paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
508 #endif
509             }
510         }
511         m_oldpos = p;
512
513 #if APPLE_CHANGES
514         v->unlockDrawingFocus();
515         v->enableFlushDrawing();
516 #endif
517     }
518     
519     return res;
520 }
521
522 void RenderFrameSet::setResizing(bool e)
523 {
524       m_resizing = e;
525       for (RenderObject* p = parent(); p; p = p->parent())
526           if (p->isFrameSet()) static_cast<RenderFrameSet*>(p)->m_clientresizing = m_resizing;
527 }
528
529 bool RenderFrameSet::canResize( int _x, int _y )
530 {
531     // if we haven't received a layout, then the gridLayout doesn't contain useful data yet
532     if (needsLayout() || !m_gridLayout[0] || !m_gridLayout[1] ) return false;
533
534     // check if we're over a horizontal or vertical boundary
535     int pos = m_gridLayout[1][0];
536     for(int c = 1; c < element()->totalCols(); c++)
537         if(_x >= pos && _x <= pos+element()->border())
538             return true;
539
540     pos = m_gridLayout[0][0];
541     for(int r = 1; r < element()->totalRows(); r++)
542         if( _y >= pos && _y <= pos+element()->border())
543             return true;
544
545     return false;
546 }
547
548 #ifndef NDEBUG
549 void RenderFrameSet::dump(QTextStream *stream, QString ind) const
550 {
551   *stream << " totalrows=" << element()->totalRows();
552   *stream << " totalcols=" << element()->totalCols();
553
554   uint i;
555   for (i = 0; i < (uint)element()->totalRows(); i++)
556     *stream << " hSplitvar(" << i << ")=" << m_hSplitVar[i];
557
558   for (i = 0; i < (uint)element()->totalCols(); i++)
559     *stream << " vSplitvar(" << i << ")=" << m_vSplitVar[i];
560
561   RenderContainer::dump(stream,ind);
562 }
563 #endif
564
565 /**************************************************************************************/
566
567 RenderPart::RenderPart(DOM::HTMLElementImpl* node)
568     : RenderWidget(node)
569 {
570     // init RenderObject attributes
571     setInline(false);
572 }
573
574 RenderPart::~RenderPart()
575 {
576     if(m_widget->inherits("KHTMLView")) {
577         static_cast<KHTMLView *>(m_widget)->deref();
578     }
579 }
580
581 void RenderPart::setWidget( QWidget *widget )
582 {
583 #ifdef DEBUG_LAYOUT
584     kdDebug(6031) << "RenderPart::setWidget()" << endl;
585 #endif
586     
587     if (widget == m_widget) {
588         return;
589     }
590
591     if(m_widget->inherits("KHTMLView")) {
592         static_cast<KHTMLView *>(m_widget)->deref();
593     }
594     
595     if(widget->inherits("KHTMLView")) { 
596         static_cast<KHTMLView *>(widget)->ref();
597         setQWidget( widget, false );
598         connect( widget, SIGNAL( cleared() ), this, SLOT( slotViewCleared() ) );
599     } else {
600         setQWidget( widget );
601     }
602     setNeedsLayoutAndMinMaxRecalc();
603     
604     // make sure the scrollbars are set correctly for restore
605     // ### find better fix
606     slotViewCleared();
607 }
608
609 bool RenderPart::partLoadingErrorNotify(khtml::ChildFrame *, const KURL& , const QString& )
610 {
611     return false;
612 }
613
614 int RenderPart::intrinsicWidth() const
615 {
616   // KDE may need a non-zero width here, although this will mess up pages (e.g., thinker.org).
617 #if APPLE_CHANGES
618     return 0;
619 #else
620     return 300;
621 #endif
622 }
623
624 int RenderPart::intrinsicHeight() const
625 {
626   // KDE may need a non-zero height here, although this will mess up pages (e.g., thinker.org).
627 #if APPLE_CHANGES
628     return 0;
629 #else
630     return 200;
631 #endif
632 }
633
634 void RenderPart::slotViewCleared()
635 {
636 }
637
638 /***************************************************************************************/
639
640 RenderFrame::RenderFrame( DOM::HTMLFrameElementImpl *frame )
641     : RenderPart(frame)
642 {
643     setInline( false );
644 }
645
646 void RenderFrame::slotViewCleared()
647 {
648     if(element() && m_widget->inherits("QScrollView")) {
649 #ifdef DEBUG_LAYOUT
650         kdDebug(6031) << "frame is a scrollview!" << endl;
651 #endif
652         QScrollView *view = static_cast<QScrollView *>(m_widget);
653         if(!element()->frameBorder || !((static_cast<HTMLFrameSetElementImpl *>(element()->parentNode()))->frameBorder()))
654             view->setFrameStyle(QFrame::NoFrame);
655 #if APPLE_CHANGES
656         // Qt creates QScrollView w/ a default style of QFrame::StyledPanel | QFrame::Sunken.
657         else
658             view->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
659
660 #else
661         view->setHScrollBarMode(element()->scrolling );
662         view->setVScrollBarMode(element()->scrolling );
663 #endif
664
665         if(view->inherits("KHTMLView")) {
666 #ifdef DEBUG_LAYOUT
667             kdDebug(6031) << "frame is a KHTMLview!" << endl;
668 #endif
669             KHTMLView *htmlView = static_cast<KHTMLView *>(view);
670             if(element()->marginWidth != -1) htmlView->setMarginWidth(element()->marginWidth);
671             if(element()->marginHeight != -1) htmlView->setMarginHeight(element()->marginHeight);
672         }
673     }
674 }
675
676 /****************************************************************************************/
677
678 RenderPartObject::RenderPartObject( DOM::HTMLElementImpl* element )
679     : RenderPart( element )
680 {
681     // init RenderObject attributes
682     setInline(true);
683 }
684
685 void RenderPartObject::updateWidget()
686 {
687   QString url;
688   QString serviceType;
689   QStringList paramNames;
690   QStringList paramValues;
691   KHTMLPart *part = m_view->part();
692
693   setNeedsLayoutAndMinMaxRecalc();
694
695   if (element()->id() == ID_OBJECT) {
696
697       HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element());
698
699       // Check for a child EMBED tag.
700       HTMLEmbedElementImpl *embed = 0;
701       for (NodeImpl *child = o->firstChild(); child; child = child->nextSibling()) {
702           if (child->id() == ID_EMBED) {
703               embed = static_cast<HTMLEmbedElementImpl *>( child );
704               break;
705           }
706       }
707       
708       // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
709       HTMLElementImpl *embedOrObject;
710       if (embed) {
711           embedOrObject = (HTMLElementImpl *)embed;
712           DOMString attribute = embedOrObject->getAttribute(ATTR_WIDTH);
713           if (!attribute.isEmpty()) {
714               o->setAttribute(ATTR_WIDTH, attribute);
715           }
716           attribute = embedOrObject->getAttribute(ATTR_HEIGHT);
717           if (!attribute.isEmpty()) {
718               o->setAttribute(ATTR_HEIGHT, attribute);
719           }
720           url = embed->url;
721           serviceType = embed->serviceType;
722       } else {
723           embedOrObject = (HTMLElementImpl *)o;
724       }
725       
726       // If there was no URL or type defined in EMBED, try the OBJECT tag.
727       if (url.isEmpty()) {
728           url = o->url;
729       }
730       if (serviceType.isEmpty()) {
731           serviceType = o->serviceType;
732       }
733       
734       QDict<bool> uniqueParamNames(5, false);
735       
736       // Scan the PARAM children.
737       // Get the URL and type from the params if we don't already have them.
738       // Get the attributes from the params if there is no EMBED tag.
739       NodeImpl *child = o->firstChild();
740       while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
741           if (child->id() == ID_PARAM) {
742               HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>( child );
743               QString name = p->name().lower();
744               if (url.isEmpty() && (name == "src" || name == "movie" || name == "code" || name == "url")) {
745                   url = p->value();
746               }
747               if (serviceType.isEmpty() && name == "type") {
748                   serviceType = p->value();
749               }
750               if (!embed) {
751                   bool dummyValue = true;
752                   uniqueParamNames.insert(p->name(), &dummyValue);
753                   paramNames.append(p->name());
754                   paramValues.append(p->value());
755               }
756           }
757           child = child->nextSibling();
758       }
759       
760       // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
761       NamedAttrMapImpl* attributes = embedOrObject->attributes();
762       if (attributes) {
763           for (unsigned long i = 0; i < attributes->length(); ++i) {
764               AttributeImpl* it = attributes->attributeItem(i);
765               QString name = o->getDocument()->attrName(it->id()).string();
766               if (embed || uniqueParamNames.find(name) == 0) {
767                   paramNames.append(name);
768                   paramValues.append(it->value().string());
769               }
770           }
771       }
772       
773       // If we still don't have a type, try to map from a specific CLASSID to a type.
774       if (serviceType.isEmpty() && !o->classId.isEmpty()) {
775           // It is ActiveX, but the nsplugin system handling
776           // should also work, that's why we don't override the
777           // serviceType with application/x-activex-handler
778           // but let the KTrader in khtmlpart::createPart() detect
779           // the user's preference: launch with activex viewer or
780           // with nspluginviewer (Niko)          
781           if (o->classId.contains("D27CDB6E-AE6D-11cf-96B8-444553540000")) {
782               serviceType = "application/x-shockwave-flash";
783           } else if (o->classId.contains("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) {
784               serviceType = "audio/x-pn-realaudio-plugin";
785           } else if (o->classId.contains("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) {
786               serviceType = "video/quicktime";
787           } else if (o->classId.contains("166B1BCA-3F9C-11CF-8075-444553540000")) {
788               serviceType = "application/x-director";
789           } else if (o->classId.contains("6BF52A52-394A-11d3-B153-00C04F79FAA6")) {
790               serviceType = "application/x-mplayer2";
791           } else {
792               // We have a clsid, means this is activex (Niko)
793               serviceType = "application/x-activex-handler";
794           }
795           // TODO: add more plugins here
796       }
797       
798       // If no URL and type, abort.
799       if (url.isEmpty() && serviceType.isEmpty()) {
800 #ifdef DEBUG_LAYOUT
801           kdDebug() << "RenderPartObject::close - empty url and serverType" << endl;
802 #endif
803           return;
804       }
805       // Avoid infinite recursion. If the plug-in's URL is the same as the part's URL, infinite frames may be created.
806       if (!url.isEmpty() && part->completeURL(url) == part->baseURL()) {
807           return;
808       }
809             
810 #if !APPLE_CHANGES      
811       params.append( QString::fromLatin1("__KHTML__CLASSID=\"%1\"").arg( o->classId ) );
812       params.append( QString::fromLatin1("__KHTML__CODEBASE=\"%1\"").arg( o->getAttribute(ATTR_CODEBASE).string() ) );
813 #endif
814
815       part->requestObject( this, url, serviceType, paramNames, paramValues );
816   } else if ( element()->id() == ID_EMBED ) {
817
818       HTMLEmbedElementImpl *o = static_cast<HTMLEmbedElementImpl *>(element());
819       url = o->url;
820       serviceType = o->serviceType;
821
822       if ( url.isEmpty() && serviceType.isEmpty() ) {
823 #ifdef DEBUG_LAYOUT
824           kdDebug() << "RenderPartObject::close - empty url and serverType" << endl;
825 #endif
826           return;
827       }
828       // Avoid infinite recursion. If the plug-in's URL is the same as the part's URL, infinite frames may be created.
829       if (!url.isEmpty() && part->completeURL(url) == part->baseURL()) {
830           return;
831       }
832       // add all attributes set on the embed object
833       NamedAttrMapImpl* a = o->attributes();
834       if (a) {
835           for (unsigned long i = 0; i < a->length(); ++i) {
836               AttributeImpl* it = a->attributeItem(i);
837               paramNames.append(o->getDocument()->attrName(it->id()).string());
838               paramValues.append(it->value().string());
839           }
840       }
841       part->requestObject( this, url, serviceType, paramNames, paramValues );
842   } else {
843       assert(element()->id() == ID_IFRAME);
844       HTMLIFrameElementImpl *o = static_cast<HTMLIFrameElementImpl *>(element());
845       url = o->url.string();
846       if (url.isEmpty()) {
847           url = "about:blank";
848       } else if (part->completeURL(url) == part->baseURL()) {
849           // Avoid infinite recursion. If the frame's URL is the same as the part's URL, infinite frames may be created.
850           return;
851       }
852       KHTMLView *v = static_cast<KHTMLView *>(m_view);
853       bool requestSucceeded = v->part()->requestFrame( this, url, o->name.string(), QStringList(), QStringList(), true );
854       if (requestSucceeded && url == "about:blank") {
855           KHTMLPart *newPart = v->part()->findFrame( o->name.string() );
856           if (newPart && newPart->xmlDocImpl()) {
857               newPart->xmlDocImpl()->setBaseURL( v->part()->baseURL().url() );
858           }
859       }
860   }
861 }
862
863 bool RenderPartObject::partLoadingErrorNotify( khtml::ChildFrame *childFrame, const KURL& url, const QString& serviceType )
864 {
865     KHTMLPart *part = static_cast<KHTMLView *>(m_view)->part();
866     //kdDebug() << "RenderPartObject::partLoadingErrorNotify serviceType=" << serviceType << endl;
867     // Check if we just tried with e.g. nsplugin
868     // and fallback to the activexhandler if there is a classid
869     // and a codebase, where we may download the ocx if it's missing
870     if( serviceType != "application/x-activex-handler" && element()->id()==ID_OBJECT ) {
871
872         // check for embed child object
873         HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element());
874         HTMLEmbedElementImpl *embed = 0;
875         NodeImpl *child = o->firstChild();
876         while ( child ) {
877             if ( child->id() == ID_EMBED )
878                 embed = static_cast<HTMLEmbedElementImpl *>( child );
879
880             child = child->nextSibling();
881         }
882         if( embed && !o->classId.isEmpty() &&
883             !( static_cast<ElementImpl *>(o)->getAttribute(ATTR_CODEBASE).string() ).isEmpty() )
884         {
885             KParts::URLArgs args;
886             args.serviceType = "application/x-activex-handler";
887             if (part->requestObject( childFrame, url, args ))
888                 return true; // success
889         }
890     }
891     // Dissociate ourselves from the current event loop (to prevent crashes
892     // due to the message box staying up)
893     QTimer::singleShot( 0, this, SLOT( slotPartLoadingErrorNotify() ) );
894     Tokenizer *tokenizer = static_cast<DOM::DocumentImpl *>(part->document().handle())->tokenizer();
895     if (tokenizer) tokenizer->setOnHold( true );
896     slotPartLoadingErrorNotify();
897     if (tokenizer) tokenizer->setOnHold( false );
898     return false;
899 }
900
901 void RenderPartObject::slotPartLoadingErrorNotify()
902 {
903 #if APPLE_CHANGES
904     // FIXME: What are we going to do for this case?
905 #else
906     // First we need to find out the servicetype - again - this code is too duplicated !
907     HTMLEmbedElementImpl *embed = 0;
908     QString serviceType;
909     if( element()->id()==ID_OBJECT ) {
910
911         // check for embed child object
912         HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element());
913         serviceType = o->serviceType;
914         NodeImpl *child = o->firstChild();
915         while ( child ) {
916             if ( child->id() == ID_EMBED )
917                 embed = static_cast<HTMLEmbedElementImpl *>( child );
918
919             child = child->nextSibling();
920         }
921
922     } else if( element()->id()==ID_EMBED ) {
923         embed = static_cast<HTMLEmbedElementImpl *>(element());
924     }
925     if ( embed )
926         serviceType = embed->serviceType;
927
928     KHTMLPart *part = static_cast<KHTMLView *>(m_view)->part();
929     KParts::BrowserExtension *ext = part->browserExtension();
930     if( embed && !embed->pluginPage.isEmpty() && ext ) {
931         // Prepare the mimetype to show in the question (comment if available, name as fallback)
932         QString mimeName = serviceType;
933         KMimeType::Ptr mime = KMimeType::mimeType(serviceType);
934         if ( mime->name() != KMimeType::defaultMimeType() )
935             mimeName = mime->comment();
936         // Prepare the URL to show in the question (host only if http, to make it short)
937         KURL pluginPageURL( embed->pluginPage );
938         QString shortURL = pluginPageURL.protocol() == "http" ? pluginPageURL.host() : pluginPageURL.prettyURL();
939         int res = KMessageBox::questionYesNo( m_view,
940             i18n("No plugin found for '%1'.\nDo you want to download one from %2?").arg(mimeName).arg(shortURL),
941             i18n("Missing plugin"), QString::null, QString::null, QString("plugin-")+serviceType);
942         if ( res == KMessageBox::Yes )
943         {
944           // Display vendor download page
945           ext->createNewWindow( pluginPageURL );
946         }
947     }
948 #endif // APPLE_CHANGES
949 }
950
951 void RenderPartObject::layout( )
952 {
953     KHTMLAssert( needsLayout() );
954     KHTMLAssert( minMaxKnown() );
955
956 #if !APPLE_CHANGES
957     int m_oldwidth = m_width;
958     int m_oldheight = m_height;
959 #endif
960
961     calcWidth();
962     calcHeight();
963
964     RenderPart::layout();
965
966     setNeedsLayout(false);
967 }
968
969 void RenderPartObject::slotViewCleared()
970 {
971   if(element() && m_widget->inherits("QScrollView") ) {
972 #ifdef DEBUG_LAYOUT
973       kdDebug(6031) << "iframe is a scrollview!" << endl;
974 #endif
975       QScrollView *view = static_cast<QScrollView *>(m_widget);
976       int frameStyle = QFrame::NoFrame;
977       QScrollView::ScrollBarMode scroll = QScrollView::Auto;
978       int marginw = -1;
979       int marginh = -1;
980       if ( element()->id() == ID_IFRAME) {
981           HTMLIFrameElementImpl *frame = static_cast<HTMLIFrameElementImpl *>(element());
982           if(frame->frameBorder)
983               frameStyle = QFrame::Box;
984           scroll = frame->scrolling;
985           marginw = frame->marginWidth;
986           marginh = frame->marginHeight;
987       }
988       view->setFrameStyle(frameStyle);
989
990 #if !APPLE_CHANGES
991       view->setVScrollBarMode(scroll);
992       view->setHScrollBarMode(scroll);
993 #endif
994
995       if(view->inherits("KHTMLView")) {
996 #ifdef DEBUG_LAYOUT
997           kdDebug(6031) << "frame is a KHTMLview!" << endl;
998 #endif
999           KHTMLView *htmlView = static_cast<KHTMLView *>(view);
1000           htmlView->setIgnoreWheelEvents( element()->id() == ID_IFRAME );
1001           if(marginw != -1) htmlView->setMarginWidth(marginw);
1002           if(marginh != -1) htmlView->setMarginHeight(marginh);
1003         }
1004   }
1005 }
1006
1007 #if APPLE_CHANGES
1008 // FIXME: This should not be necessary.  Remove this once WebKit knows to properly schedule
1009 // layouts using WebCore when objects resize.
1010 void RenderPart::updateWidgetPositions()
1011 {
1012     if (!m_widget)
1013         return;
1014     
1015     int x, y, width, height;
1016     absolutePosition(x,y);
1017     x += borderLeft() + paddingLeft();
1018     y += borderTop() + paddingTop();
1019     width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight();
1020     height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom();
1021     QRect newBounds(x,y,width,height);
1022     if (newBounds != m_widget->frameGeometry()) {
1023         // The widget changed positions.  Update the frame geometry.
1024         RenderArena *arena = ref();
1025         element()->ref();
1026         m_widget->setFrameGeometry(newBounds);
1027         element()->deref();
1028         deref(arena);
1029         
1030         QScrollView *view = static_cast<QScrollView *>(m_widget);
1031         if (view && view->inherits("KHTMLView"))
1032             static_cast<KHTMLView*>(view)->layout();
1033     }
1034 }
1035 #endif
1036
1037 #include "render_frames.moc"