📄 html.cpp
字号:
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*///----------------------------------------------------------------------------//// KDE HTML Widget#include <kurl.h>#include <kapp.h>#include <kcharsets.h>#include <kimgio.h>#include <kcursor.h>#include <assert.h>#ifdef GrayScale#undef GrayScale#endif#ifdef Color#undef Color#endif#include "htmlchain.h"#include "htmltable.h"#include "html.h"#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <strings.h>//#include <qimage.h>#include <qregexp.h>#include <qkeycode.h>#include <qprinter.h>#include <qdrawutil.h>#include <qbitmap.h>#ifndef _NANOX#include <X11/Xlib.h>#endif//#ifdef HAVE_LIBJPEG//#include "jpeg.h"//#endif#define PRINTING_MARGIN 36 // printed margin in 1/72in units#define INDENT_SIZE 30#define TIMER_INTERVAL 30 // ms between parser parsesenum ID { ID_ADDRESS, ID_BIG, ID_BLOCKQUOTE, ID_B, ID_CELL, ID_CITE, ID_CODE, ID_EM, ID_FONT, ID_HEADER, ID_I, ID_KBD, ID_PRE, ID_SAMP, ID_SMALL, ID_STRIKE, ID_STRONG, ID_S, ID_TEXTAREA, ID_TT, ID_U, ID_CAPTION, ID_TH, ID_TD, ID_TABLE, ID_DIR, ID_MENU, ID_OL, ID_UL, ID_VAR, ID_DIV };//----------------------------------------------------------------------------// convert number to roman numeralsQString toRoman( int number, bool upper ){ QString roman; char ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' }; char udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' }; char *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.insert( 0, digits[ d ] ); if ( num >= 4 && num <= 8) roman.insert( 0, digits[ d+1 ] ); if ( num == 9 ) roman.insert( 0, digits[ d+2 ] ); if ( num % 5 == 4 ) roman.insert( 0, digits[ d ] ); number /= 10; d += 2; } while ( number ); return roman;}void setNamedColor(QColor &color, const char *name){ char *endP; if ((*name != '#') && (strlen(name) == 6) && (strtoul(name, &endP, 16), (endP == name+6)) ) { QString col("#"); col += name; color.setNamedColor(col.data()); } else { color.setNamedColor(name); }}//----------------------------------------------------------------------------HTMLFontManager* pFontManager = 0;// Array of mark parser functions, e.g:// <img ... is processed by KHTMLWidget::parseI()// </ul> is processed by KHTMLWidget::parseU()//parseFunc KHTMLWidget::parseFuncArray[26] = { &KHTMLWidget::parseA, &KHTMLWidget::parseB, &KHTMLWidget::parseC, &KHTMLWidget::parseD, &KHTMLWidget::parseE, &KHTMLWidget::parseF, &KHTMLWidget::parseG, &KHTMLWidget::parseH, &KHTMLWidget::parseI, &KHTMLWidget::parseJ, &KHTMLWidget::parseK, &KHTMLWidget::parseL, &KHTMLWidget::parseM, &KHTMLWidget::parseN, &KHTMLWidget::parseO, &KHTMLWidget::parseP, &KHTMLWidget::parseQ, &KHTMLWidget::parseR, &KHTMLWidget::parseS, &KHTMLWidget::parseT, &KHTMLWidget::parseU, &KHTMLWidget::parseV, &KHTMLWidget::parseW, &KHTMLWidget::parseX, &KHTMLWidget::parseY, &KHTMLWidget::parseZ};#ifdef EXEC_EXTENSIONSKHTMLWidget::KHTMLWidget(QWidget *parent,const char *name,const char *) : KDNDWidget(parent,name,WPaintClever),tempStrings(true),parsedURLs(false),parsedTargets(false),parsedExecs(false)#elseKHTMLWidget::KHTMLWidget(QWidget *parent,const char *name,const char *) : KDNDWidget(parent,name,WPaintClever),tempStrings(true),parsedURLs(false),parsedTargets(false)#endif{ jsEnvironment = 0; leftBorder = LEFT_BORDER; rightBorder = RIGHT_BORDER; topBorder = TOP_BORDER; bottomBorder = BOTTOM_BORDER; x_offset = 0; y_offset = 0; title = ""; clue = 0; italic = false; weight = QFont::Normal; stringTok = 0; ht = 0; colorContext = 0; pressed = false; pressedURL = ""; pressedTarget = "";#ifdef EXEC_EXTENSIONS pressedExec = "";#endif actualURL = ""; baseURL = ""; baseTarget = ""; target = 0; url = 0;#ifdef EXEC_EXTENSIONS exec = 0;#endif bIsSelected = false; selectedFrame = 0; htmlView = 0; bIsFrameSet = false; bIsFrame = false; frameSet = 0; bFramesComplete = false; painter = 0; parsing = false; overURL = ""; granularity = 600; linkCursor = KCursor::arrowCursor(); bIsTextSelected = false; charsetConverter = 0; blockStack = 0; memPoolMax = 0; currentKeySeq = ""; initialXPos = 0; initialYPos = 0; mapPendingFiles.setAutoDelete( true ); framesetStack.setAutoDelete( false ); framesetList.setAutoDelete( false ); frameList.setAutoDelete( false ); // XXX waitingFileList.setAutoDelete( false ); formList.setAutoDelete( true ); listStack.setAutoDelete( true ); glossaryStack.setAutoDelete( true ); mapList.setAutoDelete( true ); colorStack.setAutoDelete( true ); /* parsedURLs.setAutoDelete( true ); parsedTargets.setAutoDelete( true ); standardFont = "times"; fixedFont = "courier"; */ defaultSettings = new HTMLSettings; settings = new HTMLSettings; QPalette pal = palette().copy(); QColorGroup cg = pal.normal(); QColorGroup newGroup( cg.foreground(), lightGray, cg.light(), cg.dark(), cg.mid(), cg.text(), lightGray ); pal.setNormal( newGroup ); setPalette( pal ); setBackgroundColor( lightGray ); QString f = kapp->kde_datadir().copy(); f += "/khtmlw/pics/khtmlw_dnd.xpm"; dndDefaultPixmap.load( f.data() ); registerFormats(); setMouseTracking( true ); connect( &updateTimer, SIGNAL( timeout() ), SLOT( slotUpdate() ) ); connect( &autoScrollYTimer, SIGNAL(timeout()), SLOT( slotAutoScrollY() ) ); if ( !pFontManager ) pFontManager = new HTMLFontManager(); textFindIter = 0;}void KHTMLWidget::requestFile( HTMLObject *_obj, const char *_url ){ // waitingFileList.append( _obj ); // emit fileRequest( _url ); //printf("========================= REQUEST %s ================\n", _url ); /////////////// // The new code /////////////// HTMLPendingFile *p = mapPendingFiles[ _url ]; if ( p ) { p->m_lstClients.append( _obj ); return; } p = new HTMLPendingFile( _url, _obj ); mapPendingFiles.insert( _url, p ); emit fileRequest( _url ); // Initialize all the scroll blob stuff. // Even if you undef out the other stuff, the blob's hooks // are still inited.#ifdef USE_THE_BLOB_ALEX_MADE // What the hell does this do in fileRequest()??????? scrollBlob=0; scrollBlobType = SCROLL_NONE; scrollBlobPixmap=QPixmap(); scrollBlobTimer = new QTimer (this, "scrollBlobTimer"); QObject::connect (scrollBlobTimer, SIGNAL(timeout()), this, SLOT(scrollBlobTimeout()));#endif}void KHTMLWidget::cancelRequestFile( HTMLObject *_obj ){ /* if ( waitingFileList.findRef( _obj ) != -1 ) { waitingFileList.removeRef( _obj ); emit cancelFileRequest( _obj->requestedFile() ); } */ /////////////// // The new code /////////////// QStrList lst; QDictIterator<HTMLPendingFile> it( mapPendingFiles ); for( ; it.current(); ++it ) { it.current()->m_lstClients.removeRef( _obj ); if ( it.current()->m_lstClients.count() == 0 ) { // emit cancelFileRequest( it.current()->m_strURL ); // emit cancelFileRequest( " "); emit fileRequest(" " ); lst.append( it.currentKey() ); } } const char* u; for( u = lst.first(); u != 0L; u = lst.next() ) { mapPendingFiles.remove( u ); }}void KHTMLWidget::cancelAllRequests(){ /* HTMLObject *o; for ( o = waitingFileList.first(); o != 0; o = waitingFileList.next() ) emit cancelFileRequest( o->requestedFile() ); waitingFileList.clear(); */ /////////////// // The new code /////////////// QDictIterator<HTMLPendingFile> it( mapPendingFiles ); for( ; it.current(); ++it ) emit cancelFileRequest( it.current()->m_strURL ); mapPendingFiles.clear();}void KHTMLWidget::requestBackgroundImage( const char *_url ){ bgPixmapURL = _url; bgPixmapURL.detach(); emit fileRequest( _url );}void KHTMLWidget::data( const char *_url, const char *_data, int _len, bool _eof ){ /////////////// // The new code /////////////// bool do_update = false; HTMLPendingFile *p = mapPendingFiles[ _url ]; if ( !p ) { return; } // end of if if ( !p->m_buffer.isOpen() ) p->m_buffer.open( IO_WriteOnly ); p->m_buffer.writeBlock( _data, _len ); if ( _eof ) { p->m_buffer.close(); HTMLObject* o; for( o = p->m_lstClients.first(); o != 0L; o = p->m_lstClients.next() ) if ( o->fileLoaded( _url, p->m_buffer ) ) do_update = true; mapPendingFiles.remove( _url ); } if ( do_update ) { calcSize(); calcAbsolutePos(); scheduleUpdate( true ); } if ( mapPendingFiles.count() == 0 && !parsing ) { emit documentDone(); } // end of if// else// {// cerr << "There are " << mapPendingFiles.count() << " remaining on queue.\n";// } // end of else }static boolfixBackground(QPixmap &bgPixmap, const QBrush &brush){#define BGMINWIDTH 50#define BGMINHEIGHT 25 if (bgPixmap.isNull()) return false; int w = bgPixmap.width(); int h = bgPixmap.height(); if (w < BGMINWIDTH) { int factor = ((BGMINWIDTH+w-1) / w);//printf("Scaling pixmap %d times in X-direction\n", factor); QPixmap newPixmap(w * factor, h); QPainter p; p.begin(&newPixmap); p.fillRect(0,0, w*factor, h, brush ); for(int i=0; i < factor; i++) p.drawPixmap(i*w, 0, bgPixmap); p.end(); bgPixmap = newPixmap; w = w * factor; } if (h < BGMINHEIGHT) { int factor = ((BGMINHEIGHT+h-1) / h);//printf("Scaling pixmap %d times in Y-direction\n", factor); QPixmap newPixmap(w, h*factor); QPainter p; p.begin(&newPixmap); p.fillRect(0,0, w, h*factor, brush); for(int i=0; i < factor; i++) p.drawPixmap(0, i*h, bgPixmap); p.end(); bgPixmap = newPixmap; h = h * factor; } return true;}void KHTMLWidget::slotFileLoaded( const char *_url, const char *_filename ){ //printf("///////// FileLoaded %s %s ////////////\n",_url,_filename ); HTMLPendingFile *p = mapPendingFiles[ _url ]; if ( !p ) { // FIXME: The bgpixmap should use the cache too... if ( !bgPixmapURL.isEmpty() ) { // Did the background image arrive ? if ( strcmp( bgPixmapURL, _url ) == 0 ) { bgPixmap.load( _filename ); bgPixmapURL = 0; if (fixBackground(bgPixmap, settings->bgColor)) scheduleUpdate( true ); } } return; } assert( !p->m_buffer.isOpen() ); HTMLObject* o; for( o = p->m_lstClients.first(); o != 0L; o = p->m_lstClients.next() ) o->fileLoaded( _filename ); mapPendingFiles.remove( _url ); if ( mapPendingFiles.count() == 0 && !parsing ) emit documentDone(); /////////////// // The old code /////////////// /* QList<HTMLObject> del; del.setAutoDelete( FALSE ); HTMLObject *p; for ( p = waitingFileList.first(); p != 0; p = waitingFileList.next() ) { if ( strcmp( _url, p->requestedFile() ) == 0 ) { del.append( p ); p->fileLoaded( _filename ); } } // Are we waiting for the background image ? if ( !bgPixmapURL.isEmpty() ) { // Did the background image arrive ? if ( strcmp( bgPixmapURL, _url ) == 0 ) { bgPixmap.load( _filename ); bgPixmapURL = 0; scheduleUpdate( true ); } } for ( p = del.first(); p != 0; p = del.next() ) waitingFileList.removeRef( p ); if ( waitingFileList.count() == 0 ) { if ( !parsing ) { emit documentDone(); } } */}void KHTMLWidget::slotFormSubmitted( const char *_method, const char *_url, const char *_data ){ emit formSubmitted( _method, _url, _data );}void KHTMLWidget::mouseMoveEvent( QMouseEvent *e ){#ifdef USE_THE_BLOB_ALEX_MADE if (scrollBlob) { if (e->pos().y() < scrollBlob->y()) { scrollBlobType = SCROLL_UP; if (scrollBlobType != SCROLL_UP) scrollBlobTimeout(); } else if (e->pos().y() > scrollBlob->y()+scrollBlob->height()) { scrollBlobType=SCROLL_DOWN; if (scrollBlobType != SCROLL_DOWN) scrollBlobTimeout(); } else { scrollBlobType=SCROLL_NONE; } }#endif KDNDWidget::mouseMoveEvent(e);}void KHTMLWidget::mousePressEvent( QMouseEvent *_mouse ){ if ( clue == 0 ) return; // Make this frame the active one if ( bIsFrame && !bIsSelected ) htmlView->setSelected( TRUE );#ifdef USE_THE_BLOB_ALEX_MADE if (_mouse->button() == MidButton ) { // If we have a blob already, then remove the old one before // we create another one. if (scrollBlob) clearBlob(); // Create a new blob at the site of the mouse click setBlob (_mouse->pos()); return; } clearBlob(); #endif if ( clue->mouseEvent( _mouse->x() + x_offset - leftBorder, _mouse->y() + y_offset - topBorder, _mouse->button(), _mouse->state() ) ) return; if ( _mouse->button() == LeftButton || _mouse->button() == MidButton ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -