📄 htmlparser.cpp
字号:
/* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) (C) 1997 Torben Weis (weis@kde.org) (C) 1999,2001 Lars Knoll (knoll@kde.org) (C) 2000,2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*///----------------------------------------------------------------------------//// KDE HTML Widget -- HTML Parser//#define PARSER_DEBUG#include "htmlparser.h"#include "dom_nodeimpl.h"#include "dom_exception.h"#include "html_baseimpl.h"#include "html_blockimpl.h"#include "html_documentimpl.h"#include "html_elementimpl.h"#include "html_formimpl.h"#include "html_headimpl.h"#include "html_imageimpl.h"#include "html_inlineimpl.h"#include "html_listimpl.h"#include "html_miscimpl.h"#include "html_tableimpl.h"#include "html_objectimpl.h"#include "dom_textimpl.h"#include "htmlhashes.h"#include "htmltokenizer.h"#include "khtmlview.h"#include "khtml_part.h"#include "cssproperties.h"#include "cssvalues.h"#include "rendering/render_object.h"#include <kdebug.h>#include <klocale.h>using namespace DOM;using namespace khtml;//----------------------------------------------------------------------------/** * @internal */class HTMLStackElem{public: HTMLStackElem( int _id, int _level, DOM::NodeImpl *_node, HTMLStackElem * _next ) : id(_id), level(_level), node(_node), next(_next) { } int id; int level; NodeImpl *node; HTMLStackElem *next;};/** * @internal * * The parser parses tokenized input into the document, building up the * document tree. If the document is wellformed, parsing it is * straightforward. * Unfortunately, people can't write wellformed HTML documents, so the parser * has to be tolerant about errors. * * We have to take care of the following error conditions: * 1. The element being added is explicitly forbidden inside some outer tag. * In this case we should close all tags up to the one, which forbids * the element, and add it afterwards. * 2. We are not allowed to add the element directly. It could be, that * the person writing the document forgot some tag inbetween (or that the * tag inbetween is optional...) This could be the case with the following * tags: HTML HEAD BODY TBODY TR TD LI (did I forget any?) * 3. We wan't to add a block element inside to an inline element. Close all * inline elements up to the next higher block element. * 4. If this doesn't help close elements, until we are allowed to add the * element or ignore the tag. * */KHTMLParser::KHTMLParser( KHTMLView *_parent, DocumentPtr *doc){ //kdDebug( 6035 ) << "parser constructor" << endl;#if SPEED_DEBUG > 0 qt.start();#endif HTMLWidget = _parent; document = doc; document->ref(); blockStack = 0; // ID_CLOSE_TAG == Num of tags forbiddenTag = new ushort[ID_CLOSE_TAG+1]; reset();}KHTMLParser::KHTMLParser( DOM::DocumentFragmentImpl *i, DocumentPtr *doc ){ HTMLWidget = 0; document = doc; document->ref(); forbiddenTag = new ushort[ID_CLOSE_TAG+1]; blockStack = 0; reset(); current = i; inBody = true; inSelect = false;}KHTMLParser::~KHTMLParser(){#if SPEED_DEBUG > 0 kdDebug( ) << "TIME: parsing time was = " << qt.elapsed() << endl;#endif document->deref(); freeBlock(); delete [] forbiddenTag; delete isindex;}void KHTMLParser::reset(){ current = document->document(); freeBlock(); // before parsing no tags are forbidden... memset(forbiddenTag, 0, (ID_CLOSE_TAG+1)*sizeof(ushort)); inBody = false; noRealBody = true; haveFrameSet = false; inSelect = false; _inline = false; form = 0; map = 0; head = 0; end = false; isindex = 0; flat = false; haveKonqBlock = false; discard_until = 0;}void KHTMLParser::parseToken(Token *t){ if (t->id > 2*ID_CLOSE_TAG) { kdDebug( 6035 ) << "Unknown tag!! tagID = " << t->id << endl; return; } if(discard_until) { if(t->id == discard_until) discard_until = 0; // do not skip </iframe> if ( discard_until || current->id() + ID_CLOSE_TAG != t->id ) return; }#ifdef PARSER_DEBUG kdDebug( 6035 ) << "\n\n==> parser: processing token " << getTagName(t->id).string() << "(" << t->id << ")" << " current = " << getTagName(current->id()).string() << "(" << current->id() << ")" << endl; kdDebug(6035) << "inline=" << _inline << " inBody=" << inBody << " noRealBody=" << noRealBody << " haveFrameSet=" << haveFrameSet << endl;#endif // holy shit. apparently some sites use </br> instead of <br> // be compatible with IE and NS if(t->id == ID_BR+ID_CLOSE_TAG && document->document()->parseMode() != DocumentImpl::Strict) t->id -= ID_CLOSE_TAG; if(t->id > ID_CLOSE_TAG) { processCloseTag(t); return; } // ignore spaces, if we're not inside a paragraph or other inline code if( t->id == ID_TEXT ) {#ifdef PARSER_DEBUG if(t->text) kdDebug(6035) << "length="<< t->text->l << " text='" << QConstString(t->text->s, t->text->l).string() << "'" << endl;#endif if ( inBody ) noRealBody = false; } NodeImpl *n = getElement(t); // just to be sure, and to catch currently unimplemented stuff if(!n) return; // set attributes if(n->isElementNode()) { ElementImpl *e = static_cast<ElementImpl *>(n); e->setAttributeMap(t->attrs); // take care of optional close tags if(endTag[e->id()] == DOM::OPTIONAL) popBlock(t->id); } // if this tag is forbidden inside the current context, pop // blocks until we are allowed to add it... while(forbiddenTag[t->id]) popOneBlock(); if ( !insertNode(n) ) { // we couldn't insert the node...#ifdef PARSER_DEBUG kdDebug( 6035 ) << "insertNode failed current=" << current->id() << ", new=" << n->id() << "!" << endl;#endif if (map == n) {#ifdef PARSER_DEBUG kdDebug( 6035 ) << " --> resetting map!" << endl;#endif map = 0; } if (form == n) {#ifdef PARSER_DEBUG kdDebug( 6035 ) << " --> resetting form!" << endl;#endif form = 0; } delete n; }}bool KHTMLParser::insertNode(NodeImpl *n){ int id = n->id(); // let's be stupid and just try to insert it. // this should work if the document is wellformed#ifdef PARSER_DEBUG NodeImpl *tmp = current;#endif NodeImpl *newNode = current->addChild(n); if ( newNode ) {#ifdef PARSER_DEBUG kdDebug( 6035 ) << "added " << n->nodeName().string() << " to " << tmp->nodeName().string() << ", new current=" << newNode->nodeName().string() << endl;#endif // don't push elements without end tag on the stack if(tagPriority[id] != 0 && !flat) { pushBlock(id, tagPriority[id]); current = newNode;#if SPEED_DEBUG < 2 if(!n->attached() && HTMLWidget ) n->attach();#endif //_inline = current->isInline(); if(current->isInline()) _inline = true; } else {#if SPEED_DEBUG < 2 if(!n->attached() && HTMLWidget) n->attach(); if(n->renderer()) n->renderer()->close();#endif flat = false; }#if SPEED_DEBUG < 1 if(tagPriority[id] == 0 && n->renderer()) n->renderer()->calcMinMaxWidth();#endif return true; } else {#ifdef PARSER_DEBUG kdDebug( 6035 ) << "ADDING NODE FAILED!!!! current = " << current->nodeName().string() << ", new = " << n->nodeName().string() << endl;#endif // error handling... HTMLElementImpl *e; bool handled = false; // switch according to the element to insert switch(id) { case ID_COMMENT: break; case ID_HEAD: // ### alllow not having <HTML> in at all, as per HTML spec if (!current->isDocumentNode() && !current->id() == ID_HTML ) return false; break; // We can deal with a base, meta and link element in the body, by just adding the element to head. case ID_META: case ID_LINK: case ID_BASE: if( !head ) createHead(); if( head ) { head->addChild(n);#if SPEED_DEBUG < 2 if(!n->attached() && HTMLWidget) n->attach();#endif return true; } break; case ID_HTML: if (!current->isDocumentNode()) return false; break; case ID_TITLE: case ID_STYLE: if ( !head ) createHead(); if ( head ) { DOM::NodeImpl *newNode = head->addChild(n); if ( newNode ) { pushBlock(id, tagPriority[id]); current = newNode;#if SPEED_DEBUG < 2 if(!n->attached() && HTMLWidget) n->attach();#endif } else {#ifdef PARSER_DEBUG kdDebug( 6035 ) << "adding style before to body failed!!!!" << endl;#endif discard_until = ID_STYLE + ID_CLOSE_TAG; return false; } return true; } else if(inBody) { discard_until = ID_STYLE + ID_CLOSE_TAG; return false; } break; // SCRIPT and OBJECT are allowd in the body. case ID_BODY: if(inBody && doc()->body()) { // we have another <BODY> element.... apply attributes to existing one // make sure we don't overwrite already existing attributes // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor> NamedAttrMapImpl *map = static_cast<NamedAttrMapImpl*>(n->attributes()); NamedAttrMapImpl *bodymap = static_cast<NamedAttrMapImpl*>(doc()->body()->attributes()); unsigned long attrNo; int exceptioncode; bool changed = false; for (attrNo = 0; map && attrNo < map->length(); attrNo++) if(!bodymap->getNamedItem(static_cast<AttrImpl*>(map->item(attrNo))->name())) { doc()->body()->setAttributeNode(static_cast<AttrImpl*>(map->item(attrNo)->cloneNode(false,exceptioncode)), exceptioncode); changed = true; } if ( changed ) doc()->applyChanges(); noRealBody = false; } else if ( current->isDocumentNode() ) break; return false; break; // the following is a hack to move non rendered elements // outside of tables. // needed for broken constructs like <table><form ...><tr>.... case ID_INPUT: { ElementImpl *e = static_cast<ElementImpl *>(n); DOMString type = e->getAttribute(ATTR_TYPE); if ( strcasecmp( type, "hidden" ) != 0 ) break; // Fall through! } case ID_TEXT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -