DH 2012-11-15 01:39:56 +02:00
parent de070bf485
commit a90b5cf37a
1998 changed files with 1034301 additions and 0 deletions

914
wxWidgets/src/html/chm.cpp Normal file
View file

@ -0,0 +1,914 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/chm.cpp
// Purpose: CHM (Help) support for wxHTML
// Author: Markus Sinner
// Copyright: (c) 2003 Herd Software Development
// CVS-ID: $Id: chm.cpp 65784 2010-10-08 11:16:54Z MW $
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_LIBMSPACK
#include <mspack.h>
#ifndef WXPRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/module.h"
#endif
#include "wx/filesys.h"
#include "wx/mstream.h"
#include "wx/wfstream.h"
#include "wx/html/forcelnk.h"
FORCE_LINK_ME(wxhtml_chm_support)
// ----------------------------------------------------------------------------
/// wxChmTools
/// <p>
/// this class is used to abstract access to CHM-Archives
/// with library mspack written by Stuart Caie
/// http://www.kyz.uklinux.net/libmspack/
// ----------------------------------------------------------------------------
class wxChmTools
{
public:
/// constructor
wxChmTools(const wxFileName &archive);
/// destructor
~wxChmTools();
/// Generate error-string for error-code
static const wxString ChmErrorMsg(int error);
/// get an array of archive-member-filenames
const wxArrayString *GetFileNames()
{
return m_fileNames;
};
/// get the name of the archive representated by this class
const wxString GetArchiveName()
{
return m_chmFileName;
};
/// Find a file in the archive
const wxString Find(const wxString& pattern,
const wxString& startfrom = wxEmptyString);
/// Extract a file in the archive into a file
size_t Extract(const wxString& pattern, const wxString& filename);
/// check archive for a file
bool Contains(const wxString& pattern);
/// get a string for the last error which occurred
const wxString GetLastErrorMessage();
/// Last Error
int m_lasterror;
private:
// these vars are used by FindFirst/Next:
wxString m_chmFileName;
char *m_chmFileNameANSI;
/// mspack-pointer to mschmd_header
struct mschmd_header *m_archive;
/// mspack-pointer to mschm_decompressor
struct mschm_decompressor *m_decompressor;
/// Array of filenames in archive
wxArrayString * m_fileNames;
/// Internal function to get filepointer
struct mschmd_file *GetMschmdFile(const wxString& pattern);
};
/***
* constructor
*
* @param archive The filename of the archive to open
*/
wxChmTools::wxChmTools(const wxFileName &archive)
{
m_chmFileName = archive.GetFullPath();
wxASSERT_MSG( !m_chmFileName.empty(), _T("empty archive name") );
m_archive = NULL;
m_decompressor = NULL;
m_fileNames = NULL;
m_lasterror = 0;
struct mschmd_header *chmh;
struct mschm_decompressor *chmd;
struct mschmd_file *file;
// Create decompressor
chmd = mspack_create_chm_decompressor(NULL);
m_decompressor = (struct mschm_decompressor *) chmd;
// NB: we must make a copy of the string because chmd->open won't call
// strdup() [libmspack-20030726], which would cause crashes in
// Unicode build when mb_str() returns temporary buffer
m_chmFileNameANSI = strdup((const char*)m_chmFileName.mb_str(wxConvFile));
// Open the archive and store it in class:
if ( (chmh = chmd->open(chmd, (char*)m_chmFileNameANSI)) )
{
m_archive = chmh;
// Create Filenamearray
m_fileNames = new wxArrayString;
// Store Filenames in array
for (file = chmh->files; file; file = file->next)
{
m_fileNames->Add(wxString::FromAscii(file->filename));
}
}
else
{
wxLogError(_("Failed to open CHM archive '%s'."),
archive.GetFullPath().c_str());
m_lasterror = (chmd->last_error(chmd));
return;
}
}
/***
* Destructor
*/
wxChmTools::~wxChmTools()
{
struct mschm_decompressor *chmd = m_decompressor;
struct mschmd_header *chmh = m_archive;
delete m_fileNames;
// Close Archive
if (chmh && chmd)
chmd->close(chmd, chmh);
free(m_chmFileNameANSI);
// Destroy Decompressor
if (chmd)
mspack_destroy_chm_decompressor(chmd);
}
/**
* Checks if the given pattern matches to any
* filename stored in archive
*
* @param pattern The filename pattern, may include '*' and/or '?'
* @return true, if any file matching pattern has been found,
* false if not
*/
bool wxChmTools::Contains(const wxString& pattern)
{
int count;
wxString pattern_tmp = wxString(pattern).MakeLower();
// loop through filearay
if ( m_fileNames && (count = m_fileNames->GetCount()) > 0 )
{
for (int i = 0; i < count; i++)
{
wxString tmp = m_fileNames->Item(i).MakeLower();
if ( tmp.Matches(pattern_tmp) || tmp.Mid(1).Matches(pattern_tmp))
return true;
}
}
return false;
}
/**
* Find()
*
* Finds the next file descibed by a pattern in the archive, starting
* the file given by second parameter
*
* @param pattern The file-pattern to search for. May contain '*' and/or '?'
* @param startfrom The filename which the search should start after
* @returns The full pathname of the found file
*/
const wxString wxChmTools::Find(const wxString& pattern,
const wxString& startfrom)
{
int count;
wxString tmp;
wxString pattern_tmp(pattern);
wxString startfrom_tmp(startfrom);
pattern_tmp.MakeLower();
startfrom_tmp.MakeLower();
if ( m_fileNames && (count = m_fileNames->GetCount()) > 0 )
{
for (int i = 0; i < count; i++)
{
tmp = m_fileNames->Item(i).MakeLower();
// if we find the string where the search should began
if ( tmp.Matches(startfrom_tmp) ||
tmp.Mid(1).Matches(startfrom_tmp) )
continue;
if ( tmp.Matches(pattern_tmp) ||
tmp.Mid(1).Matches(pattern_tmp) )
{
return tmp;
}
}
}
return wxEmptyString;
}
/**
* Extract ()
*
* extracts the first hit of pattern to the given position
*
* @param pattern A filename pattern (may contain * and ? chars)
* @param filename The FileName where to temporary extract the file to
* @return 0 at no file extracted<br>
* number of bytes extracted else
*/
size_t wxChmTools::Extract(const wxString& pattern, const wxString& filename)
{
struct mschm_decompressor *d = m_decompressor;
struct mschmd_header *h = m_archive;
struct mschmd_file *f;
wxString tmp;
wxString pattern_tmp = (wxString(pattern)).MakeLower();
for (f = h->files; f; f = f->next)
{
tmp = wxString::FromAscii(f->filename).MakeLower();
if ( tmp.Matches(pattern_tmp) ||
tmp.Mid(1).Matches(pattern_tmp) )
{
// ignore leading '/'
if (d->extract(d, f,
(char*)(const char*)filename.mb_str(wxConvFile)))
{
// Error
m_lasterror = d->last_error(d);
wxLogError(_("Could not extract %s into %s: %s"),
wxString::FromAscii(f->filename).c_str(),
filename.c_str(),
ChmErrorMsg(m_lasterror).c_str());
return 0;
}
else
{
return (size_t) f->length;
}
}
}
return 0;
}
/**
* Find a file by pattern
*
* @param pattern A filename pattern (may contain * and ? chars)
* @return A pointer to the file (mschmd_file*)
*/
struct mschmd_file *wxChmTools::GetMschmdFile(const wxString& pattern_orig)
{
struct mschmd_file *f;
struct mschmd_header *h = (struct mschmd_header *) m_archive;
wxString tmp;
wxString pattern = wxString(pattern_orig).MakeLower();
for (f = h->files; f; f = f->next)
{
tmp = wxString::FromAscii(f->filename).MakeLower();
if ( tmp.Matches(pattern) || tmp.Mid(1).Matches(pattern) )
{
// ignore leading '/'
return f;
}
}
return NULL;
}
const wxString wxChmTools::GetLastErrorMessage()
{
return ChmErrorMsg(m_lasterror);
}
const wxString wxChmTools::ChmErrorMsg(int error)
{
switch (error)
{
case MSPACK_ERR_OK:
return _("no error");
case MSPACK_ERR_ARGS:
return _("bad arguments to library function");
case MSPACK_ERR_OPEN:
return _("error opening file");
case MSPACK_ERR_READ:
return _("read error");
case MSPACK_ERR_WRITE:
return _("write error");
case MSPACK_ERR_SEEK:
return _("seek error");
case MSPACK_ERR_NOMEMORY:
return _("out of memory");
case MSPACK_ERR_SIGNATURE:
return _("bad signature");
case MSPACK_ERR_DATAFORMAT:
return _("error in data format");
case MSPACK_ERR_CHECKSUM:
return _("checksum error");
case MSPACK_ERR_CRUNCH:
return _("compression error");
case MSPACK_ERR_DECRUNCH:
return _("decompression error");
}
return _("unknown error");
}
// ---------------------------------------------------------------------------
/// wxChmInputStream
// ---------------------------------------------------------------------------
class wxChmInputStream : public wxInputStream
{
public:
/// Constructor
wxChmInputStream(const wxString& archive,
const wxString& file, bool simulate = false);
/// Destructor
virtual ~wxChmInputStream();
/// Return the size of the accessed file in archive
virtual size_t GetSize() const { return m_size; }
/// End of Stream?
virtual bool Eof() const;
/// Set simulation-mode of HHP-File (if non is found)
void SimulateHHP(bool sim) { m_simulateHHP = sim; }
protected:
/// See wxInputStream
virtual size_t OnSysRead(void *buffer, size_t bufsize);
/// See wxInputStream
virtual wxFileOffset OnSysSeek(wxFileOffset seek, wxSeekMode mode);
/// See wxInputStream
virtual wxFileOffset OnSysTell() const { return m_pos; }
private:
size_t m_size;
wxFileOffset m_pos;
bool m_simulateHHP;
char * m_content;
wxInputStream * m_contentStream;
void CreateHHPStream();
bool CreateFileStream(const wxString& pattern);
// this void* is handle of archive . I'm sorry it is void and not proper
// type but I don't want to make unzip.h header public.
// locates the file and returns a mspack_file *
mspack_file *LocateFile(wxString filename);
// should store pointer to current file
mspack_file *m_file;
// The Chm-Class for extracting the data
wxChmTools *m_chm;
wxString m_fileName;
};
/**
* Constructor
* @param archive The name of the .chm archive. Remember that archive must
* be local file accesible via fopen, fread functions!
* @param filename The Name of the file to be extracted from archive
* @param simulate if true than class should simulate .HHP-File based on #SYSTEM
* if false than class does nothing if it doesnt find .hhp
*/
wxChmInputStream::wxChmInputStream(const wxString& archive,
const wxString& filename, bool simulate)
: wxInputStream()
{
m_pos = 0;
m_size = 0;
m_content = NULL;
m_contentStream = NULL;
m_lasterror = wxSTREAM_NO_ERROR;
m_chm = new wxChmTools (wxFileName(archive));
m_file = NULL;
m_fileName = wxString(filename).MakeLower();
m_simulateHHP = simulate;
if ( !m_chm->Contains(m_fileName) )
{
// if the file could not be located, but was *.hhp, than we create
// the content of the hhp-file on the fly and store it for reading
// by the application
if ( m_fileName.Find(_T(".hhp")) != wxNOT_FOUND && m_simulateHHP )
{
// now we open an hhp-file
CreateHHPStream();
}
else
{
wxLogError(_("Could not locate file '%s'."), filename.c_str());
m_lasterror = wxSTREAM_READ_ERROR;
return;
}
}
else
{ // file found
CreateFileStream(m_fileName);
}
}
wxChmInputStream::~wxChmInputStream()
{
delete m_chm;
delete m_contentStream;
if (m_content)
{
free (m_content);
m_content=NULL;
}
}
bool wxChmInputStream::Eof() const
{
return (m_content==NULL ||
m_contentStream==NULL ||
m_contentStream->Eof() ||
m_pos>m_size);
}
size_t wxChmInputStream::OnSysRead(void *buffer, size_t bufsize)
{
if ( m_pos >= m_size )
{
m_lasterror = wxSTREAM_EOF;
return 0;
}
m_lasterror = wxSTREAM_NO_ERROR;
// If the rest to read from the stream is less
// than the buffer size, than only read the rest
if ( m_pos + bufsize > m_size )
bufsize = m_size - m_pos;
m_contentStream->SeekI(m_pos);
m_contentStream->Read(buffer, bufsize);
m_pos +=bufsize;
m_contentStream->SeekI(m_pos);
return bufsize;
}
wxFileOffset wxChmInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
{
wxString mode_str = wxEmptyString;
if ( !m_contentStream || m_contentStream->Eof() )
{
m_lasterror = wxSTREAM_EOF;
return 0;
}
m_lasterror = wxSTREAM_NO_ERROR;
wxFileOffset nextpos;
switch ( mode )
{
case wxFromCurrent:
nextpos = seek + m_pos;
break;
case wxFromStart:
nextpos = seek;
break;
case wxFromEnd:
nextpos = m_size - 1 + seek;
break;
default:
nextpos = m_pos;
break; /* just to fool compiler, never happens */
}
m_pos=nextpos;
// Set current position on stream
m_contentStream->SeekI(m_pos);
return m_pos;
}
/**
* Help Browser tries to read the contents of the
* file by interpreting a .hhp file in the Archiv.
* For .chm doesnt include such a file, we need
* to rebuild the information based on stored
* system-files.
*/
void
wxChmInputStream::CreateHHPStream()
{
wxFileName file;
bool topic = false;
bool hhc = false;
bool hhk = false;
wxInputStream *i;
wxMemoryOutputStream *out;
const char *tmp;
// Try to open the #SYSTEM-File and create the HHP File out of it
// see http://bonedaddy.net/pabs3/chmspec/0.1.2/Internal.html#SYSTEM
if ( ! m_chm->Contains(_T("/#SYSTEM")) )
{
#ifdef DEBUG
wxLogDebug(_("Archive doesnt contain #SYSTEM file"));
#endif
return;
}
else
{
file = wxFileName(_T("/#SYSTEM"));
}
if ( CreateFileStream(_T("/#SYSTEM")) )
{
// New stream for writing a memory area to simulate the
// .hhp-file
out = new wxMemoryOutputStream();
tmp = "[OPTIONS]\r\n";
out->Write((const void *) tmp, strlen(tmp));
wxUint16 code;
wxUint16 len;
void *buf;
// use the actual stream for reading
i = m_contentStream;
/* Now read the contents, and try to get the needed information */
// First 4 Bytes are Version information, skip
i->SeekI(4);
while (!i->Eof())
{
// Read #SYSTEM-Code and length
i->Read(&code, 2);
code = wxUINT16_SWAP_ON_BE( code ) ;
i->Read(&len, 2);
len = wxUINT16_SWAP_ON_BE( len ) ;
// data
buf = malloc(len);
i->Read(buf, len);
switch (code)
{
case 0: // CONTENTS_FILE
if (len)
{
tmp = "Contents file=";
hhc=true;
}
break;
case 1: // INDEX_FILE
tmp = "Index file=";
hhk = true;
break;
case 2: // DEFAULT_TOPIC
tmp = "Default Topic=";
topic = true;
break;
case 3: // TITLE
tmp = "Title=";
break;
// case 6: // COMPILED_FILE
// tmp = "Compiled File=";
// break;
case 7: // COMPILED_FILE
tmp = "Binary Index=YES\r\n";
out->Write( (const void *) tmp, strlen(tmp));
tmp = NULL;
break;
case 4: // STRUCT SYSTEM INFO
tmp = NULL ;
if ( len >= 28 )
{
char *structptr = (char*) buf ;
// LCID at position 0
wxUint32 dummy = *((wxUint32 *)(structptr+0)) ;
wxUint32 lcid = wxUINT32_SWAP_ON_BE( dummy ) ;
char msg[64];
int len = sprintf(msg, "Language=0x%X\r\n", lcid) ;
if (len > 0)
out->Write(msg, len) ;
}
break ;
default:
tmp=NULL;
}
if (tmp)
{
out->Write((const void *) tmp, strlen(tmp));
out->Write(buf, strlen((char*)buf));
out->Write("\r\n", 2);
}
free(buf);
buf=NULL;
}
// Free the old data which wont be used any more
delete m_contentStream;
if (m_content)
free (m_content);
// Now add entries which are missing
if ( !hhc && m_chm->Contains(_T("*.hhc")) )
{
tmp = "Contents File=*.hhc\r\n";
out->Write((const void *) tmp, strlen(tmp));
}
if ( !hhk && m_chm->Contains(_T("*.hhk")) )
{
tmp = "Index File=*.hhk\r\n";
out->Write((const void *) tmp, strlen(tmp));
}
// Now copy the Data from the memory
out->SeekO(0, wxFromEnd);
m_size = out->TellO();
out->SeekO(0, wxFromStart);
m_content = (char *) malloc (m_size+1);
out->CopyTo(m_content, m_size);
m_content[m_size]='\0';
m_size++;
m_contentStream = new wxMemoryInputStream(m_content, m_size);
delete out;
}
}
/**
* Creates a Stream pointing to a virtual file in
* the current archive
*/
bool wxChmInputStream::CreateFileStream(const wxString& pattern)
{
wxFileInputStream * fin;
wxString tmpfile = wxFileName::CreateTempFileName(_T("chmstrm"));
if ( tmpfile.empty() )
{
wxLogError(_("Could not create temporary file '%s'"), tmpfile.c_str());
return false;
}
// try to extract the file
if ( m_chm->Extract(pattern, tmpfile) <= 0 )
{
wxLogError(_("Extraction of '%s' into '%s' failed."),
pattern.c_str(), tmpfile.c_str());
if ( wxFileExists(tmpfile) )
wxRemoveFile(tmpfile);
return false;
}
else
{
// Open a filestream to extracted file
fin = new wxFileInputStream(tmpfile);
m_size = fin->GetSize();
m_content = (char *) malloc(m_size+1);
fin->Read(m_content, m_size);
m_content[m_size]='\0';
wxRemoveFile(tmpfile);
delete fin;
m_contentStream = new wxMemoryInputStream (m_content, m_size);
return m_contentStream->IsOk();
}
}
// ----------------------------------------------------------------------------
// wxChmFSHandler
// ----------------------------------------------------------------------------
class wxChmFSHandler : public wxFileSystemHandler
{
public:
/// Constructor and Destructor
wxChmFSHandler();
virtual ~wxChmFSHandler();
/// Is able to open location?
virtual bool CanOpen(const wxString& location);
/// Open a file
virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location);
/// Find first occurrence of spec
virtual wxString FindFirst(const wxString& spec, int flags = 0);
/// Find next occurrence of spec
virtual wxString FindNext();
private:
int m_lasterror;
wxString m_pattern;
wxString m_found;
wxChmTools * m_chm;
};
wxChmFSHandler::wxChmFSHandler() : wxFileSystemHandler()
{
m_lasterror=0;
m_pattern=wxEmptyString;
m_found=wxEmptyString;
m_chm=NULL;
}
wxChmFSHandler::~wxChmFSHandler()
{
if (m_chm)
delete m_chm;
}
bool wxChmFSHandler::CanOpen(const wxString& location)
{
wxString p = GetProtocol(location);
return (p == _T("chm")) &&
(GetProtocol(GetLeftLocation(location)) == _T("file"));
}
wxFSFile* wxChmFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs),
const wxString& location)
{
wxString right = GetRightLocation(location);
wxString left = GetLeftLocation(location);
wxInputStream *s;
int index;
if ( GetProtocol(left) != _T("file") )
{
wxLogError(_("CHM handler currently supports only local files!"));
return NULL;
}
// Work around javascript
wxString tmp = wxString(right);
if ( tmp.MakeLower().Contains(_T("javascipt")) && tmp.Contains(_T("\'")) )
{
right = right.AfterFirst(_T('\'')).BeforeLast(_T('\''));
}
// now work on the right location
if (right.Contains(_T("..")))
{
wxFileName abs(right);
abs.MakeAbsolute(_T("/"));
right = abs.GetFullPath();
}
// a workaround for absolute links to root
if ( (index=right.Index(_T("//"))) != wxNOT_FOUND )
{
right=wxString(right.Mid(index+1));
wxLogWarning(_("Link contained '//', converted to absolute link."));
}
wxFileName leftFilename = wxFileSystem::URLToFileName(left);
if (!leftFilename.FileExists())
return NULL;
// Open a stream to read the content of the chm-file
s = new wxChmInputStream(leftFilename.GetFullPath(), right, true);
wxString mime = GetMimeTypeFromExt(location);
if ( s )
{
return new wxFSFile(s,
left + _T("#chm:") + right,
mime,
GetAnchor(location),
wxDateTime(leftFilename.GetModificationTime()));
}
delete s;
return NULL;
}
/**
* Doku see wxFileSystemHandler
*/
wxString wxChmFSHandler::FindFirst(const wxString& spec, int flags)
{
wxString right = GetRightLocation(spec);
wxString left = GetLeftLocation(spec);
wxString nativename = wxFileSystem::URLToFileName(left).GetFullPath();
if ( GetProtocol(left) != _T("file") )
{
wxLogError(_("CHM handler currently supports only local files!"));
return wxEmptyString;
}
m_chm = new wxChmTools(wxFileName(nativename));
m_pattern = right.AfterLast(_T('/'));
wxString m_found = m_chm->Find(m_pattern);
// now fake around hhp-files which are not existing in projects...
if (m_found.empty() &&
m_pattern.Contains(_T(".hhp")) &&
!m_pattern.Contains(_T(".hhp.cached")))
{
m_found.Printf(_T("%s#chm:%s.hhp"),
left.c_str(), m_pattern.BeforeLast(_T('.')).c_str());
}
return m_found;
}
wxString wxChmFSHandler::FindNext()
{
if (m_pattern.empty())
return wxEmptyString;
else
return m_chm->Find(m_pattern, m_found);
}
// ---------------------------------------------------------------------------
// wxModule to register CHM handler
// ---------------------------------------------------------------------------
class wxChmSupportModule : public wxModule
{
DECLARE_DYNAMIC_CLASS(wxChmSupportModule)
public:
virtual bool OnInit()
{
wxFileSystem::AddHandler(new wxChmFSHandler);
return true;
}
virtual void OnExit() {}
}
;
IMPLEMENT_DYNAMIC_CLASS(wxChmSupportModule, wxModule)
#endif // wxUSE_LIBMSPACK

View file

@ -0,0 +1,96 @@
#*****************************************************************************
# *
# Make file for VMS *
# Author : J.Jansen (joukj@hrem.nano.tudelft.nl) *
# Date : 13 February 2006 *
# *
#*****************************************************************************
.first
define wx [--.include.wx]
.ifdef __WXMOTIF__
CXX_DEFINE = /define=(__WXMOTIF__=1)/name=(as_is,short)\
/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXMOTIF__=1)/name=(as_is,short)
.else
.ifdef __WXGTK__
CXX_DEFINE = /define=(__WXGTK__=1)/float=ieee/name=(as_is,short)/ieee=denorm\
/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXGTK__=1)/float=ieee/name=(as_is,short)/ieee=denorm
.else
.ifdef __WXGTK2__
CXX_DEFINE = /define=(__WXGTK__=1,VMS_GTK2=1)/float=ieee/name=(as_is,short)/ieee=denorm\
/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXGTK__=1,VMS_GTK2=1)/float=ieee/name=(as_is,short)/ieee=denorm
.else
.ifdef __WXX11__
CXX_DEFINE = /define=(__WXX11__=1,__WXUNIVERSAL__==1)/float=ieee\
/name=(as_is,short)/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXX11__=1,__WXUNIVERSAL__==1)/float=ieee\
/name=(as_is,short)
.else
CXX_DEFINE =
CC_DEFINE =
.endif
.endif
.endif
.endif
.suffixes : .cpp
.cpp.obj :
cxx $(CXXFLAGS)$(CXX_DEFINE) $(MMS$TARGET_NAME).cpp
.c.obj :
cc $(CFLAGS)$(CC_DEFINE) $(MMS$TARGET_NAME).c
OBJECTS = \
helpctrl.obj,helpdata.obj,helpfrm.obj,htmlcell.obj,htmlfilt.obj,\
htmlpars.obj,htmltag.obj,htmlwin.obj,htmprint.obj,m_dflist.obj,\
m_fonts.obj,m_hline.obj,m_image.obj,m_layout.obj,m_links.obj,\
m_list.obj,m_pre.obj,m_tables.obj,winpars.obj,chm.obj,m_style.obj
SOURCES = \
helpctrl.cpp,helpdata.cpp,helpfrm.cpp,htmlcell.cpp,htmlfilt.cpp,\
htmlpars.cpp,htmltag.cpp,htmlwin.cpp,htmprint.cpp,m_dflist.cpp,\
m_fonts.cpp,m_hline.cpp,m_image.cpp,m_layout.cpp,m_links.cpp,\
m_list.cpp,m_pre.cpp,m_tables.cpp,winpars.cpp,chm.cpp,m_style.cpp
all : $(SOURCES)
$(MMS)$(MMSQUALIFIERS) $(OBJECTS)
.ifdef __WXMOTIF__
library [--.lib]libwx_motif.olb $(OBJECTS)
.else
.ifdef __WXGTK__
library [--.lib]libwx_gtk.olb $(OBJECTS)
.else
.ifdef __WXGTK2__
library [--.lib]libwx_gtk2.olb $(OBJECTS)
.else
.ifdef __WXX11__
library [--.lib]libwx_x11_univ.olb $(OBJECTS)
.endif
.endif
.endif
.endif
helpctrl.obj : helpctrl.cpp
helpdata.obj : helpdata.cpp
helpfrm.obj : helpfrm.cpp
htmlcell.obj : htmlcell.cpp
htmlfilt.obj : htmlfilt.cpp
htmlpars.obj : htmlpars.cpp
htmltag.obj : htmltag.cpp
htmlwin.obj : htmlwin.cpp
htmprint.obj : htmprint.cpp
m_dflist.obj : m_dflist.cpp
m_fonts.obj : m_fonts.cpp
m_hline.obj : m_hline.cpp
m_image.obj : m_image.cpp
m_layout.obj : m_layout.cpp
m_links.obj : m_links.cpp
m_list.obj : m_list.cpp
m_pre.obj : m_pre.cpp
m_tables.obj : m_tables.cpp
winpars.obj : winpars.cpp
chm.obj : chm.cpp
m_style.obj : m_style.cpp

View file

@ -0,0 +1,442 @@
/////////////////////////////////////////////////////////////////////////////
// Name: helpctrl.cpp
// Purpose: wxHtmlHelpController
// Notes: Based on htmlhelp.cpp, implementing a monolithic
// HTML Help controller class, by Vaclav Slavik
// Author: Harm van der Heijden and Vaclav Slavik
// RCS-ID: $Id: helpctrl.cpp 52470 2008-03-13 23:29:27Z VS $
// Copyright: (c) Harm van der Heijden and Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_WXHTML_HELP
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/intl.h"
#endif // WX_PRECOMP
#include "wx/busyinfo.h"
#include "wx/html/helpctrl.h"
#include "wx/html/helpwnd.h"
#include "wx/html/helpfrm.h"
#include "wx/html/helpdlg.h"
#if wxUSE_HELP
#include "wx/tipwin.h"
#endif
#if wxUSE_LIBMSPACK
#include "wx/html/forcelnk.h"
FORCE_LINK(wxhtml_chm_support)
#endif
IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpController, wxHelpControllerBase)
wxHtmlHelpController::wxHtmlHelpController(int style, wxWindow* parentWindow):
wxHelpControllerBase(parentWindow)
{
m_helpWindow = NULL;
m_helpFrame = NULL;
m_helpDialog = NULL;
m_Config = NULL;
m_ConfigRoot = wxEmptyString;
m_titleFormat = _("Help: %s");
m_FrameStyle = style;
}
wxHtmlHelpController::~wxHtmlHelpController()
{
if (m_Config)
WriteCustomization(m_Config, m_ConfigRoot);
if (m_helpWindow)
DestroyHelpWindow();
}
void wxHtmlHelpController::DestroyHelpWindow()
{
if (m_FrameStyle & wxHF_EMBEDDED)
return;
// Find top-most parent window
// If a modal dialog
wxWindow* parent = FindTopLevelWindow();
if (parent)
{
wxDialog* dialog = wxDynamicCast(parent, wxDialog);
if (dialog && dialog->IsModal())
{
dialog->EndModal(wxID_OK);
}
parent->Destroy();
m_helpWindow = NULL;
}
m_helpDialog = NULL;
m_helpFrame = NULL;
}
void wxHtmlHelpController::OnCloseFrame(wxCloseEvent& evt)
{
if (m_Config)
WriteCustomization(m_Config, m_ConfigRoot);
evt.Skip();
OnQuit();
if ( m_helpWindow )
m_helpWindow->SetController(NULL);
m_helpWindow = NULL;
m_helpDialog = NULL;
m_helpFrame = NULL;
}
void wxHtmlHelpController::SetTitleFormat(const wxString& title)
{
m_titleFormat = title;
wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
if (frame)
{
frame->SetTitleFormat(title);
}
else if (dialog)
dialog->SetTitleFormat(title);
}
// Find the top-most parent window
wxWindow* wxHtmlHelpController::FindTopLevelWindow()
{
wxWindow* parent = m_helpWindow;
while (parent && !parent->IsTopLevel())
{
parent = parent->GetParent();
}
return parent;
}
bool wxHtmlHelpController::AddBook(const wxFileName& book_file, bool show_wait_msg)
{
return AddBook(wxFileSystem::FileNameToURL(book_file), show_wait_msg);
}
bool wxHtmlHelpController::AddBook(const wxString& book, bool show_wait_msg)
{
wxBusyCursor cur;
#if wxUSE_BUSYINFO
wxBusyInfo* busy = NULL;
wxString info;
if (show_wait_msg)
{
info.Printf(_("Adding book %s"), book.c_str());
busy = new wxBusyInfo(info);
}
#endif
bool retval = m_helpData.AddBook(book);
#if wxUSE_BUSYINFO
if (show_wait_msg)
delete busy;
#else
wxUnusedVar(show_wait_msg);
#endif
if (m_helpWindow)
m_helpWindow->RefreshLists();
return retval;
}
wxHtmlHelpFrame* wxHtmlHelpController::CreateHelpFrame(wxHtmlHelpData *data)
{
wxHtmlHelpFrame* frame = new wxHtmlHelpFrame(data);
frame->SetController(this);
frame->Create(m_parentWindow, -1, wxEmptyString, m_FrameStyle, m_Config, m_ConfigRoot);
frame->SetTitleFormat(m_titleFormat);
m_helpFrame = frame;
return frame;
}
wxHtmlHelpDialog* wxHtmlHelpController::CreateHelpDialog(wxHtmlHelpData *data)
{
wxHtmlHelpDialog* dialog = new wxHtmlHelpDialog(data);
dialog->SetController(this);
dialog->SetTitleFormat(m_titleFormat);
dialog->Create(m_parentWindow, -1, wxEmptyString, m_FrameStyle);
m_helpDialog = dialog;
return dialog;
}
wxWindow* wxHtmlHelpController::CreateHelpWindow()
{
if (m_helpWindow)
{
if (m_FrameStyle & wxHF_EMBEDDED)
return m_helpWindow;
wxWindow* topLevelWindow = FindTopLevelWindow();
if (topLevelWindow)
topLevelWindow->Raise();
return m_helpWindow;
}
if (m_Config == NULL)
{
m_Config = wxConfigBase::Get(false);
if (m_Config != NULL)
m_ConfigRoot = _T("wxWindows/wxHtmlHelpController");
}
if (m_FrameStyle & wxHF_DIALOG)
{
wxHtmlHelpDialog* dialog = CreateHelpDialog(&m_helpData);
m_helpWindow = dialog->GetHelpWindow();
}
else if ((m_FrameStyle & wxHF_EMBEDDED) && m_parentWindow)
{
m_helpWindow = new wxHtmlHelpWindow(m_parentWindow, -1, wxDefaultPosition, wxDefaultSize,
wxTAB_TRAVERSAL|wxNO_BORDER, m_FrameStyle, &m_helpData);
}
else // wxHF_FRAME
{
wxHtmlHelpFrame* frame = CreateHelpFrame(&m_helpData);
m_helpWindow = frame->GetHelpWindow();
frame->Show(true);
}
return m_helpWindow;
}
void wxHtmlHelpController::ReadCustomization(wxConfigBase* cfg, const wxString& path)
{
/* should not be called by the user; call UseConfig, and the controller
* will do the rest */
if (m_helpWindow && cfg)
m_helpWindow->ReadCustomization(cfg, path);
}
void wxHtmlHelpController::WriteCustomization(wxConfigBase* cfg, const wxString& path)
{
/* typically called by the controllers OnCloseFrame handler */
if (m_helpWindow && cfg)
m_helpWindow->WriteCustomization(cfg, path);
}
void wxHtmlHelpController::UseConfig(wxConfigBase *config, const wxString& rootpath)
{
m_Config = config;
m_ConfigRoot = rootpath;
if (m_helpWindow) m_helpWindow->UseConfig(config, rootpath);
ReadCustomization(config, rootpath);
}
//// Backward compatibility with wxHelpController API
bool wxHtmlHelpController::Initialize(const wxString& file)
{
wxString dir, filename, ext;
wxSplitPath(file, & dir, & filename, & ext);
if (!dir.empty())
dir = dir + wxFILE_SEP_PATH;
// Try to find a suitable file
wxString actualFilename = dir + filename + wxString(wxT(".zip"));
if (!wxFileExists(actualFilename))
{
actualFilename = dir + filename + wxString(wxT(".htb"));
if (!wxFileExists(actualFilename))
{
actualFilename = dir + filename + wxString(wxT(".hhp"));
if (!wxFileExists(actualFilename))
{
#if wxUSE_LIBMSPACK
actualFilename = dir + filename + wxString(wxT(".chm"));
if (!wxFileExists(actualFilename))
#endif
return false;
}
}
}
return AddBook(wxFileName(actualFilename));
}
bool wxHtmlHelpController::LoadFile(const wxString& WXUNUSED(file))
{
// Don't reload the file or we'll have it appear again, presumably.
return true;
}
bool wxHtmlHelpController::DisplaySection(int sectionNo)
{
return Display(sectionNo);
}
bool wxHtmlHelpController::DisplayTextPopup(const wxString& text, const wxPoint& WXUNUSED(pos))
{
#if wxUSE_TIPWINDOW
static wxTipWindow* s_tipWindow = NULL;
if (s_tipWindow)
{
// Prevent s_tipWindow being nulled in OnIdle,
// thereby removing the chance for the window to be closed by ShowHelp
s_tipWindow->SetTipWindowPtr(NULL);
s_tipWindow->Close();
}
s_tipWindow = NULL;
if ( !text.empty() )
{
s_tipWindow = new wxTipWindow(wxTheApp->GetTopWindow(), text, 100, & s_tipWindow);
return true;
}
#else
wxUnusedVar(text);
#endif // wxUSE_TIPWINDOW
return false;
}
void wxHtmlHelpController::SetHelpWindow(wxHtmlHelpWindow* helpWindow)
{
m_helpWindow = helpWindow;
if (helpWindow)
helpWindow->SetController(this);
}
void wxHtmlHelpController::SetFrameParameters(const wxString& title,
const wxSize& size,
const wxPoint& pos,
bool WXUNUSED(newFrameEachTime))
{
SetTitleFormat(title);
wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
if (frame)
frame->SetSize(pos.x, pos.y, size.x, size.y);
else if (dialog)
dialog->SetSize(pos.x, pos.y, size.x, size.y);
}
wxFrame* wxHtmlHelpController::GetFrameParameters(wxSize *size,
wxPoint *pos,
bool *newFrameEachTime)
{
if (newFrameEachTime)
(* newFrameEachTime) = false;
wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
if (frame)
{
if (size)
(* size) = frame->GetSize();
if (pos)
(* pos) = frame->GetPosition();
return frame;
}
else if (dialog)
{
if (size)
(* size) = dialog->GetSize();
if (pos)
(* pos) = dialog->GetPosition();
return NULL;
}
return NULL;
}
bool wxHtmlHelpController::Quit()
{
DestroyHelpWindow();
return true;
}
// Make the help controller's frame 'modal' if
// needed
void wxHtmlHelpController::MakeModalIfNeeded()
{
if ((m_FrameStyle & wxHF_EMBEDDED) == 0)
{
wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
if (frame)
frame->AddGrabIfNeeded();
else if (dialog && (m_FrameStyle & wxHF_MODAL))
{
dialog->ShowModal();
}
}
}
bool wxHtmlHelpController::Display(const wxString& x)
{
CreateHelpWindow();
bool success = m_helpWindow->Display(x);
MakeModalIfNeeded();
return success;
}
bool wxHtmlHelpController::Display(int id)
{
CreateHelpWindow();
bool success = m_helpWindow->Display(id);
MakeModalIfNeeded();
return success;
}
bool wxHtmlHelpController::DisplayContents()
{
CreateHelpWindow();
bool success = m_helpWindow->DisplayContents();
MakeModalIfNeeded();
return success;
}
bool wxHtmlHelpController::DisplayIndex()
{
CreateHelpWindow();
bool success = m_helpWindow->DisplayIndex();
MakeModalIfNeeded();
return success;
}
bool wxHtmlHelpController::KeywordSearch(const wxString& keyword,
wxHelpSearchMode mode)
{
CreateHelpWindow();
bool success = m_helpWindow->KeywordSearch(keyword, mode);
MakeModalIfNeeded();
return success;
}
/*
* wxHtmlModalHelp
* A convenience class, to use like this:
*
* wxHtmlModalHelp help(parent, helpFile, topic);
*/
wxHtmlModalHelp::wxHtmlModalHelp(wxWindow* parent, const wxString& helpFile, const wxString& topic, int style)
{
// Force some mandatory styles
style |= wxHF_DIALOG | wxHF_MODAL;
wxHtmlHelpController controller(style, parent);
controller.Initialize(helpFile);
if (topic.IsEmpty())
controller.DisplayContents();
else
controller.DisplaySection(topic);
}
#endif // wxUSE_WXHTML_HELP

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/helpdlg.cpp
// Purpose: wxHtmlHelpDialog
// Notes: Based on htmlhelp.cpp, implementing a monolithic
// HTML Help controller class, by Vaclav Slavik
// Author: Harm van der Heijden, Vaclav Slavik and Julian Smart
// RCS-ID: $Id: helpdlg.cpp 50074 2007-11-19 09:12:08Z JS $
// Copyright: (c) Harm van der Heijden, Vaclav Slavik and Julian Smart
// Licence: wxWidgets licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h"
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_WXHTML_HELP
#ifndef WXPRECOMP
#include "wx/object.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/sizer.h"
#include "wx/bmpbuttn.h"
#include "wx/statbox.h"
#include "wx/radiobox.h"
#include "wx/menu.h"
#include "wx/msgdlg.h"
#endif // WXPRECOMP
#include "wx/html/htmlwin.h"
#include "wx/html/helpdlg.h"
#include "wx/html/helpctrl.h"
#include "wx/artprov.h"
IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpDialog, wxDialog)
BEGIN_EVENT_TABLE(wxHtmlHelpDialog, wxDialog)
EVT_CLOSE(wxHtmlHelpDialog::OnCloseWindow)
END_EVENT_TABLE()
wxHtmlHelpDialog::wxHtmlHelpDialog(wxWindow* parent, wxWindowID id, const wxString& title,
int style, wxHtmlHelpData* data)
{
Init(data);
Create(parent, id, title, style);
}
void wxHtmlHelpDialog::Init(wxHtmlHelpData* data)
{
// Simply pass the pointer on to the help window
m_Data = data;
m_HtmlHelpWin = NULL;
m_helpController = NULL;
}
// Create: builds the GUI components.
bool wxHtmlHelpDialog::Create(wxWindow* parent, wxWindowID id,
const wxString& WXUNUSED(title), int style)
{
m_HtmlHelpWin = new wxHtmlHelpWindow(m_Data);
wxDialog::Create(parent, id, _("Help"),
wxPoint(m_HtmlHelpWin->GetCfgData().x, m_HtmlHelpWin->GetCfgData().y),
wxSize(m_HtmlHelpWin->GetCfgData().w, m_HtmlHelpWin->GetCfgData().h),
wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, wxT("wxHtmlHelp"));
m_HtmlHelpWin->Create(this, wxID_ANY, wxDefaultPosition, GetClientSize(),
wxTAB_TRAVERSAL|wxNO_BORDER, style);
GetPosition(& (m_HtmlHelpWin->GetCfgData().x), & (m_HtmlHelpWin->GetCfgData()).y);
SetIcon(wxArtProvider::GetIcon(wxART_HELP, wxART_HELP_BROWSER));
wxWindow* item1 = this;
wxBoxSizer* item2 = new wxBoxSizer(wxVERTICAL);
item1->SetSizer(item2);
item1->SetAutoLayout(true);
wxWindow* item3 = m_HtmlHelpWin;
item2->Add(item3, 1, wxGROW|wxALL, 5);
wxBoxSizer* item4 = new wxBoxSizer(wxHORIZONTAL);
item2->Add(item4, 0, wxGROW, 5);
item4->Add(5, 5, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* item6 = new wxButton(item1, wxID_OK, _("Close"), wxDefaultPosition, wxDefaultSize, 0);
item4->Add(item6, 0, wxALIGN_CENTER_VERTICAL|wxALL, 10);
#ifdef __WXMAC__
// Add some space for the resize handle
item4->Add(5, 5, 0, wxALIGN_CENTER_VERTICAL, 0);
#endif
Layout();
Centre();
return true;
}
wxHtmlHelpDialog::~wxHtmlHelpDialog()
{
}
void wxHtmlHelpDialog::SetTitleFormat(const wxString& format)
{
m_TitleFormat = format;
}
void wxHtmlHelpDialog::OnCloseWindow(wxCloseEvent& evt)
{
if (!IsIconized())
{
GetSize(& (m_HtmlHelpWin->GetCfgData().w), &(m_HtmlHelpWin->GetCfgData().h));
GetPosition(& (m_HtmlHelpWin->GetCfgData().x), & (m_HtmlHelpWin->GetCfgData().y));
}
if (m_HtmlHelpWin->GetSplitterWindow() && m_HtmlHelpWin->GetCfgData().navig_on)
m_HtmlHelpWin->GetCfgData().sashpos = m_HtmlHelpWin->GetSplitterWindow()->GetSashPosition();
if (m_helpController)
{
m_helpController->OnCloseFrame(evt);
}
evt.Skip();
}
#endif // wxUSE_WXHTML_HELP

View file

@ -0,0 +1,241 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/helpfrm.cpp
// Purpose: wxHtmlHelpFrame
// Notes: Based on htmlhelp.cpp, implementing a monolithic
// HTML Help controller class, by Vaclav Slavik
// Author: Harm van der Heijden and Vaclav Slavik
// RCS-ID: $Id: helpfrm.cpp 56234 2008-10-11 20:18:19Z VS $
// Copyright: (c) Harm van der Heijden and Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h"
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_WXHTML_HELP
#ifndef WXPRECOMP
#include "wx/object.h"
#include "wx/dynarray.h"
#include "wx/intl.h"
#include "wx/log.h"
#if wxUSE_STREAMS
#include "wx/stream.h"
#endif
#include "wx/sizer.h"
#include "wx/bmpbuttn.h"
#include "wx/statbox.h"
#include "wx/radiobox.h"
#include "wx/menu.h"
#include "wx/settings.h"
#include "wx/msgdlg.h"
#include "wx/textctrl.h"
#include "wx/toolbar.h"
#include "wx/choicdlg.h"
#include "wx/filedlg.h"
#endif // WXPRECOMP
#include "wx/html/helpfrm.h"
#include "wx/html/helpctrl.h"
#include "wx/notebook.h"
#include "wx/imaglist.h"
#include "wx/treectrl.h"
#include "wx/tokenzr.h"
#include "wx/wfstream.h"
#include "wx/html/htmlwin.h"
#include "wx/busyinfo.h"
#include "wx/progdlg.h"
#include "wx/fontenum.h"
#include "wx/artprov.h"
#include "wx/spinctrl.h"
IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpFrame, wxFrame)
BEGIN_EVENT_TABLE(wxHtmlHelpFrame, wxFrame)
EVT_ACTIVATE(wxHtmlHelpFrame::OnActivate)
EVT_CLOSE(wxHtmlHelpFrame::OnCloseWindow)
#ifdef __WXMAC__
EVT_MENU(wxID_CLOSE, wxHtmlHelpFrame::OnClose)
EVT_MENU(wxID_ABOUT, wxHtmlHelpFrame::OnAbout)
EVT_MENU(wxID_HELP_CONTENTS, wxHtmlHelpFrame::OnAbout)
#endif
END_EVENT_TABLE()
wxHtmlHelpFrame::wxHtmlHelpFrame(wxWindow* parent, wxWindowID id, const wxString& title,
int style, wxHtmlHelpData* data,
wxConfigBase *config, const wxString& rootpath)
{
Init(data);
Create(parent, id, title, style, config, rootpath);
}
void wxHtmlHelpFrame::Init(wxHtmlHelpData* data)
{
// Simply pass the pointer on to the help window
m_Data = data;
m_HtmlHelpWin = NULL;
m_helpController = (wxHtmlHelpController*) NULL;
}
// Create: builds the GUI components.
bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id,
const wxString& WXUNUSED(title), int style,
wxConfigBase *config, const wxString& rootpath)
{
m_HtmlHelpWin = new wxHtmlHelpWindow(m_Data);
m_HtmlHelpWin->SetController(m_helpController);
if ( config)
m_HtmlHelpWin->UseConfig(config, rootpath);
wxFrame::Create(parent, id, _("Help"),
wxPoint(m_HtmlHelpWin->GetCfgData().x, m_HtmlHelpWin->GetCfgData().y),
wxSize(m_HtmlHelpWin->GetCfgData().w, m_HtmlHelpWin->GetCfgData().h),
wxDEFAULT_FRAME_STYLE, wxT("wxHtmlHelp"));
#if wxUSE_STATUSBAR
CreateStatusBar();
#endif
m_HtmlHelpWin->Create(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxTAB_TRAVERSAL|wxNO_BORDER, style);
GetPosition(& (m_HtmlHelpWin->GetCfgData().x), & (m_HtmlHelpWin->GetCfgData()).y);
SetIcon(wxArtProvider::GetIcon(wxART_HELP, wxART_FRAME_ICON));
// On the Mac, each modeless frame must have a menubar.
// TODO: add more menu items, and perhaps add a style to show
// the menubar: compulsory on the Mac, optional elsewhere.
#ifdef __WXMAC__
wxMenuBar* menuBar = new wxMenuBar;
wxMenu* fileMenu = new wxMenu;
fileMenu->Append(wxID_HTML_OPENFILE, _("&Open..."));
fileMenu->AppendSeparator();
fileMenu->Append(wxID_CLOSE, _("&Close"));
wxMenu* helpMenu = new wxMenu;
helpMenu->Append(wxID_ABOUT, _("&About..."));
// Ensures we don't get an empty help menu
helpMenu->Append(wxID_HELP_CONTENTS, _("&About..."));
menuBar->Append(fileMenu,_("&File"));
menuBar->Append(helpMenu,_("&Help"));
SetMenuBar(menuBar);
#endif
m_HtmlHelpWin->GetHtmlWindow()->SetRelatedFrame(this, m_TitleFormat);
#if wxUSE_STATUSBAR
m_HtmlHelpWin->GetHtmlWindow()->SetRelatedStatusBar(0);
#endif
return true;
}
wxHtmlHelpFrame::~wxHtmlHelpFrame()
{
}
void wxHtmlHelpFrame::SetTitleFormat(const wxString& format)
{
if (GetHelpWindow() && GetHelpWindow()->GetHtmlWindow())
GetHelpWindow()->GetHtmlWindow()->SetRelatedFrame(this, format);
m_TitleFormat = format;
}
/*
EVENT HANDLING :
*/
void wxHtmlHelpFrame::OnActivate(wxActivateEvent& event)
{
// This saves one mouse click when using the
// wxHTML for context sensitive help systems
#ifndef __WXGTK__
// NB: wxActivateEvent is a bit broken in wxGTK
// and is sometimes sent when it should not be
if (event.GetActive() && m_HtmlHelpWin)
m_HtmlHelpWin->GetHtmlWindow()->SetFocus();
#endif
event.Skip();
}
void wxHtmlHelpFrame::OnCloseWindow(wxCloseEvent& evt)
{
if (!IsIconized())
{
GetSize(& (m_HtmlHelpWin->GetCfgData().w), &(m_HtmlHelpWin->GetCfgData().h));
GetPosition(& (m_HtmlHelpWin->GetCfgData().x), & (m_HtmlHelpWin->GetCfgData().y));
}
#ifdef __WXGTK__
if (IsGrabbed())
{
RemoveGrab();
}
#endif
if (m_HtmlHelpWin->GetSplitterWindow() && m_HtmlHelpWin->GetCfgData().navig_on)
m_HtmlHelpWin->GetCfgData().sashpos = m_HtmlHelpWin->GetSplitterWindow()->GetSashPosition();
if (m_helpController && m_helpController->IsKindOf(CLASSINFO(wxHtmlHelpController)))
{
((wxHtmlHelpController*) m_helpController)->OnCloseFrame(evt);
}
evt.Skip();
}
// Make the help controller's frame 'modal' if
// needed
void wxHtmlHelpFrame::AddGrabIfNeeded()
{
// So far, wxGTK only
#ifdef __WXGTK__
bool needGrab = false;
// Check if there are any modal windows present,
// in which case we need to add a grab.
for ( wxWindowList::iterator it = wxTopLevelWindows.begin();
it != wxTopLevelWindows.end();
++it )
{
wxWindow *win = *it;
wxDialog *dialog = wxDynamicCast(win, wxDialog);
if (dialog && dialog->IsModal())
needGrab = true;
}
if (needGrab)
AddGrab();
#endif // __WXGTK__
}
// For compatibility
void wxHtmlHelpFrame::UseConfig(wxConfigBase *config, const wxString& rootPath)
{
if (m_HtmlHelpWin)
m_HtmlHelpWin->UseConfig(config, rootPath);
}
#ifdef __WXMAC__
void wxHtmlHelpFrame::OnClose(wxCommandEvent& event)
{
Close(true);
}
void wxHtmlHelpFrame::OnAbout(wxCommandEvent& event)
{
wxMessageBox(wxT("wxWidgets HTML Help Viewer (c) 1998-2006, Vaclav Slavik et al"), wxT("HelpView"),
wxICON_INFORMATION|wxOK, this);
}
#endif
#endif // wxUSE_WXHTML_HELP

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,892 @@
/////////////////////////////////////////////////////////////////////////////
// Name: webkit.mm
// Purpose: wxWebKitCtrl - embeddable web kit control
// Author: Jethro Grassie / Kevin Ollivier
// Modified by:
// Created: 2004-4-16
// RCS-ID: $Id: webkit.mm 56767 2008-11-14 23:02:15Z KO $
// Copyright: (c) Jethro Grassie / Kevin Ollivier
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "webkit.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/splitter.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#if wxUSE_WEBKIT
#ifdef __WXCOCOA__
#include "wx/cocoa/autorelease.h"
#else
#include "wx/mac/uma.h"
#include <Carbon/Carbon.h>
#include <WebKit/WebKit.h>
#include <WebKit/HIWebView.h>
#include <WebKit/CarbonUtils.h>
#endif
#include "wx/html/webkit.h"
#define DEBUG_WEBKIT_SIZING 0
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxWebKitCtrl, wxControl)
BEGIN_EVENT_TABLE(wxWebKitCtrl, wxControl)
EVT_SIZE(wxWebKitCtrl::OnSize)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------
// Carbon Events handlers
// ----------------------------------------------------------------------------
// prototype for function in src/mac/carbon/toplevel.cpp
void SetupMouseEvent( wxMouseEvent &wxevent , wxMacCarbonEvent &cEvent );
static const EventTypeSpec eventList[] =
{
//{ kEventClassControl, kEventControlTrack } ,
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassKeyboard, kEventRawKeyDown } ,
{ kEventClassKeyboard, kEventRawKeyRepeat } ,
{ kEventClassKeyboard, kEventRawKeyUp } ,
{ kEventClassKeyboard, kEventRawKeyModifiersChanged } ,
{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
{ kEventClassTextInput, kEventTextInputUpdateActiveInputArea } ,
#if DEBUG_WEBKIT_SIZING == 1
{ kEventClassControl, kEventControlBoundsChanged } ,
#endif
};
// mix this in from window.cpp
pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) ;
// NOTE: This is mostly taken from KeyboardEventHandler in toplevel.cpp, but
// that expects the data pointer is a top-level window, so I needed to change
// that in this case. However, once 2.8 is out, we should factor out the common logic
// among the two functions and merge them.
static pascal OSStatus wxWebKitKeyEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
{
OSStatus result = eventNotHandledErr ;
wxMacCarbonEvent cEvent( event ) ;
wxWebKitCtrl* thisWindow = (wxWebKitCtrl*) data ;
wxWindow* focus = thisWindow ;
unsigned char charCode ;
wxChar uniChar[2] ;
uniChar[0] = 0;
uniChar[1] = 0;
UInt32 keyCode ;
UInt32 modifiers ;
Point point ;
UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ;
#if wxUSE_UNICODE
ByteCount dataSize = 0 ;
if ( GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0 , &dataSize, NULL ) == noErr )
{
UniChar buf[2] ;
int numChars = dataSize / sizeof( UniChar) + 1;
UniChar* charBuf = buf ;
if ( numChars * 2 > 4 )
charBuf = new UniChar[ numChars ] ;
GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize , NULL , charBuf ) ;
charBuf[ numChars - 1 ] = 0;
#if SIZEOF_WCHAR_T == 2
uniChar = charBuf[0] ;
#else
wxMBConvUTF16 converter ;
converter.MB2WC( uniChar , (const char*)charBuf , 2 ) ;
#endif
if ( numChars * 2 > 4 )
delete[] charBuf ;
}
#endif
GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode );
GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode );
GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers );
GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &point );
UInt32 message = (keyCode << 8) + charCode;
switch ( GetEventKind( event ) )
{
case kEventRawKeyRepeat :
case kEventRawKeyDown :
{
WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
wxTheApp->MacSetCurrentEvent( event , handler ) ;
if ( /* focus && */ wxTheApp->MacSendKeyDownEvent(
focus , message , modifiers , when , point.h , point.v , uniChar[0] ) )
{
result = noErr ;
}
wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
}
break ;
case kEventRawKeyUp :
if ( /* focus && */ wxTheApp->MacSendKeyUpEvent(
focus , message , modifiers , when , point.h , point.v , uniChar[0] ) )
{
result = noErr ;
}
break ;
case kEventRawKeyModifiersChanged :
{
wxKeyEvent event(wxEVT_KEY_DOWN);
event.m_shiftDown = modifiers & shiftKey;
event.m_controlDown = modifiers & controlKey;
event.m_altDown = modifiers & optionKey;
event.m_metaDown = modifiers & cmdKey;
event.m_x = point.h;
event.m_y = point.v;
#if wxUSE_UNICODE
event.m_uniChar = uniChar[0] ;
#endif
event.SetTimestamp(when);
event.SetEventObject(focus);
if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & controlKey )
{
event.m_keyCode = WXK_CONTROL ;
event.SetEventType( ( modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
focus->GetEventHandler()->ProcessEvent( event ) ;
}
if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & shiftKey )
{
event.m_keyCode = WXK_SHIFT ;
event.SetEventType( ( modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
focus->GetEventHandler()->ProcessEvent( event ) ;
}
if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & optionKey )
{
event.m_keyCode = WXK_ALT ;
event.SetEventType( ( modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
focus->GetEventHandler()->ProcessEvent( event ) ;
}
if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & cmdKey )
{
event.m_keyCode = WXK_COMMAND ;
event.SetEventType( ( modifiers & cmdKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
focus->GetEventHandler()->ProcessEvent( event ) ;
}
wxApp::s_lastModifiers = modifiers ;
}
break ;
default:
break;
}
return result ;
}
static pascal OSStatus wxWebKitCtrlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
{
OSStatus result = eventNotHandledErr ;
wxMacCarbonEvent cEvent( event ) ;
ControlRef controlRef ;
wxWebKitCtrl* thisWindow = (wxWebKitCtrl*) data ;
wxTopLevelWindowMac* tlw = NULL;
if (thisWindow)
tlw = thisWindow->MacGetTopLevelWindow();
cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
wxWindow* currentMouseWindow = thisWindow ;
if ( wxApp::s_captureWindow )
currentMouseWindow = wxApp::s_captureWindow;
switch ( GetEventClass( event ) )
{
case kEventClassKeyboard:
{
result = wxWebKitKeyEventHandler(handler, event, data);
break;
}
case kEventClassTextInput:
{
result = wxMacUnicodeTextEventHandler(handler, event, data);
break;
}
case kEventClassMouse:
{
switch ( GetEventKind( event ) )
{
case kEventMouseDragged :
case kEventMouseMoved :
case kEventMouseDown :
case kEventMouseUp :
{
wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
SetupMouseEvent( wxevent , cEvent ) ;
currentMouseWindow->ScreenToClient( &wxevent.m_x , &wxevent.m_y ) ;
wxevent.SetEventObject( currentMouseWindow ) ;
wxevent.SetId( currentMouseWindow->GetId() ) ;
if ( currentMouseWindow->GetEventHandler()->ProcessEvent(wxevent) )
{
result = noErr;
}
break; // this should enable WebKit to fire mouse dragged and mouse up events...
}
default :
break ;
}
}
default:
break;
}
result = CallNextEventHandler(handler, event);
return result ;
}
DEFINE_ONE_SHOT_HANDLER_GETTER( wxWebKitCtrlEventHandler )
// ----------------------------------------------------------------------------
// wxWebKit Events
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS( wxWebKitStateChangedEvent, wxCommandEvent )
DEFINE_EVENT_TYPE( wxEVT_WEBKIT_STATE_CHANGED )
wxWebKitStateChangedEvent::wxWebKitStateChangedEvent( wxWindow* win )
{
SetEventType( wxEVT_WEBKIT_STATE_CHANGED);
SetEventObject( win );
SetId(win->GetId());
}
IMPLEMENT_DYNAMIC_CLASS( wxWebKitBeforeLoadEvent, wxCommandEvent )
DEFINE_EVENT_TYPE( wxEVT_WEBKIT_BEFORE_LOAD )
wxWebKitBeforeLoadEvent::wxWebKitBeforeLoadEvent( wxWindow* win )
{
m_cancelled = false;
SetEventType( wxEVT_WEBKIT_BEFORE_LOAD);
SetEventObject( win );
SetId(win->GetId());
}
IMPLEMENT_DYNAMIC_CLASS( wxWebKitNewWindowEvent, wxCommandEvent )
DEFINE_EVENT_TYPE( wxEVT_WEBKIT_NEW_WINDOW )
wxWebKitNewWindowEvent::wxWebKitNewWindowEvent( wxWindow* win )
{
SetEventType( wxEVT_WEBKIT_NEW_WINDOW);
SetEventObject( win );
SetId(win->GetId());
}
//---------------------------------------------------------
// helper functions for NSString<->wxString conversion
//---------------------------------------------------------
inline wxString wxStringWithNSString(NSString *nsstring)
{
#if wxUSE_UNICODE
return wxString([nsstring UTF8String], wxConvUTF8);
#else
return wxString([nsstring lossyCString]);
#endif // wxUSE_UNICODE
}
inline NSString* wxNSStringWithWxString(const wxString &wxstring)
{
#if wxUSE_UNICODE
return [NSString stringWithUTF8String: wxstring.mb_str(wxConvUTF8)];
#else
return [NSString stringWithCString: wxstring.c_str() length:wxstring.Len()];
#endif // wxUSE_UNICODE
}
inline int wxNavTypeFromWebNavType(int type){
if (type == WebNavigationTypeLinkClicked)
return wxWEBKIT_NAV_LINK_CLICKED;
if (type == WebNavigationTypeFormSubmitted)
return wxWEBKIT_NAV_FORM_SUBMITTED;
if (type == WebNavigationTypeBackForward)
return wxWEBKIT_NAV_BACK_NEXT;
if (type == WebNavigationTypeReload)
return wxWEBKIT_NAV_RELOAD;
if (type == WebNavigationTypeFormResubmitted)
return wxWEBKIT_NAV_FORM_RESUBMITTED;
return wxWEBKIT_NAV_OTHER;
}
@interface MyFrameLoadMonitor : NSObject
{
wxWebKitCtrl* webKitWindow;
}
- initWithWxWindow: (wxWebKitCtrl*)inWindow;
@end
@interface MyPolicyDelegate : NSObject
{
wxWebKitCtrl* webKitWindow;
}
- initWithWxWindow: (wxWebKitCtrl*)inWindow;
@end
// ----------------------------------------------------------------------------
// creation/destruction
// ----------------------------------------------------------------------------
bool wxWebKitCtrl::Create(wxWindow *parent,
wxWindowID winID,
const wxString& strURL,
const wxPoint& pos,
const wxSize& size, long style,
const wxValidator& validator,
const wxString& name)
{
m_currentURL = strURL;
//m_pageTitle = _("Untitled Page");
//still needed for wxCocoa??
/*
int width, height;
wxSize sizeInstance;
if (size.x == wxDefaultCoord || size.y == wxDefaultCoord)
{
m_parent->GetClientSize(&width, &height);
sizeInstance.x = width;
sizeInstance.y = height;
}
else
{
sizeInstance.x = size.x;
sizeInstance.y = size.y;
}
*/
// now create and attach WebKit view...
#ifdef __WXCOCOA__
wxControl::Create(parent, m_windowID, pos, sizeInstance, style , validator , name);
SetSize(pos.x, pos.y, sizeInstance.x, sizeInstance.y);
wxTopLevelWindowCocoa *topWin = wxDynamicCast(this, wxTopLevelWindowCocoa);
NSWindow* nsWin = topWin->GetNSWindow();
NSRect rect;
rect.origin.x = pos.x;
rect.origin.y = pos.y;
rect.size.width = sizeInstance.x;
rect.size.height = sizeInstance.y;
m_webView = (WebView*)[[WebView alloc] initWithFrame:rect frameName:@"webkitFrame" groupName:@"webkitGroup"];
SetNSView(m_webView);
[m_cocoaNSView release];
if(m_parent) m_parent->CocoaAddChild(this);
SetInitialFrameRect(pos,sizeInstance);
#else
m_macIsUserPane = false;
wxControl::Create(parent, winID, pos, size, style , validator , name);
m_peer = new wxMacControl(this);
WebInitForCarbon();
HIWebViewCreate( m_peer->GetControlRefAddr() );
m_webView = (WebView*) HIWebViewGetWebView( m_peer->GetControlRef() );
MacPostControlCreate(pos, size);
HIViewSetVisible( m_peer->GetControlRef(), true );
[m_webView setHidden:false];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
if ( UMAGetSystemVersion() >= 0x1030 )
HIViewChangeFeatures( m_peer->GetControlRef() , kHIViewIsOpaque , 0 ) ;
#endif
InstallControlEventHandler( m_peer->GetControlRef() , GetwxWebKitCtrlEventHandlerUPP(),
GetEventTypeCount(eventList), eventList, this,
(EventHandlerRef *)&m_webKitCtrlEventHandler);
#endif
// Register event listener interfaces
MyFrameLoadMonitor* myFrameLoadMonitor = [[MyFrameLoadMonitor alloc] initWithWxWindow: this];
[m_webView setFrameLoadDelegate:myFrameLoadMonitor];
// this is used to veto page loads, etc.
MyPolicyDelegate* myPolicyDelegate = [[MyPolicyDelegate alloc] initWithWxWindow: this];
[m_webView setPolicyDelegate:myPolicyDelegate];
LoadURL(m_currentURL);
return true;
}
wxWebKitCtrl::~wxWebKitCtrl()
{
MyFrameLoadMonitor* myFrameLoadMonitor = [m_webView frameLoadDelegate];
MyPolicyDelegate* myPolicyDelegate = [m_webView policyDelegate];
[m_webView setFrameLoadDelegate: nil];
[m_webView setPolicyDelegate: nil];
if (myFrameLoadMonitor)
[myFrameLoadMonitor release];
if (myPolicyDelegate)
[myPolicyDelegate release];
}
// ----------------------------------------------------------------------------
// public methods
// ----------------------------------------------------------------------------
void wxWebKitCtrl::LoadURL(const wxString &url)
{
if( !m_webView )
return;
[[m_webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:wxNSStringWithWxString(url)]]];
m_currentURL = url;
}
bool wxWebKitCtrl::CanGoBack(){
if ( !m_webView )
return false;
return [m_webView canGoBack];
}
bool wxWebKitCtrl::CanGoForward(){
if ( !m_webView )
return false;
return [m_webView canGoForward];
}
bool wxWebKitCtrl::GoBack(){
if ( !m_webView )
return false;
bool result = [(WebView*)m_webView goBack];
return result;
}
bool wxWebKitCtrl::GoForward(){
if ( !m_webView )
return false;
bool result = [(WebView*)m_webView goForward];
return result;
}
void wxWebKitCtrl::Reload(){
if ( !m_webView )
return;
[[m_webView mainFrame] reload];
}
void wxWebKitCtrl::Stop(){
if ( !m_webView )
return;
[[m_webView mainFrame] stopLoading];
}
bool wxWebKitCtrl::CanGetPageSource(){
if ( !m_webView )
return false;
WebDataSource* dataSource = [[m_webView mainFrame] dataSource];
return ( [[dataSource representation] canProvideDocumentSource] );
}
wxString wxWebKitCtrl::GetPageSource(){
if (CanGetPageSource()){
WebDataSource* dataSource = [[m_webView mainFrame] dataSource];
return wxStringWithNSString( [[dataSource representation] documentSource] );
}
return wxEmptyString;
}
wxString wxWebKitCtrl::GetSelection(){
if ( !m_webView )
return wxEmptyString;
NSString* selectedText = [[m_webView selectedDOMRange] toString];
return wxStringWithNSString( selectedText );
}
bool wxWebKitCtrl::CanIncreaseTextSize(){
if ( !m_webView )
return false;
if ([m_webView canMakeTextLarger])
return true;
else
return false;
}
void wxWebKitCtrl::IncreaseTextSize(){
if ( !m_webView )
return;
if (CanIncreaseTextSize())
[m_webView makeTextLarger:(WebView*)m_webView];
}
bool wxWebKitCtrl::CanDecreaseTextSize(){
if ( !m_webView )
return false;
if ([m_webView canMakeTextSmaller])
return true;
else
return false;
}
void wxWebKitCtrl::DecreaseTextSize(){
if ( !m_webView )
return;
if (CanDecreaseTextSize())
[m_webView makeTextSmaller:(WebView*)m_webView];
}
void wxWebKitCtrl::SetPageSource(const wxString& source, const wxString& baseUrl){
if ( !m_webView )
return;
[[m_webView mainFrame] loadHTMLString:(NSString*)wxNSStringWithWxString( source ) baseURL:[NSURL URLWithString:wxNSStringWithWxString( baseUrl )]];
}
void wxWebKitCtrl::Print(bool showPrompt){
if ( !m_webView )
return;
id view = [[[m_webView mainFrame] frameView] documentView];
NSPrintOperation *op = [NSPrintOperation printOperationWithView:view printInfo: [NSPrintInfo sharedPrintInfo]];
if (showPrompt){
[op setShowsPrintPanel: showPrompt];
// in my tests, the progress bar always freezes and it stops the whole print operation.
// do not turn this to true unless there is a workaround for the bug.
[op setShowsProgressPanel: false];
}
// Print it.
[op runOperation];
}
void wxWebKitCtrl::MakeEditable(bool enable){
if ( !m_webView )
return;
[m_webView setEditable:enable ];
}
bool wxWebKitCtrl::IsEditable(){
if ( !m_webView )
return false;
return [m_webView isEditable];
}
int wxWebKitCtrl::GetScrollPos(){
id result = [[m_webView windowScriptObject] evaluateWebScript:@"document.body.scrollTop"];
return [result intValue];
}
void wxWebKitCtrl::SetScrollPos(int pos){
if ( !m_webView )
return;
wxString javascript;
javascript.Printf(wxT("document.body.scrollTop = %d;"), pos);
[[m_webView windowScriptObject] evaluateWebScript:(NSString*)wxNSStringWithWxString( javascript )];
}
wxString wxWebKitCtrl::RunScript(const wxString& javascript){
if ( !m_webView )
return wxEmptyString;
id result = [[m_webView windowScriptObject] evaluateWebScript:(NSString*)wxNSStringWithWxString( javascript )];
NSString* resultAsString;
wxString resultAsWxString = wxEmptyString;
NSString* className = NSStringFromClass([result class]);
if ([className isEqualToString:@"NSCFNumber"])
resultAsString = [NSString stringWithFormat:@"%@", result];
else if ([className isEqualToString:@"NSCFString"])
resultAsString = result;
else if ([className isEqualToString:@"NSCFBoolean"]){
if ([result boolValue])
resultAsString = @"true";
else
resultAsString = @"false";
}
else if ([className isEqualToString:@"WebScriptObject"])
resultAsString = [result stringRepresentation];
else
fprintf(stderr, "wxWebKitCtrl::RunScript - Unexpected return type: %s!\n", [className UTF8String]);
resultAsWxString = wxStringWithNSString( resultAsString );
return resultAsWxString;
}
void wxWebKitCtrl::OnSize(wxSizeEvent &event){
// This is a nasty hack because WebKit seems to lose its position when it is embedded
// in a control that is not itself the content view for a TLW.
// I put it in OnSize because these calcs are not perfect, and in fact are basically
// guesses based on reverse engineering, so it's best to give people the option of
// overriding OnSize with their own calcs if need be.
// I also left some test debugging print statements as a convenience if a(nother)
// problem crops up.
wxWindow* tlw = MacGetTopLevelWindow();
NSRect frame = [m_webView frame];
NSRect bounds = [m_webView bounds];
#if DEBUG_WEBKIT_SIZING
fprintf(stderr,"Carbon window x=%d, y=%d, width=%d, height=%d\n", GetPosition().x, GetPosition().y, GetSize().x, GetSize().y);
fprintf(stderr, "Cocoa window frame x=%G, y=%G, width=%G, height=%G\n", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
fprintf(stderr, "Cocoa window bounds x=%G, y=%G, width=%G, height=%G\n", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
#endif
// This must be the case that Apple tested with, because well, in this one case
// we don't need to do anything! It just works. ;)
if (GetParent() == tlw){
return;
}
// since we no longer use parent coordinates, we always want 0,0.
int x = 0;
int y = 0;
HIRect rect;
rect.origin.x = x;
rect.origin.y = y;
#if DEBUG_WEBKIT_SIZING
printf("Before conversion, origin is: x = %d, y = %d\n", x, y);
#endif
// NB: In most cases, when calling HIViewConvertRect, what people want is to use GetRootControl(),
// and this tripped me up at first. But in fact, what we want is the root view, because we need to
// make the y origin relative to the very top of the window, not its contents, since we later flip
// the y coordinate for Cocoa.
HIViewConvertRect (&rect, m_peer->GetControlRef(),
HIViewGetRoot( (WindowRef) MacGetTopLevelWindowRef() ) );
x = (int)rect.origin.x;
y = (int)rect.origin.y;
#if DEBUG_WEBKIT_SIZING
printf("Moving Cocoa frame origin to: x = %d, y = %d\n", x, y);
#endif
if (tlw){
//flip the y coordinate to convert to Cocoa coordinates
y = tlw->GetSize().y - ((GetSize().y) + y);
}
#if DEBUG_WEBKIT_SIZING
printf("y = %d after flipping value\n", y);
#endif
frame.origin.x = x;
frame.origin.y = y;
[m_webView setFrame:frame];
if (IsShown())
[(WebView*)m_webView display];
event.Skip();
}
void wxWebKitCtrl::MacVisibilityChanged(){
bool isHidden = !IsControlVisible( m_peer->GetControlRef());
if (!isHidden)
[(WebView*)m_webView display];
[m_webView setHidden:isHidden];
}
//------------------------------------------------------------
// Listener interfaces
//------------------------------------------------------------
// NB: I'm still tracking this down, but it appears the Cocoa window
// still has these events fired on it while the Carbon control is being
// destroyed. Therefore, we must be careful to check both the existence
// of the Carbon control and the event handler before firing events.
@implementation MyFrameLoadMonitor
- initWithWxWindow: (wxWebKitCtrl*)inWindow
{
[super init];
webKitWindow = inWindow; // non retained
return self;
}
- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
{
if (webKitWindow && frame == [sender mainFrame]){
NSString *url = [[[[frame provisionalDataSource] request] URL] absoluteString];
wxWebKitStateChangedEvent thisEvent(webKitWindow);
thisEvent.SetState(wxWEBKIT_STATE_NEGOTIATING);
thisEvent.SetURL( wxStringWithNSString( url ) );
if (webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent( thisEvent );
}
}
- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
{
if (webKitWindow && frame == [sender mainFrame]){
NSString *url = [[[[frame dataSource] request] URL] absoluteString];
wxWebKitStateChangedEvent thisEvent(webKitWindow);
thisEvent.SetState(wxWEBKIT_STATE_TRANSFERRING);
thisEvent.SetURL( wxStringWithNSString( url ) );
if (webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent( thisEvent );
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
if (webKitWindow && frame == [sender mainFrame]){
NSString *url = [[[[frame dataSource] request] URL] absoluteString];
wxWebKitStateChangedEvent thisEvent(webKitWindow);
thisEvent.SetState(wxWEBKIT_STATE_STOP);
thisEvent.SetURL( wxStringWithNSString( url ) );
if (webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent( thisEvent );
}
}
- (void)webView:(WebView *)sender didFailLoadWithError:(NSError*) error forFrame:(WebFrame *)frame
{
if (webKitWindow && frame == [sender mainFrame]){
NSString *url = [[[[frame dataSource] request] URL] absoluteString];
wxWebKitStateChangedEvent thisEvent(webKitWindow);
thisEvent.SetState(wxWEBKIT_STATE_FAILED);
thisEvent.SetURL( wxStringWithNSString( url ) );
if (webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent( thisEvent );
}
}
- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError*) error forFrame:(WebFrame *)frame
{
if (webKitWindow && frame == [sender mainFrame]){
NSString *url = [[[[frame provisionalDataSource] request] URL] absoluteString];
wxWebKitStateChangedEvent thisEvent(webKitWindow);
thisEvent.SetState(wxWEBKIT_STATE_FAILED);
thisEvent.SetURL( wxStringWithNSString( url ) );
if (webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent( thisEvent );
}
}
- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
{
if (webKitWindow && frame == [sender mainFrame]){
webKitWindow->SetPageTitle(wxStringWithNSString( title ));
}
}
@end
@implementation MyPolicyDelegate
- initWithWxWindow: (wxWebKitCtrl*)inWindow
{
[super init];
webKitWindow = inWindow; // non retained
return self;
}
- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
{
wxWebKitBeforeLoadEvent thisEvent(webKitWindow);
// Get the navigation type.
NSNumber *n = [actionInformation objectForKey:WebActionNavigationTypeKey];
int actionType = [n intValue];
thisEvent.SetNavigationType( wxNavTypeFromWebNavType(actionType) );
NSString *url = [[request URL] absoluteString];
thisEvent.SetURL( wxStringWithNSString( url ) );
if (webKitWindow && webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);
if (thisEvent.IsCancelled())
[listener ignore];
else
[listener use];
}
- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener
{
wxWebKitNewWindowEvent thisEvent(webKitWindow);
NSString *url = [[request URL] absoluteString];
thisEvent.SetURL( wxStringWithNSString( url ) );
thisEvent.SetTargetName( wxStringWithNSString( frameName ) );
if (webKitWindow && webKitWindow->GetEventHandler())
webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);
[listener use];
}
@end
#endif //wxUSE_WEBKIT

View file

@ -0,0 +1,223 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/htmlfilt.cpp
// Purpose: wxHtmlFilter - input filter for translating into HTML format
// Author: Vaclav Slavik
// RCS-ID: $Id: htmlfilt.cpp 38788 2006-04-18 08:11:26Z ABX $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#endif
#include "wx/strconv.h"
#include "wx/html/htmlfilt.h"
#include "wx/html/htmlwin.h"
// utility function: read a wxString from a wxInputStream
static void ReadString(wxString& str, wxInputStream* s, wxMBConv& conv)
{
size_t streamSize = s->GetSize();
if (streamSize == ~(size_t)0)
{
const size_t bufSize = 4095;
char buffer[bufSize+1];
size_t lastRead;
do
{
s->Read(buffer, bufSize);
lastRead = s->LastRead();
buffer[lastRead] = 0;
str.Append(wxString(buffer, conv));
}
while (lastRead == bufSize);
}
else
{
char* src = new char[streamSize+1];
s->Read(src, streamSize);
src[streamSize] = 0;
str = wxString(src, conv);
delete[] src;
}
}
/*
There is code for several default filters:
*/
IMPLEMENT_ABSTRACT_CLASS(wxHtmlFilter, wxObject)
//--------------------------------------------------------------------------------
// wxHtmlFilterPlainText
// filter for text/plain or uknown
//--------------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterPlainText, wxHtmlFilter)
bool wxHtmlFilterPlainText::CanRead(const wxFSFile& WXUNUSED(file)) const
{
return true;
}
wxString wxHtmlFilterPlainText::ReadFile(const wxFSFile& file) const
{
wxInputStream *s = file.GetStream();
wxString doc, doc2;
if (s == NULL) return wxEmptyString;
ReadString(doc, s, wxConvISO8859_1);
doc.Replace(wxT("&"), wxT("&amp;"), true);
doc.Replace(wxT("<"), wxT("&lt;"), true);
doc.Replace(wxT(">"), wxT("&gt;"), true);
doc2 = wxT("<HTML><BODY><PRE>\n") + doc + wxT("\n</PRE></BODY></HTML>");
return doc2;
}
//--------------------------------------------------------------------------------
// wxHtmlFilterImage
// filter for image/*
//--------------------------------------------------------------------------------
class wxHtmlFilterImage : public wxHtmlFilter
{
DECLARE_DYNAMIC_CLASS(wxHtmlFilterImage)
public:
virtual bool CanRead(const wxFSFile& file) const;
virtual wxString ReadFile(const wxFSFile& file) const;
};
IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterImage, wxHtmlFilter)
bool wxHtmlFilterImage::CanRead(const wxFSFile& file) const
{
return (file.GetMimeType().Left(6) == wxT("image/"));
}
wxString wxHtmlFilterImage::ReadFile(const wxFSFile& file) const
{
wxString res = wxT("<HTML><BODY><IMG SRC=\"") + file.GetLocation() + wxT("\"></BODY></HTML>");
return res;
}
//--------------------------------------------------------------------------------
// wxHtmlFilterHTML
// filter for text/html
//--------------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterHTML, wxHtmlFilter)
bool wxHtmlFilterHTML::CanRead(const wxFSFile& file) const
{
// return (file.GetMimeType() == "text/html");
// This is true in most case but some page can return:
// "text/html; char-encoding=...."
// So we use Find instead
return (file.GetMimeType().Find(wxT("text/html")) == 0);
}
wxString wxHtmlFilterHTML::ReadFile(const wxFSFile& file) const
{
wxInputStream *s = file.GetStream();
wxString doc;
if (s == NULL)
{
wxLogError(_("Cannot open HTML document: %s"), file.GetLocation().c_str());
return wxEmptyString;
}
// NB: We convert input file to wchar_t here in Unicode mode, based on
// either Content-Type header or <meta> tags. In ANSI mode, we don't
// do it as it is done by wxHtmlParser (for this reason, we add <meta>
// tag if we used Content-Type header).
#if wxUSE_UNICODE
int charsetPos;
if ((charsetPos = file.GetMimeType().Find(_T("; charset="))) != wxNOT_FOUND)
{
wxString charset = file.GetMimeType().Mid(charsetPos + 10);
wxCSConv conv(charset);
ReadString(doc, s, conv);
}
else
{
wxString tmpdoc;
ReadString(tmpdoc, s, wxConvISO8859_1);
wxString charset = wxHtmlParser::ExtractCharsetInformation(tmpdoc);
if (charset.empty())
doc = tmpdoc;
else
{
wxCSConv conv(charset);
doc = wxString(tmpdoc.mb_str(wxConvISO8859_1), conv);
}
}
#else // !wxUSE_UNICODE
ReadString(doc, s, wxConvLibc);
// add meta tag if we obtained this through http:
if (!file.GetMimeType().empty())
{
wxString hdr;
wxString mime = file.GetMimeType();
hdr.Printf(_T("<meta http-equiv=\"Content-Type\" content=\"%s\">"), mime.c_str());
return hdr+doc;
}
#endif
return doc;
}
///// Module:
class wxHtmlFilterModule : public wxModule
{
DECLARE_DYNAMIC_CLASS(wxHtmlFilterModule)
public:
virtual bool OnInit()
{
wxHtmlWindow::AddFilter(new wxHtmlFilterHTML);
wxHtmlWindow::AddFilter(new wxHtmlFilterImage);
return true;
}
virtual void OnExit() {}
};
IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterModule, wxModule)
#endif

View file

@ -0,0 +1,961 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/htmlpars.cpp
// Purpose: wxHtmlParser class (generic parser)
// Author: Vaclav Slavik
// RCS-ID: $Id: htmlpars.cpp 66413 2010-12-20 17:40:05Z JS $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/dynarray.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/app.h"
#endif
#include "wx/tokenzr.h"
#include "wx/wfstream.h"
#include "wx/url.h"
#include "wx/fontmap.h"
#include "wx/html/htmldefs.h"
#include "wx/html/htmlpars.h"
#include "wx/arrimpl.cpp"
#ifdef __WXWINCE__
#include "wx/msw/wince/missing.h" // for bsearch()
#endif
// DLL options compatibility check:
WX_CHECK_BUILD_OPTIONS("wxHTML")
const wxChar *wxTRACE_HTML_DEBUG = _T("htmldebug");
//-----------------------------------------------------------------------------
// wxHtmlParser helpers
//-----------------------------------------------------------------------------
class wxHtmlTextPiece
{
public:
wxHtmlTextPiece(int pos, int lng) : m_pos(pos), m_lng(lng) {}
int m_pos, m_lng;
};
WX_DECLARE_OBJARRAY(wxHtmlTextPiece, wxHtmlTextPieces);
WX_DEFINE_OBJARRAY(wxHtmlTextPieces)
class wxHtmlParserState
{
public:
wxHtmlTag *m_curTag;
wxHtmlTag *m_tags;
wxHtmlTextPieces *m_textPieces;
int m_curTextPiece;
wxString m_source;
wxHtmlParserState *m_nextState;
};
//-----------------------------------------------------------------------------
// wxHtmlParser
//-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxHtmlParser,wxObject)
wxHtmlParser::wxHtmlParser()
: wxObject(), m_HandlersHash(wxKEY_STRING),
m_FS(NULL), m_HandlersStack(NULL)
{
m_entitiesParser = new wxHtmlEntitiesParser;
m_Tags = NULL;
m_CurTag = NULL;
m_TextPieces = NULL;
m_CurTextPiece = 0;
m_SavedStates = NULL;
}
wxHtmlParser::~wxHtmlParser()
{
while (RestoreState()) {}
DestroyDOMTree();
if (m_HandlersStack)
{
wxList& tmp = *m_HandlersStack;
wxList::iterator it, en;
for( it = tmp.begin(), en = tmp.end(); it != en; ++it )
delete (wxHashTable*)*it;
tmp.clear();
}
delete m_HandlersStack;
m_HandlersHash.Clear();
WX_CLEAR_LIST(wxList, m_HandlersList);
delete m_entitiesParser;
}
wxObject* wxHtmlParser::Parse(const wxString& source)
{
InitParser(source);
DoParsing();
wxObject *result = GetProduct();
DoneParser();
return result;
}
void wxHtmlParser::InitParser(const wxString& source)
{
SetSource(source);
m_stopParsing = false;
}
void wxHtmlParser::DoneParser()
{
DestroyDOMTree();
}
void wxHtmlParser::SetSource(const wxString& src)
{
DestroyDOMTree();
m_Source = src;
CreateDOMTree();
m_CurTag = NULL;
m_CurTextPiece = 0;
}
void wxHtmlParser::CreateDOMTree()
{
wxHtmlTagsCache cache(m_Source);
m_TextPieces = new wxHtmlTextPieces;
CreateDOMSubTree(NULL, 0, m_Source.length(), &cache);
m_CurTextPiece = 0;
}
extern bool wxIsCDATAElement(const wxChar *tag);
void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur,
int begin_pos, int end_pos,
wxHtmlTagsCache *cache)
{
if (end_pos <= begin_pos) return;
wxChar c;
int i = begin_pos;
int textBeginning = begin_pos;
// If the tag contains CDATA text, we include the text between beginning
// and ending tag verbosely. Setting i=end_pos will skip to the very
// end of this function where text piece is added, bypassing any child
// tags parsing (CDATA element can't have child elements by definition):
if (cur != NULL && wxIsCDATAElement(cur->GetName().c_str()))
{
i = end_pos;
}
while (i < end_pos)
{
c = m_Source.GetChar(i);
if (c == wxT('<'))
{
// add text to m_TextPieces:
if (i - textBeginning > 0)
m_TextPieces->Add(
wxHtmlTextPiece(textBeginning, i - textBeginning));
// if it is a comment, skip it:
if (i < end_pos-6 && m_Source.GetChar(i+1) == wxT('!') &&
m_Source.GetChar(i+2) == wxT('-') &&
m_Source.GetChar(i+3) == wxT('-'))
{
// Comments begin with "<!--" and end with "--[ \t\r\n]*>"
// according to HTML 4.0
int dashes = 0;
i += 4;
while (i < end_pos)
{
c = m_Source.GetChar(i++);
if ((c == wxT(' ') || c == wxT('\n') ||
c == wxT('\r') || c == wxT('\t')) && dashes >= 2) {}
else if (c == wxT('>') && dashes >= 2)
{
textBeginning = i;
break;
}
else if (c == wxT('-'))
dashes++;
else
dashes = 0;
}
}
// add another tag to the tree:
else if (i < end_pos-1 && m_Source.GetChar(i+1) != wxT('/'))
{
wxHtmlTag *chd;
if (cur)
chd = new wxHtmlTag(cur, m_Source,
i, end_pos, cache, m_entitiesParser);
else
{
chd = new wxHtmlTag(NULL, m_Source,
i, end_pos, cache, m_entitiesParser);
if (!m_Tags)
{
// if this is the first tag to be created make the root
// m_Tags point to it:
m_Tags = chd;
}
else
{
// if there is already a root tag add this tag as
// the last sibling:
chd->m_Prev = m_Tags->GetLastSibling();
chd->m_Prev->m_Next = chd;
}
}
if (chd->HasEnding())
{
CreateDOMSubTree(chd,
chd->GetBeginPos(), chd->GetEndPos1(),
cache);
i = chd->GetEndPos2();
}
else
i = chd->GetBeginPos();
textBeginning = i;
}
// ... or skip ending tag:
else
{
while (i < end_pos && m_Source.GetChar(i) != wxT('>')) i++;
textBeginning = i+1;
}
}
else i++;
}
// add remaining text to m_TextPieces:
if (end_pos - textBeginning > 0)
m_TextPieces->Add(
wxHtmlTextPiece(textBeginning, end_pos - textBeginning));
}
void wxHtmlParser::DestroyDOMTree()
{
wxHtmlTag *t1, *t2;
t1 = m_Tags;
while (t1)
{
t2 = t1->GetNextSibling();
delete t1;
t1 = t2;
}
m_Tags = m_CurTag = NULL;
delete m_TextPieces;
m_TextPieces = NULL;
}
void wxHtmlParser::DoParsing()
{
m_CurTag = m_Tags;
m_CurTextPiece = 0;
DoParsing(0, m_Source.length());
}
void wxHtmlParser::DoParsing(int begin_pos, int end_pos)
{
if (end_pos <= begin_pos) return;
wxHtmlTextPieces& pieces = *m_TextPieces;
size_t piecesCnt = pieces.GetCount();
while (begin_pos < end_pos)
{
while (m_CurTag && m_CurTag->GetBeginPos() < begin_pos)
m_CurTag = m_CurTag->GetNextTag();
while (m_CurTextPiece < piecesCnt &&
pieces[m_CurTextPiece].m_pos < begin_pos)
m_CurTextPiece++;
if (m_CurTextPiece < piecesCnt &&
(!m_CurTag ||
pieces[m_CurTextPiece].m_pos < m_CurTag->GetBeginPos()))
{
// Add text:
AddText(GetEntitiesParser()->Parse(
m_Source.Mid(pieces[m_CurTextPiece].m_pos,
pieces[m_CurTextPiece].m_lng)));
begin_pos = pieces[m_CurTextPiece].m_pos +
pieces[m_CurTextPiece].m_lng;
m_CurTextPiece++;
}
else if (m_CurTag)
{
if (m_CurTag->HasEnding())
begin_pos = m_CurTag->GetEndPos2();
else
begin_pos = m_CurTag->GetBeginPos();
wxHtmlTag *t = m_CurTag;
m_CurTag = m_CurTag->GetNextTag();
AddTag(*t);
if (m_stopParsing)
return;
}
else break;
}
}
void wxHtmlParser::AddTag(const wxHtmlTag& tag)
{
wxHtmlTagHandler *h;
bool inner = false;
h = (wxHtmlTagHandler*) m_HandlersHash.Get(tag.GetName());
if (h)
{
inner = h->HandleTag(tag);
if (m_stopParsing)
return;
}
if (!inner)
{
if (tag.HasEnding())
DoParsing(tag.GetBeginPos(), tag.GetEndPos1());
}
}
void wxHtmlParser::AddTagHandler(wxHtmlTagHandler *handler)
{
wxString s(handler->GetSupportedTags());
wxStringTokenizer tokenizer(s, wxT(", "));
while (tokenizer.HasMoreTokens())
m_HandlersHash.Put(tokenizer.GetNextToken(), handler);
if (m_HandlersList.IndexOf(handler) == wxNOT_FOUND)
m_HandlersList.Append(handler);
handler->SetParser(this);
}
void wxHtmlParser::PushTagHandler(wxHtmlTagHandler *handler, const wxString& tags)
{
wxStringTokenizer tokenizer(tags, wxT(", "));
wxString key;
if (m_HandlersStack == NULL)
{
m_HandlersStack = new wxList;
}
m_HandlersStack->Insert((wxObject*)new wxHashTable(m_HandlersHash));
while (tokenizer.HasMoreTokens())
{
key = tokenizer.GetNextToken();
m_HandlersHash.Delete(key);
m_HandlersHash.Put(key, handler);
}
}
void wxHtmlParser::PopTagHandler()
{
wxList::compatibility_iterator first;
if ( !m_HandlersStack ||
#if wxUSE_STL
!(first = m_HandlersStack->GetFirst())
#else // !wxUSE_STL
((first = m_HandlersStack->GetFirst()) == NULL)
#endif // wxUSE_STL/!wxUSE_STL
)
{
wxLogWarning(_("Warning: attempt to remove HTML tag handler from empty stack."));
return;
}
m_HandlersHash = *((wxHashTable*) first->GetData());
delete (wxHashTable*) first->GetData();
m_HandlersStack->Erase(first);
}
void wxHtmlParser::SetSourceAndSaveState(const wxString& src)
{
wxHtmlParserState *s = new wxHtmlParserState;
s->m_curTag = m_CurTag;
s->m_tags = m_Tags;
s->m_textPieces = m_TextPieces;
s->m_curTextPiece = m_CurTextPiece;
s->m_source = m_Source;
s->m_nextState = m_SavedStates;
m_SavedStates = s;
m_CurTag = NULL;
m_Tags = NULL;
m_TextPieces = NULL;
m_CurTextPiece = 0;
m_Source = wxEmptyString;
SetSource(src);
}
bool wxHtmlParser::RestoreState()
{
if (!m_SavedStates) return false;
DestroyDOMTree();
wxHtmlParserState *s = m_SavedStates;
m_SavedStates = s->m_nextState;
m_CurTag = s->m_curTag;
m_Tags = s->m_tags;
m_TextPieces = s->m_textPieces;
m_CurTextPiece = s->m_curTextPiece;
m_Source = s->m_source;
delete s;
return true;
}
wxString wxHtmlParser::GetInnerSource(const wxHtmlTag& tag)
{
return GetSource()->Mid(tag.GetBeginPos(),
tag.GetEndPos1() - tag.GetBeginPos());
}
//-----------------------------------------------------------------------------
// wxHtmlTagHandler
//-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxHtmlTagHandler,wxObject)
void wxHtmlTagHandler::ParseInnerSource(const wxString& source)
{
// It is safe to temporarily change the source being parsed,
// provided we restore the state back after parsing
m_Parser->SetSourceAndSaveState(source);
m_Parser->DoParsing();
m_Parser->RestoreState();
}
//-----------------------------------------------------------------------------
// wxHtmlEntitiesParser
//-----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxHtmlEntitiesParser,wxObject)
wxHtmlEntitiesParser::wxHtmlEntitiesParser()
#if wxUSE_WCHAR_T && !wxUSE_UNICODE
: m_conv(NULL), m_encoding(wxFONTENCODING_SYSTEM)
#endif
{
}
wxHtmlEntitiesParser::~wxHtmlEntitiesParser()
{
#if wxUSE_WCHAR_T && !wxUSE_UNICODE
delete m_conv;
#endif
}
void wxHtmlEntitiesParser::SetEncoding(wxFontEncoding encoding)
{
#if wxUSE_WCHAR_T && !wxUSE_UNICODE
if (encoding == m_encoding)
return;
delete m_conv;
m_encoding = encoding;
if (m_encoding == wxFONTENCODING_SYSTEM)
m_conv = NULL;
else
m_conv = new wxCSConv(wxFontMapper::GetEncodingName(m_encoding));
#else
(void) encoding;
#endif
}
wxString wxHtmlEntitiesParser::Parse(const wxString& input)
{
const wxChar *c, *last;
const wxChar *in_str = input.c_str();
wxString output;
for (c = in_str, last = in_str; *c != wxT('\0'); c++)
{
if (*c == wxT('&'))
{
if ( output.empty() )
output.reserve(input.length());
if (c - last > 0)
output.append(last, c - last);
if ( *++c == wxT('\0') )
break;
wxString entity;
const wxChar *ent_s = c;
wxChar entity_char;
for (; (*c >= wxT('a') && *c <= wxT('z')) ||
(*c >= wxT('A') && *c <= wxT('Z')) ||
(*c >= wxT('0') && *c <= wxT('9')) ||
*c == wxT('_') || *c == wxT('#'); c++) {}
entity.append(ent_s, c - ent_s);
if (*c != wxT(';')) c--;
last = c+1;
entity_char = GetEntityChar(entity);
if (entity_char)
output << entity_char;
else
{
output.append(ent_s-1, c-ent_s+2);
wxLogTrace(wxTRACE_HTML_DEBUG,
wxT("Unrecognized HTML entity: '%s'"),
entity.c_str());
}
}
}
if (last == in_str) // common case: no entity
return input;
if (*last != wxT('\0'))
output.append(last);
return output;
}
struct wxHtmlEntityInfo
{
const wxChar *name;
unsigned code;
};
extern "C" int LINKAGEMODE wxHtmlEntityCompare(const void *key, const void *item)
{
return wxStrcmp((wxChar*)key, ((wxHtmlEntityInfo*)item)->name);
}
#if !wxUSE_UNICODE
wxChar wxHtmlEntitiesParser::GetCharForCode(unsigned code)
{
#if wxUSE_WCHAR_T
char buf[2];
wchar_t wbuf[2];
wbuf[0] = (wchar_t)code;
wbuf[1] = 0;
wxMBConv *conv = m_conv ? m_conv : &wxConvLocal;
if (conv->WC2MB(buf, wbuf, 2) == (size_t)-1)
return '?';
return buf[0];
#else
return (code < 256) ? (wxChar)code : '?';
#endif
}
#endif
wxChar wxHtmlEntitiesParser::GetEntityChar(const wxString& entity)
{
unsigned code = 0;
if (entity.empty())
return 0; // invalid entity reference
if (entity[0] == wxT('#'))
{
const wxChar *ent_s = entity.c_str();
const wxChar *format;
if (ent_s[1] == wxT('x') || ent_s[1] == wxT('X'))
{
format = wxT("%x");
ent_s++;
}
else
format = wxT("%u");
ent_s++;
if (wxSscanf(ent_s, format, &code) != 1)
code = 0;
}
else
{
static wxHtmlEntityInfo substitutions[] = {
{ wxT("AElig"),198 },
{ wxT("Aacute"),193 },
{ wxT("Acirc"),194 },
{ wxT("Agrave"),192 },
{ wxT("Alpha"),913 },
{ wxT("Aring"),197 },
{ wxT("Atilde"),195 },
{ wxT("Auml"),196 },
{ wxT("Beta"),914 },
{ wxT("Ccedil"),199 },
{ wxT("Chi"),935 },
{ wxT("Dagger"),8225 },
{ wxT("Delta"),916 },
{ wxT("ETH"),208 },
{ wxT("Eacute"),201 },
{ wxT("Ecirc"),202 },
{ wxT("Egrave"),200 },
{ wxT("Epsilon"),917 },
{ wxT("Eta"),919 },
{ wxT("Euml"),203 },
{ wxT("Gamma"),915 },
{ wxT("Iacute"),205 },
{ wxT("Icirc"),206 },
{ wxT("Igrave"),204 },
{ wxT("Iota"),921 },
{ wxT("Iuml"),207 },
{ wxT("Kappa"),922 },
{ wxT("Lambda"),923 },
{ wxT("Mu"),924 },
{ wxT("Ntilde"),209 },
{ wxT("Nu"),925 },
{ wxT("OElig"),338 },
{ wxT("Oacute"),211 },
{ wxT("Ocirc"),212 },
{ wxT("Ograve"),210 },
{ wxT("Omega"),937 },
{ wxT("Omicron"),927 },
{ wxT("Oslash"),216 },
{ wxT("Otilde"),213 },
{ wxT("Ouml"),214 },
{ wxT("Phi"),934 },
{ wxT("Pi"),928 },
{ wxT("Prime"),8243 },
{ wxT("Psi"),936 },
{ wxT("Rho"),929 },
{ wxT("Scaron"),352 },
{ wxT("Sigma"),931 },
{ wxT("THORN"),222 },
{ wxT("Tau"),932 },
{ wxT("Theta"),920 },
{ wxT("Uacute"),218 },
{ wxT("Ucirc"),219 },
{ wxT("Ugrave"),217 },
{ wxT("Upsilon"),933 },
{ wxT("Uuml"),220 },
{ wxT("Xi"),926 },
{ wxT("Yacute"),221 },
{ wxT("Yuml"),376 },
{ wxT("Zeta"),918 },
{ wxT("aacute"),225 },
{ wxT("acirc"),226 },
{ wxT("acute"),180 },
{ wxT("aelig"),230 },
{ wxT("agrave"),224 },
{ wxT("alefsym"),8501 },
{ wxT("alpha"),945 },
{ wxT("amp"),38 },
{ wxT("and"),8743 },
{ wxT("ang"),8736 },
{ wxT("apos"),39 },
{ wxT("aring"),229 },
{ wxT("asymp"),8776 },
{ wxT("atilde"),227 },
{ wxT("auml"),228 },
{ wxT("bdquo"),8222 },
{ wxT("beta"),946 },
{ wxT("brvbar"),166 },
{ wxT("bull"),8226 },
{ wxT("cap"),8745 },
{ wxT("ccedil"),231 },
{ wxT("cedil"),184 },
{ wxT("cent"),162 },
{ wxT("chi"),967 },
{ wxT("circ"),710 },
{ wxT("clubs"),9827 },
{ wxT("cong"),8773 },
{ wxT("copy"),169 },
{ wxT("crarr"),8629 },
{ wxT("cup"),8746 },
{ wxT("curren"),164 },
{ wxT("dArr"),8659 },
{ wxT("dagger"),8224 },
{ wxT("darr"),8595 },
{ wxT("deg"),176 },
{ wxT("delta"),948 },
{ wxT("diams"),9830 },
{ wxT("divide"),247 },
{ wxT("eacute"),233 },
{ wxT("ecirc"),234 },
{ wxT("egrave"),232 },
{ wxT("empty"),8709 },
{ wxT("emsp"),8195 },
{ wxT("ensp"),8194 },
{ wxT("epsilon"),949 },
{ wxT("equiv"),8801 },
{ wxT("eta"),951 },
{ wxT("eth"),240 },
{ wxT("euml"),235 },
{ wxT("euro"),8364 },
{ wxT("exist"),8707 },
{ wxT("fnof"),402 },
{ wxT("forall"),8704 },
{ wxT("frac12"),189 },
{ wxT("frac14"),188 },
{ wxT("frac34"),190 },
{ wxT("frasl"),8260 },
{ wxT("gamma"),947 },
{ wxT("ge"),8805 },
{ wxT("gt"),62 },
{ wxT("hArr"),8660 },
{ wxT("harr"),8596 },
{ wxT("hearts"),9829 },
{ wxT("hellip"),8230 },
{ wxT("iacute"),237 },
{ wxT("icirc"),238 },
{ wxT("iexcl"),161 },
{ wxT("igrave"),236 },
{ wxT("image"),8465 },
{ wxT("infin"),8734 },
{ wxT("int"),8747 },
{ wxT("iota"),953 },
{ wxT("iquest"),191 },
{ wxT("isin"),8712 },
{ wxT("iuml"),239 },
{ wxT("kappa"),954 },
{ wxT("lArr"),8656 },
{ wxT("lambda"),955 },
{ wxT("lang"),9001 },
{ wxT("laquo"),171 },
{ wxT("larr"),8592 },
{ wxT("lceil"),8968 },
{ wxT("ldquo"),8220 },
{ wxT("le"),8804 },
{ wxT("lfloor"),8970 },
{ wxT("lowast"),8727 },
{ wxT("loz"),9674 },
{ wxT("lrm"),8206 },
{ wxT("lsaquo"),8249 },
{ wxT("lsquo"),8216 },
{ wxT("lt"),60 },
{ wxT("macr"),175 },
{ wxT("mdash"),8212 },
{ wxT("micro"),181 },
{ wxT("middot"),183 },
{ wxT("minus"),8722 },
{ wxT("mu"),956 },
{ wxT("nabla"),8711 },
{ wxT("nbsp"),160 },
{ wxT("ndash"),8211 },
{ wxT("ne"),8800 },
{ wxT("ni"),8715 },
{ wxT("not"),172 },
{ wxT("notin"),8713 },
{ wxT("nsub"),8836 },
{ wxT("ntilde"),241 },
{ wxT("nu"),957 },
{ wxT("oacute"),243 },
{ wxT("ocirc"),244 },
{ wxT("oelig"),339 },
{ wxT("ograve"),242 },
{ wxT("oline"),8254 },
{ wxT("omega"),969 },
{ wxT("omicron"),959 },
{ wxT("oplus"),8853 },
{ wxT("or"),8744 },
{ wxT("ordf"),170 },
{ wxT("ordm"),186 },
{ wxT("oslash"),248 },
{ wxT("otilde"),245 },
{ wxT("otimes"),8855 },
{ wxT("ouml"),246 },
{ wxT("para"),182 },
{ wxT("part"),8706 },
{ wxT("permil"),8240 },
{ wxT("perp"),8869 },
{ wxT("phi"),966 },
{ wxT("pi"),960 },
{ wxT("piv"),982 },
{ wxT("plusmn"),177 },
{ wxT("pound"),163 },
{ wxT("prime"),8242 },
{ wxT("prod"),8719 },
{ wxT("prop"),8733 },
{ wxT("psi"),968 },
{ wxT("quot"),34 },
{ wxT("rArr"),8658 },
{ wxT("radic"),8730 },
{ wxT("rang"),9002 },
{ wxT("raquo"),187 },
{ wxT("rarr"),8594 },
{ wxT("rceil"),8969 },
{ wxT("rdquo"),8221 },
{ wxT("real"),8476 },
{ wxT("reg"),174 },
{ wxT("rfloor"),8971 },
{ wxT("rho"),961 },
{ wxT("rlm"),8207 },
{ wxT("rsaquo"),8250 },
{ wxT("rsquo"),8217 },
{ wxT("sbquo"),8218 },
{ wxT("scaron"),353 },
{ wxT("sdot"),8901 },
{ wxT("sect"),167 },
{ wxT("shy"),173 },
{ wxT("sigma"),963 },
{ wxT("sigmaf"),962 },
{ wxT("sim"),8764 },
{ wxT("spades"),9824 },
{ wxT("sub"),8834 },
{ wxT("sube"),8838 },
{ wxT("sum"),8721 },
{ wxT("sup"),8835 },
{ wxT("sup1"),185 },
{ wxT("sup2"),178 },
{ wxT("sup3"),179 },
{ wxT("supe"),8839 },
{ wxT("szlig"),223 },
{ wxT("tau"),964 },
{ wxT("there4"),8756 },
{ wxT("theta"),952 },
{ wxT("thetasym"),977 },
{ wxT("thinsp"),8201 },
{ wxT("thorn"),254 },
{ wxT("tilde"),732 },
{ wxT("times"),215 },
{ wxT("trade"),8482 },
{ wxT("uArr"),8657 },
{ wxT("uacute"),250 },
{ wxT("uarr"),8593 },
{ wxT("ucirc"),251 },
{ wxT("ugrave"),249 },
{ wxT("uml"),168 },
{ wxT("upsih"),978 },
{ wxT("upsilon"),965 },
{ wxT("uuml"),252 },
{ wxT("weierp"),8472 },
{ wxT("xi"),958 },
{ wxT("yacute"),253 },
{ wxT("yen"),165 },
{ wxT("yuml"),255 },
{ wxT("zeta"),950 },
{ wxT("zwj"),8205 },
{ wxT("zwnj"),8204 },
{NULL, 0}};
static size_t substitutions_cnt = 0;
if (substitutions_cnt == 0)
while (substitutions[substitutions_cnt].code != 0)
substitutions_cnt++;
wxHtmlEntityInfo *info = NULL;
#ifdef __WXWINCE__
// bsearch crashes under WinCE for some reason
size_t i;
for (i = 0; i < substitutions_cnt; i++)
{
if (entity == substitutions[i].name)
{
info = & substitutions[i];
break;
}
}
#else
info = (wxHtmlEntityInfo*) bsearch(entity.c_str(), substitutions,
substitutions_cnt,
sizeof(wxHtmlEntityInfo),
wxHtmlEntityCompare);
#endif
if (info)
code = info->code;
}
if (code == 0)
return 0;
else
return GetCharForCode(code);
}
wxFSFile *wxHtmlParser::OpenURL(wxHtmlURLType WXUNUSED(type),
const wxString& url) const
{
return m_FS ? m_FS->OpenFile(url) : NULL;
}
//-----------------------------------------------------------------------------
// wxHtmlParser::ExtractCharsetInformation
//-----------------------------------------------------------------------------
class wxMetaTagParser : public wxHtmlParser
{
public:
wxMetaTagParser() { }
wxObject* GetProduct() { return NULL; }
protected:
virtual void AddText(const wxChar* WXUNUSED(txt)) {}
DECLARE_NO_COPY_CLASS(wxMetaTagParser)
};
class wxMetaTagHandler : public wxHtmlTagHandler
{
public:
wxMetaTagHandler(wxString *retval) : wxHtmlTagHandler(), m_retval(retval) {}
wxString GetSupportedTags() { return wxT("META,BODY"); }
bool HandleTag(const wxHtmlTag& tag);
private:
wxString *m_retval;
DECLARE_NO_COPY_CLASS(wxMetaTagHandler)
};
bool wxMetaTagHandler::HandleTag(const wxHtmlTag& tag)
{
if (tag.GetName() == _T("BODY"))
{
m_Parser->StopParsing();
return false;
}
if (tag.HasParam(_T("HTTP-EQUIV")) &&
tag.GetParam(_T("HTTP-EQUIV")).IsSameAs(_T("Content-Type"), false) &&
tag.HasParam(_T("CONTENT")))
{
wxString content = tag.GetParam(_T("CONTENT")).Lower();
if (content.Left(19) == _T("text/html; charset="))
{
*m_retval = content.Mid(19);
m_Parser->StopParsing();
}
}
return false;
}
/*static*/
wxString wxHtmlParser::ExtractCharsetInformation(const wxString& markup)
{
wxString charset;
wxMetaTagParser *parser = new wxMetaTagParser();
if(parser)
{
parser->AddTagHandler(new wxMetaTagHandler(&charset));
parser->Parse(markup);
delete parser;
}
return charset;
}
#endif

View file

@ -0,0 +1,521 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/htmltag.cpp
// Purpose: wxHtmlTag class (represents single tag)
// Author: Vaclav Slavik
// RCS-ID: $Id: htmltag.cpp 53433 2008-05-03 00:40:29Z VZ $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML
#include "wx/html/htmltag.h"
#ifndef WXPRECOMP
#include "wx/colour.h"
#endif
#include "wx/html/htmlpars.h"
#include <stdio.h> // for vsscanf
#include <stdarg.h>
//-----------------------------------------------------------------------------
// wxHtmlTagsCache
//-----------------------------------------------------------------------------
struct wxHtmlCacheItem
{
// this is "pos" value passed to wxHtmlTag's constructor.
// it is position of '<' character of the tag
int Key;
// end positions for the tag:
// end1 is '<' of ending tag,
// end2 is '>' or both are
// -1 if there is no ending tag for this one...
// or -2 if this is ending tag </...>
int End1, End2;
// name of this tag
wxChar *Name;
};
IMPLEMENT_CLASS(wxHtmlTagsCache,wxObject)
#define CACHE_INCREMENT 64
bool wxIsCDATAElement(const wxChar *tag)
{
return (wxStrcmp(tag, _T("SCRIPT")) == 0) ||
(wxStrcmp(tag, _T("STYLE")) == 0);
}
wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source)
{
const wxChar *src = source.c_str();
int lng = source.length();
wxChar tagBuffer[256];
m_Cache = NULL;
m_CacheSize = 0;
m_CachePos = 0;
int pos = 0;
while (pos < lng)
{
if (src[pos] == wxT('<')) // tag found:
{
if (m_CacheSize % CACHE_INCREMENT == 0)
m_Cache = (wxHtmlCacheItem*) realloc(m_Cache, (m_CacheSize + CACHE_INCREMENT) * sizeof(wxHtmlCacheItem));
int tg = m_CacheSize++;
int stpos = pos++;
m_Cache[tg].Key = stpos;
int i;
for ( i = 0;
pos < lng && i < (int)WXSIZEOF(tagBuffer) - 1 &&
src[pos] != wxT('>') && !wxIsspace(src[pos]);
i++, pos++ )
{
tagBuffer[i] = (wxChar)wxToupper(src[pos]);
}
tagBuffer[i] = _T('\0');
m_Cache[tg].Name = new wxChar[i+1];
memcpy(m_Cache[tg].Name, tagBuffer, (i+1)*sizeof(wxChar));
while (pos < lng && src[pos] != wxT('>')) pos++;
if (src[stpos+1] == wxT('/')) // ending tag:
{
m_Cache[tg].End1 = m_Cache[tg].End2 = -2;
// find matching begin tag:
for (i = tg; i >= 0; i--)
if ((m_Cache[i].End1 == -1) && (wxStrcmp(m_Cache[i].Name, tagBuffer+1) == 0))
{
m_Cache[i].End1 = stpos;
m_Cache[i].End2 = pos + 1;
break;
}
}
else
{
m_Cache[tg].End1 = m_Cache[tg].End2 = -1;
if (wxIsCDATAElement(tagBuffer))
{
// store the orig pos in case we are missing the closing
// tag (see below)
wxInt32 old_pos = pos;
bool foundCloseTag = false;
// find next matching tag
int tag_len = wxStrlen(tagBuffer);
while (pos < lng)
{
// find the ending tag
while (pos + 1 < lng &&
(src[pos] != '<' || src[pos+1] != '/'))
++pos;
if (src[pos] == '<')
++pos;
// see if it matches
int match_pos = 0;
while (pos < lng && match_pos < tag_len && src[pos] != '>' && src[pos] != '<') {
// cast to wxChar needed to suppress warning in
// Unicode build
if ((wxChar)wxToupper(src[pos]) == tagBuffer[match_pos]) {
++match_pos;
}
else if (src[pos] == wxT(' ') || src[pos] == wxT('\n') ||
src[pos] == wxT('\r') || src[pos] == wxT('\t')) {
// need to skip over these
}
else {
match_pos = 0;
}
++pos;
}
// found a match
if (match_pos == tag_len)
{
pos = pos - tag_len - 3;
foundCloseTag = true;
break;
}
else // keep looking for the closing tag
{
++pos;
}
}
if (!foundCloseTag)
{
// we didn't find closing tag; this means the markup
// is incorrect and the best thing we can do is to
// ignore the unclosed tag and continue parsing as if
// it didn't exist:
pos = old_pos;
}
}
}
}
pos++;
}
// ok, we're done, now we'll free .Name members of cache - we don't need it anymore:
for (int i = 0; i < m_CacheSize; i++)
{
delete[] m_Cache[i].Name;
m_Cache[i].Name = NULL;
}
}
void wxHtmlTagsCache::QueryTag(int at, int* end1, int* end2)
{
if (m_Cache == NULL) return;
if (m_Cache[m_CachePos].Key != at)
{
int delta = (at < m_Cache[m_CachePos].Key) ? -1 : 1;
do
{
if ( m_CachePos < 0 || m_CachePos == m_CacheSize )
{
// something is very wrong with HTML, give up by returning an
// impossibly large value which is going to be ignored by the
// caller
*end1 =
*end2 = INT_MAX;
return;
}
m_CachePos += delta;
}
while (m_Cache[m_CachePos].Key != at);
}
*end1 = m_Cache[m_CachePos].End1;
*end2 = m_Cache[m_CachePos].End2;
}
//-----------------------------------------------------------------------------
// wxHtmlTag
//-----------------------------------------------------------------------------
IMPLEMENT_CLASS(wxHtmlTag,wxObject)
wxHtmlTag::wxHtmlTag(wxHtmlTag *parent,
const wxString& source, int pos, int end_pos,
wxHtmlTagsCache *cache,
wxHtmlEntitiesParser *entParser) : wxObject()
{
/* Setup DOM relations */
m_Next = NULL;
m_FirstChild = m_LastChild = NULL;
m_Parent = parent;
if (parent)
{
m_Prev = m_Parent->m_LastChild;
if (m_Prev == NULL)
m_Parent->m_FirstChild = this;
else
m_Prev->m_Next = this;
m_Parent->m_LastChild = this;
}
else
m_Prev = NULL;
/* Find parameters and their values: */
int i;
wxChar c;
// fill-in name, params and begin pos:
i = pos+1;
// find tag's name and convert it to uppercase:
while ((i < end_pos) &&
((c = source[i++]) != wxT(' ') && c != wxT('\r') &&
c != wxT('\n') && c != wxT('\t') &&
c != wxT('>')))
{
if ((c >= wxT('a')) && (c <= wxT('z')))
c -= (wxT('a') - wxT('A'));
m_Name << c;
}
// if the tag has parameters, read them and "normalize" them,
// i.e. convert to uppercase, replace whitespaces by spaces and
// remove whitespaces around '=':
if (source[i-1] != wxT('>'))
{
#define IS_WHITE(c) (c == wxT(' ') || c == wxT('\r') || \
c == wxT('\n') || c == wxT('\t'))
wxString pname, pvalue;
wxChar quote;
enum
{
ST_BEFORE_NAME = 1,
ST_NAME,
ST_BEFORE_EQ,
ST_BEFORE_VALUE,
ST_VALUE
} state;
quote = 0;
state = ST_BEFORE_NAME;
while (i < end_pos)
{
c = source[i++];
if (c == wxT('>') && !(state == ST_VALUE && quote != 0))
{
if (state == ST_BEFORE_EQ || state == ST_NAME)
{
m_ParamNames.Add(pname);
m_ParamValues.Add(wxEmptyString);
}
else if (state == ST_VALUE && quote == 0)
{
m_ParamNames.Add(pname);
if (entParser)
m_ParamValues.Add(entParser->Parse(pvalue));
else
m_ParamValues.Add(pvalue);
}
break;
}
switch (state)
{
case ST_BEFORE_NAME:
if (!IS_WHITE(c))
{
pname = c;
state = ST_NAME;
}
break;
case ST_NAME:
if (IS_WHITE(c))
state = ST_BEFORE_EQ;
else if (c == wxT('='))
state = ST_BEFORE_VALUE;
else
pname << c;
break;
case ST_BEFORE_EQ:
if (c == wxT('='))
state = ST_BEFORE_VALUE;
else if (!IS_WHITE(c))
{
m_ParamNames.Add(pname);
m_ParamValues.Add(wxEmptyString);
pname = c;
state = ST_NAME;
}
break;
case ST_BEFORE_VALUE:
if (!IS_WHITE(c))
{
if (c == wxT('"') || c == wxT('\''))
quote = c, pvalue = wxEmptyString;
else
quote = 0, pvalue = c;
state = ST_VALUE;
}
break;
case ST_VALUE:
if ((quote != 0 && c == quote) ||
(quote == 0 && IS_WHITE(c)))
{
m_ParamNames.Add(pname);
if (quote == 0)
{
// VS: backward compatibility, no real reason,
// but wxHTML code relies on this... :(
pvalue.MakeUpper();
}
if (entParser)
m_ParamValues.Add(entParser->Parse(pvalue));
else
m_ParamValues.Add(pvalue);
state = ST_BEFORE_NAME;
}
else
pvalue << c;
break;
}
}
#undef IS_WHITE
}
m_Begin = i;
cache->QueryTag(pos, &m_End1, &m_End2);
if (m_End1 > end_pos) m_End1 = end_pos;
if (m_End2 > end_pos) m_End2 = end_pos;
}
wxHtmlTag::~wxHtmlTag()
{
wxHtmlTag *t1, *t2;
t1 = m_FirstChild;
while (t1)
{
t2 = t1->GetNextSibling();
delete t1;
t1 = t2;
}
}
bool wxHtmlTag::HasParam(const wxString& par) const
{
return (m_ParamNames.Index(par, false) != wxNOT_FOUND);
}
wxString wxHtmlTag::GetParam(const wxString& par, bool with_commas) const
{
int index = m_ParamNames.Index(par, false);
if (index == wxNOT_FOUND)
return wxEmptyString;
if (with_commas)
{
// VS: backward compatibility, seems to be never used by wxHTML...
wxString s;
s << wxT('"') << m_ParamValues[index] << wxT('"');
return s;
}
else
return m_ParamValues[index];
}
int wxHtmlTag::ScanParam(const wxString& par,
const wxChar *format,
void *param) const
{
wxString parval = GetParam(par);
return wxSscanf(parval, format, param);
}
bool wxHtmlTag::GetParamAsColour(const wxString& par, wxColour *clr) const
{
wxCHECK_MSG( clr, false, _T("invalid colour argument") );
wxString str = GetParam(par);
// handle colours defined in HTML 4.0 first:
if (str.length() > 1 && str[0] != _T('#'))
{
#define HTML_COLOUR(name, r, g, b) \
if (str.IsSameAs(wxT(name), false)) \
{ clr->Set(r, g, b); return true; }
HTML_COLOUR("black", 0x00,0x00,0x00)
HTML_COLOUR("silver", 0xC0,0xC0,0xC0)
HTML_COLOUR("gray", 0x80,0x80,0x80)
HTML_COLOUR("white", 0xFF,0xFF,0xFF)
HTML_COLOUR("maroon", 0x80,0x00,0x00)
HTML_COLOUR("red", 0xFF,0x00,0x00)
HTML_COLOUR("purple", 0x80,0x00,0x80)
HTML_COLOUR("fuchsia", 0xFF,0x00,0xFF)
HTML_COLOUR("green", 0x00,0x80,0x00)
HTML_COLOUR("lime", 0x00,0xFF,0x00)
HTML_COLOUR("olive", 0x80,0x80,0x00)
HTML_COLOUR("yellow", 0xFF,0xFF,0x00)
HTML_COLOUR("navy", 0x00,0x00,0x80)
HTML_COLOUR("blue", 0x00,0x00,0xFF)
HTML_COLOUR("teal", 0x00,0x80,0x80)
HTML_COLOUR("aqua", 0x00,0xFF,0xFF)
#undef HTML_COLOUR
}
// then try to parse #rrggbb representations or set from other well
// known names (note that this doesn't strictly conform to HTML spec,
// but it doesn't do real harm -- but it *must* be done after the standard
// colors are handled above):
if (clr->Set(str))
return true;
return false;
}
bool wxHtmlTag::GetParamAsInt(const wxString& par, int *clr) const
{
if ( !HasParam(par) )
return false;
long i;
if ( !GetParam(par).ToLong(&i) )
return false;
*clr = (int)i;
return true;
}
wxString wxHtmlTag::GetAllParams() const
{
// VS: this function is for backward compatibility only,
// never used by wxHTML
wxString s;
size_t cnt = m_ParamNames.GetCount();
for (size_t i = 0; i < cnt; i++)
{
s << m_ParamNames[i];
s << wxT('=');
if (m_ParamValues[i].Find(wxT('"')) != wxNOT_FOUND)
s << wxT('\'') << m_ParamValues[i] << wxT('\'');
else
s << wxT('"') << m_ParamValues[i] << wxT('"');
}
return s;
}
wxHtmlTag *wxHtmlTag::GetFirstSibling() const
{
if (m_Parent)
return m_Parent->m_FirstChild;
else
{
wxHtmlTag *cur = (wxHtmlTag*)this;
while (cur->m_Prev)
cur = cur->m_Prev;
return cur;
}
}
wxHtmlTag *wxHtmlTag::GetLastSibling() const
{
if (m_Parent)
return m_Parent->m_LastChild;
else
{
wxHtmlTag *cur = (wxHtmlTag*)this;
while (cur->m_Next)
cur = cur->m_Next;
return cur;
}
}
wxHtmlTag *wxHtmlTag::GetNextTag() const
{
if (m_FirstChild) return m_FirstChild;
if (m_Next) return m_Next;
wxHtmlTag *cur = m_Parent;
if (!cur) return NULL;
while (cur->m_Parent && !cur->m_Next)
cur = cur->m_Parent;
return cur->m_Next;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,728 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/htmprint.cpp
// Purpose: html printing classes
// Author: Vaclav Slavik
// Created: 25/09/99
// RCS-ID: $Id: htmprint.cpp 55069 2008-08-12 16:02:31Z VS $
// Copyright: (c) Vaclav Slavik, 1999
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_PRINTING_ARCHITECTURE && wxUSE_STREAMS
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/dc.h"
#include "wx/settings.h"
#include "wx/msgdlg.h"
#include "wx/module.h"
#endif
#include "wx/print.h"
#include "wx/printdlg.h"
#include "wx/html/htmprint.h"
#include "wx/wxhtml.h"
#include "wx/wfstream.h"
// default font size of normal text (HTML font size 0) for printing, in points:
#define DEFAULT_PRINT_FONT_SIZE 12
//--------------------------------------------------------------------------------
// wxHtmlDCRenderer
//--------------------------------------------------------------------------------
wxHtmlDCRenderer::wxHtmlDCRenderer() : wxObject()
{
m_DC = NULL;
m_Width = m_Height = 0;
m_Cells = NULL;
m_Parser = new wxHtmlWinParser();
m_FS = new wxFileSystem();
m_Parser->SetFS(m_FS);
SetStandardFonts(DEFAULT_PRINT_FONT_SIZE);
}
wxHtmlDCRenderer::~wxHtmlDCRenderer()
{
if (m_Cells) delete m_Cells;
if (m_Parser) delete m_Parser;
if (m_FS) delete m_FS;
}
void wxHtmlDCRenderer::SetDC(wxDC *dc, double pixel_scale)
{
m_DC = dc;
m_Parser->SetDC(m_DC, pixel_scale);
}
void wxHtmlDCRenderer::SetSize(int width, int height)
{
m_Width = width;
m_Height = height;
}
void wxHtmlDCRenderer::SetHtmlText(const wxString& html, const wxString& basepath, bool isdir)
{
if (m_DC == NULL) return;
if (m_Cells != NULL) delete m_Cells;
m_FS->ChangePathTo(basepath, isdir);
m_Cells = (wxHtmlContainerCell*) m_Parser->Parse(html);
m_Cells->SetIndent(0, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
m_Cells->Layout(m_Width);
}
void wxHtmlDCRenderer::SetFonts(const wxString& normal_face, const wxString& fixed_face,
const int *sizes)
{
m_Parser->SetFonts(normal_face, fixed_face, sizes);
if (m_DC == NULL && m_Cells != NULL)
m_Cells->Layout(m_Width);
}
void wxHtmlDCRenderer::SetStandardFonts(int size,
const wxString& normal_face,
const wxString& fixed_face)
{
m_Parser->SetStandardFonts(size, normal_face, fixed_face);
if (m_DC == NULL && m_Cells != NULL)
m_Cells->Layout(m_Width);
}
int wxHtmlDCRenderer::Render(int x, int y,
wxArrayInt& known_pagebreaks,
int from, int dont_render, int to)
{
int pbreak, hght;
if (m_Cells == NULL || m_DC == NULL) return 0;
pbreak = (int)(from + m_Height);
while (m_Cells->AdjustPagebreak(&pbreak, known_pagebreaks)) {}
hght = pbreak - from;
if(to < hght)
hght = to;
if (!dont_render)
{
wxHtmlRenderingInfo rinfo;
wxDefaultHtmlRenderingStyle rstyle;
rinfo.SetStyle(&rstyle);
m_DC->SetBrush(*wxWHITE_BRUSH);
m_DC->SetClippingRegion(x, y, m_Width, hght);
m_Cells->Draw(*m_DC,
x, (y - from),
y, y + hght,
rinfo);
m_DC->DestroyClippingRegion();
}
if (pbreak < m_Cells->GetHeight()) return pbreak;
else return GetTotalHeight();
}
int wxHtmlDCRenderer::GetTotalHeight()
{
if (m_Cells) return m_Cells->GetHeight();
else return 0;
}
//--------------------------------------------------------------------------------
// wxHtmlPrintout
//--------------------------------------------------------------------------------
wxList wxHtmlPrintout::m_Filters;
wxHtmlPrintout::wxHtmlPrintout(const wxString& title) : wxPrintout(title)
{
m_Renderer = new wxHtmlDCRenderer;
m_RendererHdr = new wxHtmlDCRenderer;
m_NumPages = wxHTML_PRINT_MAX_PAGES;
m_Document = m_BasePath = wxEmptyString; m_BasePathIsDir = true;
m_Headers[0] = m_Headers[1] = wxEmptyString;
m_Footers[0] = m_Footers[1] = wxEmptyString;
m_HeaderHeight = m_FooterHeight = 0;
SetMargins(); // to default values
SetStandardFonts(DEFAULT_PRINT_FONT_SIZE);
}
wxHtmlPrintout::~wxHtmlPrintout()
{
delete m_Renderer;
delete m_RendererHdr;
}
void wxHtmlPrintout::CleanUpStatics()
{
WX_CLEAR_LIST(wxList, m_Filters);
}
// Adds input filter
void wxHtmlPrintout::AddFilter(wxHtmlFilter *filter)
{
m_Filters.Append(filter);
}
void wxHtmlPrintout::OnPreparePrinting()
{
int pageWidth, pageHeight, mm_w, mm_h, scr_w, scr_h, dc_w, dc_h;
float ppmm_h, ppmm_v;
GetPageSizePixels(&pageWidth, &pageHeight);
GetPageSizeMM(&mm_w, &mm_h);
ppmm_h = (float)pageWidth / mm_w;
ppmm_v = (float)pageHeight / mm_h;
int ppiPrinterX, ppiPrinterY;
GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
int ppiScreenX, ppiScreenY;
GetPPIScreen(&ppiScreenX, &ppiScreenY);
wxDisplaySize(&scr_w, &scr_h);
GetDC()->GetSize(&dc_w, &dc_h);
GetDC()->SetUserScale((double)dc_w / (double)pageWidth,
(double)dc_h / (double)pageHeight);
/* prepare headers/footers renderer: */
m_RendererHdr->SetDC(GetDC(), (double)ppiPrinterY / (double)ppiScreenY);
m_RendererHdr->SetSize((int) (ppmm_h * (mm_w - m_MarginLeft - m_MarginRight)),
(int) (ppmm_v * (mm_h - m_MarginTop - m_MarginBottom)));
if (m_Headers[0] != wxEmptyString)
{
m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[0], 1));
m_HeaderHeight = m_RendererHdr->GetTotalHeight();
}
else if (m_Headers[1] != wxEmptyString)
{
m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[1], 1));
m_HeaderHeight = m_RendererHdr->GetTotalHeight();
}
if (m_Footers[0] != wxEmptyString)
{
m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[0], 1));
m_FooterHeight = m_RendererHdr->GetTotalHeight();
}
else if (m_Footers[1] != wxEmptyString)
{
m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[1], 1));
m_FooterHeight = m_RendererHdr->GetTotalHeight();
}
/* prepare main renderer: */
m_Renderer->SetDC(GetDC(), (double)ppiPrinterY / (double)ppiScreenY);
m_Renderer->SetSize((int) (ppmm_h * (mm_w - m_MarginLeft - m_MarginRight)),
(int) (ppmm_v * (mm_h - m_MarginTop - m_MarginBottom) -
m_FooterHeight - m_HeaderHeight -
((m_HeaderHeight == 0) ? 0 : m_MarginSpace * ppmm_v) -
((m_FooterHeight == 0) ? 0 : m_MarginSpace * ppmm_v)
));
m_Renderer->SetHtmlText(m_Document, m_BasePath, m_BasePathIsDir);
CountPages();
}
bool wxHtmlPrintout::OnBeginDocument(int startPage, int endPage)
{
if (!wxPrintout::OnBeginDocument(startPage, endPage)) return false;
return true;
}
bool wxHtmlPrintout::OnPrintPage(int page)
{
wxDC *dc = GetDC();
if (dc && dc->Ok())
{
if (HasPage(page))
RenderPage(dc, page);
return true;
}
else return false;
}
void wxHtmlPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
{
*minPage = 1;
if ( m_NumPages >= (signed)m_PageBreaks.Count()-1)
*maxPage = m_NumPages;
else
*maxPage = (signed)m_PageBreaks.Count()-1;
*selPageFrom = 1;
*selPageTo = (signed)m_PageBreaks.Count()-1;
}
bool wxHtmlPrintout::HasPage(int pageNum)
{
return pageNum > 0 && (unsigned)pageNum < m_PageBreaks.Count();
}
void wxHtmlPrintout::SetHtmlText(const wxString& html, const wxString &basepath, bool isdir)
{
m_Document = html;
m_BasePath = basepath;
m_BasePathIsDir = isdir;
}
void wxHtmlPrintout::SetHtmlFile(const wxString& htmlfile)
{
wxFileSystem fs;
wxFSFile *ff;
if (wxFileExists(htmlfile))
ff = fs.OpenFile(wxFileSystem::FileNameToURL(htmlfile));
else
ff = fs.OpenFile(htmlfile);
if (ff == NULL)
{
wxLogError(htmlfile + _(": file does not exist!"));
return;
}
bool done = false;
wxHtmlFilterHTML defaultFilter;
wxString doc;
wxList::compatibility_iterator node = m_Filters.GetFirst();
while (node)
{
wxHtmlFilter *h = (wxHtmlFilter*) node->GetData();
if (h->CanRead(*ff))
{
doc = h->ReadFile(*ff);
done = true;
break;
}
node = node->GetNext();
}
if (!done)
doc = defaultFilter.ReadFile(*ff);
SetHtmlText(doc, htmlfile, false);
delete ff;
}
void wxHtmlPrintout::SetHeader(const wxString& header, int pg)
{
if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
m_Headers[0] = header;
if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
m_Headers[1] = header;
}
void wxHtmlPrintout::SetFooter(const wxString& footer, int pg)
{
if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
m_Footers[0] = footer;
if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
m_Footers[1] = footer;
}
void wxHtmlPrintout::CountPages()
{
wxBusyCursor wait;
int pageWidth, pageHeight, mm_w, mm_h;
float ppmm_h, ppmm_v;
GetPageSizePixels(&pageWidth, &pageHeight);
GetPageSizeMM(&mm_w, &mm_h);
ppmm_h = (float)pageWidth / mm_w;
ppmm_v = (float)pageHeight / mm_h;
int pos = 0;
m_NumPages = 0;
// m_PageBreaks[0] = 0;
m_PageBreaks.Clear();
m_PageBreaks.Add( 0);
do
{
pos = m_Renderer->Render((int)( ppmm_h * m_MarginLeft),
(int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight),
m_PageBreaks,
pos, true, INT_MAX);
m_PageBreaks.Add( pos);
if( m_PageBreaks.Count() > wxHTML_PRINT_MAX_PAGES)
{
wxMessageBox( _("HTML pagination algorithm generated more than the allowed maximum number of pages and it can't continue any longer!"),
_("Warning"), wxCANCEL | wxICON_ERROR );
break;
}
} while (pos < m_Renderer->GetTotalHeight());
}
void wxHtmlPrintout::RenderPage(wxDC *dc, int page)
{
wxBusyCursor wait;
int pageWidth, pageHeight, mm_w, mm_h, scr_w, scr_h, dc_w, dc_h;
float ppmm_h, ppmm_v;
GetPageSizePixels(&pageWidth, &pageHeight);
GetPageSizeMM(&mm_w, &mm_h);
ppmm_h = (float)pageWidth / mm_w;
ppmm_v = (float)pageHeight / mm_h;
wxDisplaySize(&scr_w, &scr_h);
dc->GetSize(&dc_w, &dc_h);
int ppiPrinterX, ppiPrinterY;
GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
wxUnusedVar(ppiPrinterX);
int ppiScreenX, ppiScreenY;
GetPPIScreen(&ppiScreenX, &ppiScreenY);
wxUnusedVar(ppiScreenX);
dc->SetUserScale((double)dc_w / (double)pageWidth,
(double)dc_h / (double)pageHeight);
m_Renderer->SetDC(dc, (double)ppiPrinterY / (double)ppiScreenY);
dc->SetBackgroundMode(wxTRANSPARENT);
m_Renderer->Render((int) (ppmm_h * m_MarginLeft),
(int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), m_PageBreaks,
m_PageBreaks[page-1], false, m_PageBreaks[page]-m_PageBreaks[page-1]);
m_RendererHdr->SetDC(dc, (double)ppiPrinterY / (double)ppiScreenY);
if (m_Headers[page % 2] != wxEmptyString)
{
m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[page % 2], page));
m_RendererHdr->Render((int) (ppmm_h * m_MarginLeft), (int) (ppmm_v * m_MarginTop), m_PageBreaks);
}
if (m_Footers[page % 2] != wxEmptyString)
{
m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[page % 2], page));
m_RendererHdr->Render((int) (ppmm_h * m_MarginLeft), (int) (pageHeight - ppmm_v * m_MarginBottom - m_FooterHeight), m_PageBreaks);
}
}
wxString wxHtmlPrintout::TranslateHeader(const wxString& instr, int page)
{
wxString r = instr;
wxString num;
num.Printf(wxT("%i"), page);
r.Replace(wxT("@PAGENUM@"), num);
num.Printf(wxT("%lu"), (unsigned long)(m_PageBreaks.Count() - 1));
r.Replace(wxT("@PAGESCNT@"), num);
const wxDateTime now = wxDateTime::Now();
r.Replace(wxT("@DATE@"), now.FormatDate());
r.Replace(wxT("@TIME@"), now.FormatTime());
r.Replace(wxT("@TITLE@"), GetTitle());
return r;
}
void wxHtmlPrintout::SetMargins(float top, float bottom, float left, float right, float spaces)
{
m_MarginTop = top;
m_MarginBottom = bottom;
m_MarginLeft = left;
m_MarginRight = right;
m_MarginSpace = spaces;
}
void wxHtmlPrintout::SetFonts(const wxString& normal_face, const wxString& fixed_face,
const int *sizes)
{
m_Renderer->SetFonts(normal_face, fixed_face, sizes);
m_RendererHdr->SetFonts(normal_face, fixed_face, sizes);
}
void wxHtmlPrintout::SetStandardFonts(int size,
const wxString& normal_face,
const wxString& fixed_face)
{
m_Renderer->SetStandardFonts(size, normal_face, fixed_face);
m_RendererHdr->SetStandardFonts(size, normal_face, fixed_face);
}
//----------------------------------------------------------------------------
// wxHtmlEasyPrinting
//----------------------------------------------------------------------------
wxHtmlEasyPrinting::wxHtmlEasyPrinting(const wxString& name, wxWindow *parentWindow)
{
m_ParentWindow = parentWindow;
m_Name = name;
m_PrintData = NULL;
m_PageSetupData = new wxPageSetupDialogData;
m_Headers[0] = m_Headers[1] = m_Footers[0] = m_Footers[1] = wxEmptyString;
m_PageSetupData->EnableMargins(true);
m_PageSetupData->SetMarginTopLeft(wxPoint(25, 25));
m_PageSetupData->SetMarginBottomRight(wxPoint(25, 25));
SetStandardFonts(DEFAULT_PRINT_FONT_SIZE);
}
wxHtmlEasyPrinting::~wxHtmlEasyPrinting()
{
delete m_PrintData;
delete m_PageSetupData;
}
wxPrintData *wxHtmlEasyPrinting::GetPrintData()
{
if (m_PrintData == NULL)
m_PrintData = new wxPrintData();
return m_PrintData;
}
bool wxHtmlEasyPrinting::PreviewFile(const wxString &htmlfile)
{
wxHtmlPrintout *p1 = CreatePrintout();
p1->SetHtmlFile(htmlfile);
wxHtmlPrintout *p2 = CreatePrintout();
p2->SetHtmlFile(htmlfile);
return DoPreview(p1, p2);
}
bool wxHtmlEasyPrinting::PreviewText(const wxString &htmltext, const wxString &basepath)
{
wxHtmlPrintout *p1 = CreatePrintout();
p1->SetHtmlText(htmltext, basepath, true);
wxHtmlPrintout *p2 = CreatePrintout();
p2->SetHtmlText(htmltext, basepath, true);
return DoPreview(p1, p2);
}
bool wxHtmlEasyPrinting::PrintFile(const wxString &htmlfile)
{
wxHtmlPrintout *p = CreatePrintout();
p->SetHtmlFile(htmlfile);
bool ret = DoPrint(p);
delete p;
return ret;
}
bool wxHtmlEasyPrinting::PrintText(const wxString &htmltext, const wxString &basepath)
{
wxHtmlPrintout *p = CreatePrintout();
p->SetHtmlText(htmltext, basepath, true);
bool ret = DoPrint(p);
delete p;
return ret;
}
bool wxHtmlEasyPrinting::DoPreview(wxHtmlPrintout *printout1, wxHtmlPrintout *printout2)
{
// Pass two printout objects: for preview, and possible printing.
wxPrintDialogData printDialogData(*GetPrintData());
wxPrintPreview *preview = new wxPrintPreview(printout1, printout2, &printDialogData);
if (!preview->Ok())
{
delete preview;
return false;
}
wxPreviewFrame *frame = new wxPreviewFrame(preview, m_ParentWindow,
m_Name + _(" Preview"),
wxPoint(100, 100), wxSize(650, 500));
frame->Centre(wxBOTH);
frame->Initialize();
frame->Show(true);
return true;
}
bool wxHtmlEasyPrinting::DoPrint(wxHtmlPrintout *printout)
{
wxPrintDialogData printDialogData(*GetPrintData());
wxPrinter printer(&printDialogData);
if (!printer.Print(m_ParentWindow, printout, true))
{
return false;
}
(*GetPrintData()) = printer.GetPrintDialogData().GetPrintData();
return true;
}
void wxHtmlEasyPrinting::PageSetup()
{
if (!GetPrintData()->Ok())
{
wxLogError(_("There was a problem during page setup: you may need to set a default printer."));
return;
}
m_PageSetupData->SetPrintData(*GetPrintData());
wxPageSetupDialog pageSetupDialog(m_ParentWindow, m_PageSetupData);
if (pageSetupDialog.ShowModal() == wxID_OK)
{
(*GetPrintData()) = pageSetupDialog.GetPageSetupData().GetPrintData();
(*m_PageSetupData) = pageSetupDialog.GetPageSetupData();
}
}
void wxHtmlEasyPrinting::SetHeader(const wxString& header, int pg)
{
if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
m_Headers[0] = header;
if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
m_Headers[1] = header;
}
void wxHtmlEasyPrinting::SetFooter(const wxString& footer, int pg)
{
if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
m_Footers[0] = footer;
if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
m_Footers[1] = footer;
}
void wxHtmlEasyPrinting::SetFonts(const wxString& normal_face, const wxString& fixed_face,
const int *sizes)
{
m_fontMode = FontMode_Explicit;
m_FontFaceNormal = normal_face;
m_FontFaceFixed = fixed_face;
if (sizes)
{
m_FontsSizes = m_FontsSizesArr;
for (int i = 0; i < 7; i++) m_FontsSizes[i] = sizes[i];
}
else
m_FontsSizes = NULL;
}
void wxHtmlEasyPrinting::SetStandardFonts(int size,
const wxString& normal_face,
const wxString& fixed_face)
{
m_fontMode = FontMode_Standard;
m_FontFaceNormal = normal_face;
m_FontFaceFixed = fixed_face;
m_FontsSizesArr[0] = size;
}
wxHtmlPrintout *wxHtmlEasyPrinting::CreatePrintout()
{
wxHtmlPrintout *p = new wxHtmlPrintout(m_Name);
if (m_fontMode == FontMode_Explicit)
{
p->SetFonts(m_FontFaceNormal, m_FontFaceFixed, m_FontsSizes);
}
else // FontMode_Standard
{
p->SetStandardFonts(m_FontsSizesArr[0],
m_FontFaceNormal, m_FontFaceFixed);
}
p->SetHeader(m_Headers[0], wxPAGE_EVEN);
p->SetHeader(m_Headers[1], wxPAGE_ODD);
p->SetFooter(m_Footers[0], wxPAGE_EVEN);
p->SetFooter(m_Footers[1], wxPAGE_ODD);
p->SetMargins(m_PageSetupData->GetMarginTopLeft().y,
m_PageSetupData->GetMarginBottomRight().y,
m_PageSetupData->GetMarginTopLeft().x,
m_PageSetupData->GetMarginBottomRight().x);
return p;
}
// A module to allow initialization/cleanup
// without calling these functions from app.cpp or from
// the user's application.
class wxHtmlPrintingModule: public wxModule
{
DECLARE_DYNAMIC_CLASS(wxHtmlPrintingModule)
public:
wxHtmlPrintingModule() : wxModule() {}
bool OnInit() { return true; }
void OnExit() { wxHtmlPrintout::CleanUpStatics(); }
};
IMPLEMENT_DYNAMIC_CLASS(wxHtmlPrintingModule, wxModule)
// This hack forces the linker to always link in m_* files
// (wxHTML doesn't work without handlers from these files)
#include "wx/html/forcelnk.h"
FORCE_WXHTML_MODULES()
#endif // wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE

View file

@ -0,0 +1,86 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_dflist.cpp
// Purpose: wxHtml module for definition lists (DL,DT,DD)
// Author: Vaclav Slavik
// RCS-ID: $Id: m_dflist.cpp 38788 2006-04-18 08:11:26Z ABX $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlcell.h"
FORCE_LINK_ME(m_dflist)
TAG_HANDLER_BEGIN(DEFLIST, "DL,DT,DD" )
TAG_HANDLER_CONSTR(DEFLIST) { }
TAG_HANDLER_PROC(tag)
{
wxHtmlContainerCell *c;
if (tag.GetName() == wxT("DL"))
{
if (m_WParser->GetContainer()->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
m_WParser->GetContainer()->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
ParseInner(tag);
if (m_WParser->GetContainer()->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
m_WParser->GetContainer()->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
return true;
}
else if (tag.GetName() == wxT("DT"))
{
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
c->SetAlignHor(wxHTML_ALIGN_LEFT);
c->SetMinHeight(m_WParser->GetCharHeight());
return false;
}
else // "DD"
{
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT);
return false;
}
}
TAG_HANDLER_END(DEFLIST)
TAGS_MODULE_BEGIN(DefinitionList)
TAGS_MODULE_ADD(DEFLIST)
TAGS_MODULE_END(DefinitionList)
#endif

View file

@ -0,0 +1,322 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_fonts.cpp
// Purpose: wxHtml module for fonts & colors of fonts
// Author: Vaclav Slavik
// RCS-ID: $Id: m_fonts.cpp 39371 2006-05-28 13:51:34Z VZ $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/fontenum.h"
#include "wx/tokenzr.h"
FORCE_LINK_ME(m_fonts)
TAG_HANDLER_BEGIN(FONT, "FONT" )
TAG_HANDLER_VARS
wxArrayString m_Faces;
TAG_HANDLER_CONSTR(FONT) { }
TAG_HANDLER_PROC(tag)
{
wxColour oldclr = m_WParser->GetActualColor();
int oldsize = m_WParser->GetFontSize();
wxString oldface = m_WParser->GetFontFace();
if (tag.HasParam(wxT("COLOR")))
{
wxColour clr;
if (tag.GetParamAsColour(wxT("COLOR"), &clr))
{
m_WParser->SetActualColor(clr);
m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(clr));
}
}
if (tag.HasParam(wxT("SIZE")))
{
int tmp = 0;
wxChar c = tag.GetParam(wxT("SIZE")).GetChar(0);
if (tag.GetParamAsInt(wxT("SIZE"), &tmp))
{
if (c == wxT('+') || c == wxT('-'))
m_WParser->SetFontSize(oldsize+tmp);
else
m_WParser->SetFontSize(tmp);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
}
}
if (tag.HasParam(wxT("FACE")))
{
if (m_Faces.GetCount() == 0)
m_Faces = wxFontEnumerator::GetFacenames();
wxStringTokenizer tk(tag.GetParam(wxT("FACE")), wxT(","));
int index;
while (tk.HasMoreTokens())
{
if ((index = m_Faces.Index(tk.GetNextToken(), false)) != wxNOT_FOUND)
{
m_WParser->SetFontFace(m_Faces[index]);
m_WParser->GetContainer()->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
break;
}
}
}
ParseInner(tag);
if (oldface != m_WParser->GetFontFace())
{
m_WParser->SetFontFace(oldface);
m_WParser->GetContainer()->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
}
if (oldsize != m_WParser->GetFontSize())
{
m_WParser->SetFontSize(oldsize);
m_WParser->GetContainer()->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
}
if (oldclr != m_WParser->GetActualColor())
{
m_WParser->SetActualColor(oldclr);
m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(oldclr));
}
return true;
}
TAG_HANDLER_END(FONT)
TAG_HANDLER_BEGIN(FACES_U, "U,STRIKE")
TAG_HANDLER_CONSTR(FACES_U) { }
TAG_HANDLER_PROC(tag)
{
int underlined = m_WParser->GetFontUnderlined();
m_WParser->SetFontUnderlined(true);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
ParseInner(tag);
m_WParser->SetFontUnderlined(underlined);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
return true;
}
TAG_HANDLER_END(FACES_U)
TAG_HANDLER_BEGIN(FACES_B, "B,STRONG")
TAG_HANDLER_CONSTR(FACES_B) { }
TAG_HANDLER_PROC(tag)
{
int bold = m_WParser->GetFontBold();
m_WParser->SetFontBold(true);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
ParseInner(tag);
m_WParser->SetFontBold(bold);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
return true;
}
TAG_HANDLER_END(FACES_B)
TAG_HANDLER_BEGIN(FACES_I, "I,EM,CITE,ADDRESS")
TAG_HANDLER_CONSTR(FACES_I) { }
TAG_HANDLER_PROC(tag)
{
int italic = m_WParser->GetFontItalic();
m_WParser->SetFontItalic(true);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
ParseInner(tag);
m_WParser->SetFontItalic(italic);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
return true;
}
TAG_HANDLER_END(FACES_I)
TAG_HANDLER_BEGIN(FACES_TT, "TT,CODE,KBD,SAMP")
TAG_HANDLER_CONSTR(FACES_TT) { }
TAG_HANDLER_PROC(tag)
{
int fixed = m_WParser->GetFontFixed();
m_WParser->SetFontFixed(true);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
ParseInner(tag);
m_WParser->SetFontFixed(fixed);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
return true;
}
TAG_HANDLER_END(FACES_TT)
TAG_HANDLER_BEGIN(Hx, "H1,H2,H3,H4,H5,H6")
TAG_HANDLER_CONSTR(Hx) { }
TAG_HANDLER_PROC(tag)
{
int old_size, old_b, old_i, old_u, old_f, old_al;
wxHtmlContainerCell *c;
old_size = m_WParser->GetFontSize();
old_b = m_WParser->GetFontBold();
old_i = m_WParser->GetFontItalic();
old_u = m_WParser->GetFontUnderlined();
old_f = m_WParser->GetFontFixed();
old_al = m_WParser->GetAlign();
m_WParser->SetFontBold(true);
m_WParser->SetFontItalic(false);
m_WParser->SetFontUnderlined(false);
m_WParser->SetFontFixed(false);
if (tag.GetName() == wxT("H1"))
m_WParser->SetFontSize(7);
else if (tag.GetName() == wxT("H2"))
m_WParser->SetFontSize(6);
else if (tag.GetName() == wxT("H3"))
m_WParser->SetFontSize(5);
else if (tag.GetName() == wxT("H4"))
{
m_WParser->SetFontSize(5);
m_WParser->SetFontItalic(true);
m_WParser->SetFontBold(false);
}
else if (tag.GetName() == wxT("H5"))
m_WParser->SetFontSize(4);
else if (tag.GetName() == wxT("H6"))
{
m_WParser->SetFontSize(4);
m_WParser->SetFontItalic(true);
m_WParser->SetFontBold(false);
}
c = m_WParser->GetContainer();
if (c->GetFirstChild())
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
c = m_WParser->GetContainer();
}
c = m_WParser->GetContainer();
c->SetAlign(tag);
c->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
m_WParser->SetAlign(c->GetAlignHor());
ParseInner(tag);
m_WParser->SetFontSize(old_size);
m_WParser->SetFontBold(old_b);
m_WParser->SetFontItalic(old_i);
m_WParser->SetFontUnderlined(old_u);
m_WParser->SetFontFixed(old_f);
m_WParser->SetAlign(old_al);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
m_WParser->CloseContainer();
m_WParser->OpenContainer();
c = m_WParser->GetContainer();
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
return true;
}
TAG_HANDLER_END(Hx)
TAG_HANDLER_BEGIN(BIGSMALL, "BIG,SMALL")
TAG_HANDLER_CONSTR(BIGSMALL) { }
TAG_HANDLER_PROC(tag)
{
int oldsize = m_WParser->GetFontSize();
int sz = (tag.GetName() == wxT("BIG")) ? +1 : -1;
m_WParser->SetFontSize(sz);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
ParseInner(tag);
m_WParser->SetFontSize(oldsize);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
return true;
}
TAG_HANDLER_END(BIGSMALL)
TAGS_MODULE_BEGIN(Fonts)
TAGS_MODULE_ADD(FONT)
TAGS_MODULE_ADD(FACES_U)
TAGS_MODULE_ADD(FACES_I)
TAGS_MODULE_ADD(FACES_B)
TAGS_MODULE_ADD(FACES_TT)
TAGS_MODULE_ADD(Hx)
TAGS_MODULE_ADD(BIGSMALL)
TAGS_MODULE_END(Fonts)
#endif

View file

@ -0,0 +1,111 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_hline.cpp
// Purpose: wxHtml module for horizontal line (HR tag)
// Author: Vaclav Slavik
// RCS-ID: $Id: m_hline.cpp 38788 2006-04-18 08:11:26Z ABX $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/brush.h"
#include "wx/pen.h"
#include "wx/dc.h"
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlcell.h"
FORCE_LINK_ME(m_hline)
//-----------------------------------------------------------------------------
// wxHtmlLineCell
//-----------------------------------------------------------------------------
class wxHtmlLineCell : public wxHtmlCell
{
public:
wxHtmlLineCell(int size, bool shading) : wxHtmlCell() {m_Height = size; m_HasShading = shading;}
void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
wxHtmlRenderingInfo& info);
void Layout(int w)
{ m_Width = w; wxHtmlCell::Layout(w); }
private:
// Should we draw 3-D shading or not
bool m_HasShading;
DECLARE_NO_COPY_CLASS(wxHtmlLineCell)
};
void wxHtmlLineCell::Draw(wxDC& dc, int x, int y,
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info))
{
wxBrush mybrush(wxT("GREY"), (m_HasShading) ? wxTRANSPARENT : wxSOLID);
wxPen mypen(wxT("GREY"), 1, wxSOLID);
dc.SetBrush(mybrush);
dc.SetPen(mypen);
dc.DrawRectangle(x + m_PosX, y + m_PosY, m_Width, m_Height);
}
//-----------------------------------------------------------------------------
// The list handler:
//-----------------------------------------------------------------------------
TAG_HANDLER_BEGIN(HR, "HR")
TAG_HANDLER_CONSTR(HR) { }
TAG_HANDLER_PROC(tag)
{
wxHtmlContainerCell *c;
int sz;
bool HasShading;
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_VERTICAL);
c->SetAlignHor(wxHTML_ALIGN_CENTER);
c->SetAlign(tag);
c->SetWidthFloat(tag);
sz = 1;
tag.GetParamAsInt(wxT("SIZE"), &sz);
HasShading = !(tag.HasParam(wxT("NOSHADE")));
c->InsertCell(new wxHtmlLineCell((int)((double)sz * m_WParser->GetPixelScale()), HasShading));
m_WParser->CloseContainer();
m_WParser->OpenContainer();
return false;
}
TAG_HANDLER_END(HR)
TAGS_MODULE_BEGIN(HLine)
TAGS_MODULE_ADD(HR)
TAGS_MODULE_END(HLine)
#endif

View file

@ -0,0 +1,735 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_image.cpp
// Purpose: wxHtml module for displaying images
// Author: Vaclav Slavik
// RCS-ID: $Id: m_image.cpp 52997 2008-04-03 18:55:46Z VS $
// Copyright: (c) 1999 Vaclav Slavik, Joel Lucsy
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/dynarray.h"
#include "wx/dc.h"
#include "wx/scrolwin.h"
#include "wx/timer.h"
#include "wx/dcmemory.h"
#include "wx/log.h"
#include "wx/math.h"
#include "wx/image.h"
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlwin.h"
#include "wx/gifdecod.h"
#include "wx/artprov.h"
#include <float.h>
FORCE_LINK_ME(m_image)
WX_DECLARE_OBJARRAY(int, CoordArray);
#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
WX_DEFINE_OBJARRAY(CoordArray)
// ---------------------------------------------------------------------------
// wxHtmlImageMapAreaCell
// 0-width, 0-height cell that represents single area in
// imagemap (it's GetLink is called from wxHtmlImageCell's)
// ---------------------------------------------------------------------------
class wxHtmlImageMapAreaCell : public wxHtmlCell
{
public:
enum celltype { CIRCLE, RECT, POLY };
protected:
CoordArray coords;
celltype type;
int radius;
public:
wxHtmlImageMapAreaCell( celltype t, wxString &coords, double pixel_scale = 1.0);
virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
void Draw(wxDC& WXUNUSED(dc),
int WXUNUSED(x), int WXUNUSED(y),
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info)) {}
DECLARE_NO_COPY_CLASS(wxHtmlImageMapAreaCell)
};
wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t, wxString &incoords, double pixel_scale )
{
int i;
wxString x = incoords, y;
type = t;
while ((i = x.Find( ',' )) != wxNOT_FOUND)
{
coords.Add( (int)(pixel_scale * (double)wxAtoi( x.Left( i ).c_str())) );
x = x.Mid( i + 1 );
}
coords.Add( (int)(pixel_scale * (double)wxAtoi( x.c_str())) );
}
wxHtmlLinkInfo *wxHtmlImageMapAreaCell::GetLink( int x, int y ) const
{
switch (type)
{
case RECT:
{
int l, t, r, b;
l = coords[ 0 ];
t = coords[ 1 ];
r = coords[ 2 ];
b = coords[ 3 ];
if (x >= l && x <= r && y >= t && y <= b)
{
return m_Link;
}
break;
}
case CIRCLE:
{
int l, t, r;
double d;
l = coords[ 0 ];
t = coords[ 1 ];
r = coords[ 2 ];
d = sqrt( (double) (((x - l) * (x - l)) + ((y - t) * (y - t))) );
if (d < (double)r)
{
return m_Link;
}
}
break;
case POLY:
{
if (coords.GetCount() >= 6)
{
int intersects = 0;
int wherex = x;
int wherey = y;
int totalv = coords.GetCount() / 2;
int totalc = totalv * 2;
int xval = coords[totalc - 2];
int yval = coords[totalc - 1];
int end = totalc;
int pointer = 1;
if ((yval >= wherey) != (coords[pointer] >= wherey))
{
if ((xval >= wherex) == (coords[0] >= wherex))
{
intersects += (xval >= wherex) ? 1 : 0;
}
else
{
intersects += ((xval - (yval - wherey) *
(coords[0] - xval) /
(coords[pointer] - yval)) >= wherex) ? 1 : 0;
}
}
while (pointer < end)
{
yval = coords[pointer];
pointer += 2;
if (yval >= wherey)
{
while ((pointer < end) && (coords[pointer] >= wherey))
{
pointer += 2;
}
if (pointer >= end)
{
break;
}
if ((coords[pointer - 3] >= wherex) ==
(coords[pointer - 1] >= wherex)) {
intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
}
else
{
intersects +=
((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
(coords[pointer - 1] - coords[pointer - 3]) /
(coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
}
}
else
{
while ((pointer < end) && (coords[pointer] < wherey))
{
pointer += 2;
}
if (pointer >= end)
{
break;
}
if ((coords[pointer - 3] >= wherex) ==
(coords[pointer - 1] >= wherex))
{
intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
}
else
{
intersects +=
((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
(coords[pointer - 1] - coords[pointer - 3]) /
(coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
}
}
}
if ((intersects & 1) != 0)
{
return m_Link;
}
}
}
break;
}
if (m_Next)
{
wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
return a->GetLink( x, y );
}
return NULL;
}
//--------------------------------------------------------------------------------
// wxHtmlImageMapCell
// 0-width, 0-height cell that represents map from imagemaps
// it is always placed before wxHtmlImageMapAreaCells
// It responds to Find(wxHTML_COND_ISIMAGEMAP)
//--------------------------------------------------------------------------------
class wxHtmlImageMapCell : public wxHtmlCell
{
public:
wxHtmlImageMapCell( wxString &name );
protected:
wxString m_Name;
public:
virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
virtual const wxHtmlCell *Find( int cond, const void *param ) const;
void Draw(wxDC& WXUNUSED(dc),
int WXUNUSED(x), int WXUNUSED(y),
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info)) {}
DECLARE_NO_COPY_CLASS(wxHtmlImageMapCell)
};
wxHtmlImageMapCell::wxHtmlImageMapCell( wxString &name )
{
m_Name = name ;
}
wxHtmlLinkInfo *wxHtmlImageMapCell::GetLink( int x, int y ) const
{
wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
if (a)
return a->GetLink( x, y );
return wxHtmlCell::GetLink( x, y );
}
const wxHtmlCell *wxHtmlImageMapCell::Find( int cond, const void *param ) const
{
if (cond == wxHTML_COND_ISIMAGEMAP)
{
if (m_Name == *((wxString*)(param)))
return this;
}
return wxHtmlCell::Find(cond, param);
}
//--------------------------------------------------------------------------------
// wxHtmlImageCell
// Image/bitmap
//--------------------------------------------------------------------------------
class wxHtmlImageCell : public wxHtmlCell
{
public:
wxHtmlImageCell(wxHtmlWindowInterface *windowIface,
wxFSFile *input, int w = wxDefaultCoord, int h = wxDefaultCoord,
double scale = 1.0, int align = wxHTML_ALIGN_BOTTOM,
const wxString& mapname = wxEmptyString);
virtual ~wxHtmlImageCell();
void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
wxHtmlRenderingInfo& info);
virtual wxHtmlLinkInfo *GetLink(int x = 0, int y = 0) const;
void SetImage(const wxImage& img);
#if wxUSE_GIF && wxUSE_TIMER
void AdvanceAnimation(wxTimer *timer);
virtual void Layout(int w);
#endif
private:
wxBitmap *m_bitmap;
int m_bmpW, m_bmpH;
bool m_showFrame:1;
wxHtmlWindowInterface *m_windowIface;
#if wxUSE_GIF && wxUSE_TIMER
wxGIFDecoder *m_gifDecoder;
wxTimer *m_gifTimer;
int m_physX, m_physY;
size_t m_nCurrFrame;
#endif
double m_scale;
wxHtmlImageMapCell *m_imageMap;
wxString m_mapName;
DECLARE_NO_COPY_CLASS(wxHtmlImageCell)
};
#if wxUSE_GIF && wxUSE_TIMER
class wxGIFTimer : public wxTimer
{
public:
wxGIFTimer(wxHtmlImageCell *cell) : m_cell(cell) {}
virtual void Notify()
{
m_cell->AdvanceAnimation(this);
}
private:
wxHtmlImageCell *m_cell;
DECLARE_NO_COPY_CLASS(wxGIFTimer)
};
#endif
//----------------------------------------------------------------------------
// wxHtmlImageCell
//----------------------------------------------------------------------------
wxHtmlImageCell::wxHtmlImageCell(wxHtmlWindowInterface *windowIface,
wxFSFile *input,
int w, int h, double scale, int align,
const wxString& mapname) : wxHtmlCell()
{
m_windowIface = windowIface;
m_scale = scale;
m_showFrame = false;
m_bitmap = NULL;
m_bmpW = w;
m_bmpH = h;
m_imageMap = NULL;
m_mapName = mapname;
SetCanLiveOnPagebreak(false);
#if wxUSE_GIF && wxUSE_TIMER
m_gifDecoder = NULL;
m_gifTimer = NULL;
m_physX = m_physY = wxDefaultCoord;
m_nCurrFrame = 0;
#endif
if ( m_bmpW && m_bmpH )
{
if ( input )
{
wxInputStream *s = input->GetStream();
if ( s )
{
#if wxUSE_GIF && wxUSE_TIMER
bool readImg = true;
if ( m_windowIface &&
(input->GetLocation().Matches(wxT("*.gif")) ||
input->GetLocation().Matches(wxT("*.GIF"))) )
{
m_gifDecoder = new wxGIFDecoder();
if ( m_gifDecoder->LoadGIF(*s) == wxGIF_OK )
{
wxImage img;
if ( m_gifDecoder->ConvertToImage(0, &img) )
SetImage(img);
readImg = false;
if ( m_gifDecoder->IsAnimation() )
{
m_gifTimer = new wxGIFTimer(this);
long delay = m_gifDecoder->GetDelay(0);
if ( delay == 0 )
delay = 1;
m_gifTimer->Start(delay, true);
}
else
{
wxDELETE(m_gifDecoder);
}
}
else
{
wxDELETE(m_gifDecoder);
}
}
if ( readImg )
#endif // wxUSE_GIF && wxUSE_TIMER
{
wxImage image(*s, wxBITMAP_TYPE_ANY);
if ( image.Ok() )
SetImage(image);
}
}
}
else // input==NULL, use "broken image" bitmap
{
if ( m_bmpW == wxDefaultCoord && m_bmpH == wxDefaultCoord )
{
m_bmpW = 29;
m_bmpH = 31;
}
else
{
m_showFrame = true;
if ( m_bmpW == wxDefaultCoord ) m_bmpW = 31;
if ( m_bmpH == wxDefaultCoord ) m_bmpH = 33;
}
m_bitmap =
new wxBitmap(wxArtProvider::GetBitmap(wxART_MISSING_IMAGE));
}
}
//else: ignore the 0-sized images used sometimes on the Web pages
m_Width = (int)(scale * (double)m_bmpW);
m_Height = (int)(scale * (double)m_bmpH);
switch (align)
{
case wxHTML_ALIGN_TOP :
m_Descent = m_Height;
break;
case wxHTML_ALIGN_CENTER :
m_Descent = m_Height / 2;
break;
case wxHTML_ALIGN_BOTTOM :
default :
m_Descent = 0;
break;
}
}
void wxHtmlImageCell::SetImage(const wxImage& img)
{
#if !defined(__WXMSW__) || wxUSE_WXDIB
if ( img.Ok() )
{
delete m_bitmap;
int ww, hh;
ww = img.GetWidth();
hh = img.GetHeight();
if ( m_bmpW == wxDefaultCoord )
m_bmpW = ww;
if ( m_bmpH == wxDefaultCoord )
m_bmpH = hh;
// Only scale the bitmap at the rendering stage,
// so we don't lose quality twice
/*
if ((m_bmpW != ww) || (m_bmpH != hh))
{
wxImage img2 = img.Scale(m_bmpW, m_bmpH);
m_bitmap = new wxBitmap(img2);
}
else
*/
m_bitmap = new wxBitmap(img);
}
#endif
}
#if wxUSE_GIF && wxUSE_TIMER
void wxHtmlImageCell::AdvanceAnimation(wxTimer *timer)
{
wxImage img;
// advance current frame
m_nCurrFrame++;
if (m_nCurrFrame == m_gifDecoder->GetFrameCount())
m_nCurrFrame = 0;
if ( m_physX == wxDefaultCoord )
{
m_physX = m_physY = 0;
for (wxHtmlCell *cell = this; cell; cell = cell->GetParent())
{
m_physX += cell->GetPosX();
m_physY += cell->GetPosY();
}
}
wxWindow *win = m_windowIface->GetHTMLWindow();
wxPoint pos =
m_windowIface->HTMLCoordsToWindow(this, wxPoint(m_physX, m_physY));
wxRect rect(pos, wxSize(m_Width, m_Height));
if ( win->GetClientRect().Intersects(rect) &&
m_gifDecoder->ConvertToImage(m_nCurrFrame, &img) )
{
#if !defined(__WXMSW__) || wxUSE_WXDIB
if ( m_gifDecoder->GetFrameSize(m_nCurrFrame) != wxSize(m_Width, m_Height) ||
m_gifDecoder->GetFramePosition(m_nCurrFrame) != wxPoint(0, 0) )
{
wxBitmap bmp(img);
wxMemoryDC dc;
dc.SelectObject(*m_bitmap);
dc.DrawBitmap(bmp, m_gifDecoder->GetFramePosition(m_nCurrFrame),
true /* use mask */);
}
else
#endif
SetImage(img);
win->Refresh(img.HasMask(), &rect);
}
long delay = m_gifDecoder->GetDelay(m_nCurrFrame);
if ( delay == 0 )
delay = 1;
timer->Start(delay, true);
}
void wxHtmlImageCell::Layout(int w)
{
wxHtmlCell::Layout(w);
m_physX = m_physY = wxDefaultCoord;
}
#endif
wxHtmlImageCell::~wxHtmlImageCell()
{
delete m_bitmap;
#if wxUSE_GIF && wxUSE_TIMER
delete m_gifTimer;
delete m_gifDecoder;
#endif
}
void wxHtmlImageCell::Draw(wxDC& dc, int x, int y,
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info))
{
if ( m_showFrame )
{
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.DrawRectangle(x + m_PosX, y + m_PosY, m_Width, m_Height);
x++, y++;
}
if ( m_bitmap )
{
// We add in the scaling from the desired bitmap width
// and height, so we only do the scaling once.
double imageScaleX = 1.0;
double imageScaleY = 1.0;
if (m_bmpW != m_bitmap->GetWidth())
imageScaleX = (double) m_bmpW / (double) m_bitmap->GetWidth();
if (m_bmpH != m_bitmap->GetHeight())
imageScaleY = (double) m_bmpH / (double) m_bitmap->GetHeight();
double us_x, us_y;
dc.GetUserScale(&us_x, &us_y);
dc.SetUserScale(us_x * m_scale * imageScaleX, us_y * m_scale * imageScaleY);
dc.DrawBitmap(*m_bitmap, (int) ((x + m_PosX) / (m_scale*imageScaleX)),
(int) ((y + m_PosY) / (m_scale*imageScaleY)), true);
dc.SetUserScale(us_x, us_y);
}
}
wxHtmlLinkInfo *wxHtmlImageCell::GetLink( int x, int y ) const
{
if (m_mapName.empty())
return wxHtmlCell::GetLink( x, y );
if (!m_imageMap)
{
wxHtmlContainerCell *p, *op;
op = p = GetParent();
while (p)
{
op = p;
p = p->GetParent();
}
p = op;
wxHtmlCell *cell = (wxHtmlCell*)p->Find(wxHTML_COND_ISIMAGEMAP,
(const void*)(&m_mapName));
if (!cell)
{
((wxString&)m_mapName).Clear();
return wxHtmlCell::GetLink( x, y );
}
{ // dirty hack, ask Joel why he fills m_ImageMap in this place
// THE problem is that we're in const method and we can't modify m_ImageMap
wxHtmlImageMapCell **cx = (wxHtmlImageMapCell**)(&m_imageMap);
*cx = (wxHtmlImageMapCell*)cell;
}
}
return m_imageMap->GetLink(x, y);
}
//--------------------------------------------------------------------------------
// tag handler
//--------------------------------------------------------------------------------
TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
TAG_HANDLER_CONSTR(IMG) { }
TAG_HANDLER_PROC(tag)
{
if (tag.GetName() == wxT("IMG"))
{
if (tag.HasParam(wxT("SRC")))
{
int w = wxDefaultCoord, h = wxDefaultCoord;
int al;
wxFSFile *str;
wxString tmp = tag.GetParam(wxT("SRC"));
wxString mn = wxEmptyString;
str = m_WParser->OpenURL(wxHTML_URL_IMAGE, tmp);
if (tag.HasParam(wxT("WIDTH")))
tag.GetParamAsInt(wxT("WIDTH"), &w);
if (tag.HasParam(wxT("HEIGHT")))
tag.GetParamAsInt(wxT("HEIGHT"), &h);
al = wxHTML_ALIGN_BOTTOM;
if (tag.HasParam(wxT("ALIGN")))
{
wxString alstr = tag.GetParam(wxT("ALIGN"));
alstr.MakeUpper(); // for the case alignment was in ".."
if (alstr == wxT("TEXTTOP"))
al = wxHTML_ALIGN_TOP;
else if ((alstr == wxT("CENTER")) || (alstr == wxT("ABSCENTER")))
al = wxHTML_ALIGN_CENTER;
}
if (tag.HasParam(wxT("USEMAP")))
{
mn = tag.GetParam( wxT("USEMAP") );
if (mn.GetChar(0) == wxT('#'))
{
mn = mn.Mid( 1 );
}
}
wxHtmlImageCell *cel = new wxHtmlImageCell(
m_WParser->GetWindowInterface(),
str, w, h,
m_WParser->GetPixelScale(),
al, mn);
m_WParser->ApplyStateToCell(cel);
cel->SetId(tag.GetParam(wxT("id"))); // may be empty
m_WParser->GetContainer()->InsertCell(cel);
if (str)
delete str;
}
}
if (tag.GetName() == wxT("MAP"))
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
if (tag.HasParam(wxT("NAME")))
{
wxString tmp = tag.GetParam(wxT("NAME"));
wxHtmlImageMapCell *cel = new wxHtmlImageMapCell( tmp );
m_WParser->GetContainer()->InsertCell( cel );
}
ParseInner( tag );
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
if (tag.GetName() == wxT("AREA"))
{
if (tag.HasParam(wxT("SHAPE")))
{
wxString tmp = tag.GetParam(wxT("SHAPE"));
wxString coords = wxEmptyString;
tmp.MakeUpper();
wxHtmlImageMapAreaCell *cel = NULL;
if (tag.HasParam(wxT("COORDS")))
{
coords = tag.GetParam(wxT("COORDS"));
}
if (tmp == wxT("POLY"))
{
cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY, coords, m_WParser->GetPixelScale() );
}
else if (tmp == wxT("CIRCLE"))
{
cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE, coords, m_WParser->GetPixelScale() );
}
else if (tmp == wxT("RECT"))
{
cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT, coords, m_WParser->GetPixelScale() );
}
if (cel != NULL && tag.HasParam(wxT("HREF")))
{
wxString target;
if (tag.HasParam(wxT("TARGET")))
target = tag.GetParam(wxT("TARGET"));
cel->SetLink(wxHtmlLinkInfo(tag.GetParam(wxT("HREF")), target));
}
if (cel != NULL)
m_WParser->GetContainer()->InsertCell( cel );
}
}
return false;
}
TAG_HANDLER_END(IMG)
TAGS_MODULE_BEGIN(Image)
TAGS_MODULE_ADD(IMG)
TAGS_MODULE_END(Image)
#endif

View file

@ -0,0 +1,474 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_layout.cpp
// Purpose: wxHtml module for basic paragraphs/layout handling
// Author: Vaclav Slavik
// RCS-ID: $Id: m_layout.cpp 55881 2008-09-25 17:19:30Z VS $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/image.h"
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlwin.h"
FORCE_LINK_ME(m_layout)
#ifdef __WXWINCE__
#include "wx/msw/wince/missing.h" // for bsearch()
#else
#include <stdlib.h> // bsearch()
#endif
//-----------------------------------------------------------------------------
// wxHtmlPageBreakCell
//-----------------------------------------------------------------------------
// Since html isn't a page-layout language, it doesn't support page
// page breaks directly--that requires CSS2 support. But a page-break
// facility is handy, and has been requested more than once on the
// mailing lists. This wxHtml tag handler implements just enough of
// CSS2 to support a page break by recognizing only
// <div style="page-break-before:always">
//
// wxHtml maintains page breaks in wxHtmlPrintout::m_PageBreaks. The
// tag handler below adds appropriate offsets to that array member.
// wxHtmlDCRenderer::Render() accesses that array and makes a new page
// begin after each page-break tag.
// The page-break handler does all its work in AdjustPagebreak(). For
// all tag handlers, that function adjusts the page-break position.
// For other tags, it determines whether the html element can fit on
// the remainder of the page; if it cannot fit, but must not be split,
// then the function moves the page break provided in the argument up,
// and returns 'true' to inform the caller that the argument was
// modified.
//
// Due to its special purpose, the page-break facility differs from
// other tags. It takes up no space, but it behaves as though there is
// never enough room to fit it on the remainder of the page--it always
// forces a page break. Therefore, unlike other elements that trigger
// a page break, it would never 'fit' on the following page either.
// Therefore it's necessary to compare each pagebreak candidate to the
// array wxHtmlPrintout::m_PageBreaks of pagebreaks already set, and
// set a new one only if it's not in that array.
class wxHtmlPageBreakCell : public wxHtmlCell
{
public:
wxHtmlPageBreakCell() {}
bool AdjustPagebreak(int* pagebreak,
wxArrayInt& known_pagebreaks) const;
void Draw(wxDC& WXUNUSED(dc),
int WXUNUSED(x), int WXUNUSED(y),
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info)) {}
private:
DECLARE_NO_COPY_CLASS(wxHtmlPageBreakCell)
};
// Comparison routine for bsearch into an int* array of pagebreaks.
extern "C" int wxCMPFUNC_CONV wxInteger_compare(void const* i0, void const* i1)
{
return *(int*)i0 - *(int*)i1;
}
bool wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak, wxArrayInt& known_pagebreaks) const
{
// When we are counting pages, 'known_pagebreaks' is non-NULL.
// That's the only time we change 'pagebreak'. Otherwise, pages
// were already counted, 'known_pagebreaks' is NULL, and we don't
// do anything except return false.
//
// We also simply return false if the 'pagebreak' argument is
// less than (vertically above) or the same as the current
// vertical position. Otherwise we'd be setting a pagebreak above
// the current cell, which is incorrect, or duplicating a
// pagebreak that has already been set.
if( known_pagebreaks.Count() == 0 || *pagebreak <= m_PosY)
{
return false;
}
// m_PosY is only the vertical offset from the parent. The pagebreak
// required here is the total page offset, so m_PosY must be added
// to the parent's offset and height.
int total_height = m_PosY;
for ( wxHtmlCell *parent = GetParent(); parent; parent = parent->GetParent() )
{
total_height += parent->GetPosY();
}
// Search the array of pagebreaks to see whether we've already set
// a pagebreak here. The standard bsearch() function is appropriate
// because the array of pagebreaks through known_pagebreaks[number_of_pages]
// is known to be sorted in strictly increasing order. '1 + number_of_pages'
// is used as a bsearch() argument because the array contains a leading
// zero plus one element for each page.
int where = known_pagebreaks.Index( total_height);
// Add a pagebreak only if there isn't one already set here.
if( wxNOT_FOUND != where)
{
return false;
}
else
{
*pagebreak = m_PosY;
return true;
}
}
TAG_HANDLER_BEGIN(P, "P")
TAG_HANDLER_CONSTR(P) { }
TAG_HANDLER_PROC(tag)
{
if (m_WParser->GetContainer()->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
m_WParser->GetContainer()->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
m_WParser->GetContainer()->SetAlign(tag);
return false;
}
TAG_HANDLER_END(P)
TAG_HANDLER_BEGIN(BR, "BR")
TAG_HANDLER_CONSTR(BR) { }
TAG_HANDLER_PROC(tag)
{
int al = m_WParser->GetContainer()->GetAlignHor();
wxHtmlContainerCell *c;
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
c->SetAlignHor(al);
c->SetAlign(tag);
c->SetMinHeight(m_WParser->GetCharHeight());
return false;
}
TAG_HANDLER_END(BR)
TAG_HANDLER_BEGIN(CENTER, "CENTER")
TAG_HANDLER_CONSTR(CENTER) { }
TAG_HANDLER_PROC(tag)
{
int old = m_WParser->GetAlign();
wxHtmlContainerCell *c = m_WParser->GetContainer();
m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
if (c->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
else
c->SetAlignHor(wxHTML_ALIGN_CENTER);
if (tag.HasEnding())
{
ParseInner(tag);
m_WParser->SetAlign(old);
if (c->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
else
c->SetAlignHor(old);
return true;
}
else return false;
}
TAG_HANDLER_END(CENTER)
TAG_HANDLER_BEGIN(DIV, "DIV")
TAG_HANDLER_CONSTR(DIV) { }
TAG_HANDLER_PROC(tag)
{
if(tag.HasParam(wxT("STYLE")))
{
if(tag.GetParam(wxT("STYLE")).IsSameAs(wxT("PAGE-BREAK-BEFORE:ALWAYS"), false))
{
m_WParser->CloseContainer();
m_WParser->OpenContainer()->InsertCell(new wxHtmlPageBreakCell);
m_WParser->CloseContainer();
m_WParser->OpenContainer();
return false;
}
else
{
// Treat other STYLE parameters here when they're supported.
return false;
}
}
else if(tag.HasParam(wxT("ALIGN")))
{
int old = m_WParser->GetAlign();
wxHtmlContainerCell *c = m_WParser->GetContainer();
if (c->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
c = m_WParser->GetContainer();
c->SetAlign(tag);
m_WParser->SetAlign(c->GetAlignHor());
}
else
{
c->SetAlign(tag);
m_WParser->SetAlign(c->GetAlignHor());
}
ParseInner(tag);
m_WParser->SetAlign(old);
if (c->GetFirstChild() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
else
c->SetAlignHor(old);
return true;
}
else
{
// Same as BR
int al = m_WParser->GetContainer()->GetAlignHor();
wxHtmlContainerCell *c;
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
c->SetAlignHor(al);
c->SetAlign(tag);
c->SetMinHeight(m_WParser->GetCharHeight());
return false;
}
}
TAG_HANDLER_END(DIV)
TAG_HANDLER_BEGIN(TITLE, "TITLE")
TAG_HANDLER_CONSTR(TITLE) { }
TAG_HANDLER_PROC(tag)
{
wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface();
if (winIface)
{
wxString title = m_WParser->GetSource()->Mid(
tag.GetBeginPos(),
tag.GetEndPos1()-tag.GetBeginPos());
#if !wxUSE_UNICODE && wxUSE_WCHAR_T
const wxFontEncoding enc = m_WParser->GetInputEncoding();
if ( enc != wxFONTENCODING_DEFAULT )
{
// need to convert to the current one
title = wxString(title.wc_str(wxCSConv(enc)), wxConvLocal);
}
#endif // !wxUSE_UNICODE
title = m_WParser->GetEntitiesParser()->Parse(title);
winIface->SetHTMLWindowTitle(title);
}
return true;
}
TAG_HANDLER_END(TITLE)
TAG_HANDLER_BEGIN(BODY, "BODY")
TAG_HANDLER_CONSTR(BODY) { }
TAG_HANDLER_PROC(tag)
{
wxColour clr;
if (tag.GetParamAsColour(wxT("TEXT"), &clr))
{
m_WParser->SetActualColor(clr);
m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(clr));
}
if (tag.GetParamAsColour(wxT("LINK"), &clr))
m_WParser->SetLinkColor(clr);
wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface();
// the rest of this function requires a window:
if ( !winIface )
return false;
if (tag.HasParam(wxT("BACKGROUND")))
{
wxFSFile *fileBgImage = m_WParser->OpenURL
(
wxHTML_URL_IMAGE,
tag.GetParam(wxT("BACKGROUND"))
);
if ( fileBgImage )
{
wxInputStream *is = fileBgImage->GetStream();
if ( is )
{
#if !defined(__WXMSW__) || wxUSE_WXDIB
wxImage image(*is);
if ( image.Ok() )
winIface->SetHTMLBackgroundImage(image);
#endif
}
delete fileBgImage;
}
}
if (tag.GetParamAsColour(wxT("BGCOLOR"), &clr))
{
m_WParser->GetContainer()->InsertCell(
new wxHtmlColourCell(clr, wxHTML_CLR_BACKGROUND));
winIface->SetHTMLBackgroundColour(clr);
}
return false;
}
TAG_HANDLER_END(BODY)
TAG_HANDLER_BEGIN(BLOCKQUOTE, "BLOCKQUOTE")
TAG_HANDLER_CONSTR(BLOCKQUOTE) { }
TAG_HANDLER_PROC(tag)
{
wxHtmlContainerCell *c;
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
if (c->GetAlignHor() == wxHTML_ALIGN_RIGHT)
c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_RIGHT);
else
c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT);
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
m_WParser->OpenContainer();
ParseInner(tag);
c = m_WParser->CloseContainer();
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_BOTTOM);
m_WParser->CloseContainer();
m_WParser->OpenContainer();
return true;
}
TAG_HANDLER_END(BLOCKQUOTE)
TAG_HANDLER_BEGIN(SUBSUP, "SUB,SUP")
TAG_HANDLER_PROC(tag)
{
bool issub = (tag.GetName() == wxT("SUB"));
wxHtmlScriptMode oldmode = m_WParser->GetScriptMode();
int oldbase = m_WParser->GetScriptBaseline();
int oldsize = m_WParser->GetFontSize();
wxHtmlContainerCell *cont = m_WParser->GetContainer();
wxHtmlCell *c = cont->GetLastChild();
m_WParser->SetScriptMode(issub ? wxHTML_SCRIPT_SUB : wxHTML_SCRIPT_SUP);
m_WParser->SetScriptBaseline(
oldbase + c ? c->GetScriptBaseline() : 0);
// select smaller font
m_WParser->SetFontSize(m_WParser->GetFontSize()-2);
cont->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
ParseInner(tag);
// restore font size
m_WParser->SetFontSize(oldsize);
m_WParser->GetContainer()->InsertCell(
new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
// restore base and alignment
m_WParser->SetScriptBaseline(oldbase);
m_WParser->SetScriptMode(oldmode);
return true;
}
TAG_HANDLER_END(SUBSUP)
// Tag handler for tags that we have to ignore, otherwise non-text data
// would show up as text:
TAG_HANDLER_BEGIN(DoNothing, "SCRIPT")
TAG_HANDLER_CONSTR(DoNothing) { }
TAG_HANDLER_PROC(WXUNUSED(tag))
{
return true;
}
TAG_HANDLER_END(DoNothing)
TAGS_MODULE_BEGIN(Layout)
TAGS_MODULE_ADD(P)
TAGS_MODULE_ADD(BR)
TAGS_MODULE_ADD(CENTER)
TAGS_MODULE_ADD(DIV)
TAGS_MODULE_ADD(TITLE)
TAGS_MODULE_ADD(BODY)
TAGS_MODULE_ADD(BLOCKQUOTE)
TAGS_MODULE_ADD(SUBSUP)
TAGS_MODULE_ADD(DoNothing)
TAGS_MODULE_END(Layout)
#endif

View file

@ -0,0 +1,107 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_links.cpp
// Purpose: wxHtml module for links & anchors
// Author: Vaclav Slavik
// RCS-ID: $Id: m_links.cpp 38788 2006-04-18 08:11:26Z ABX $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
FORCE_LINK_ME(m_links)
class wxHtmlAnchorCell : public wxHtmlCell
{
private:
wxString m_AnchorName;
public:
wxHtmlAnchorCell(const wxString& name) : wxHtmlCell()
{ m_AnchorName = name; }
void Draw(wxDC& WXUNUSED(dc),
int WXUNUSED(x), int WXUNUSED(y),
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info)) {}
virtual const wxHtmlCell* Find(int condition, const void* param) const
{
if ((condition == wxHTML_COND_ISANCHOR) &&
(m_AnchorName == (*((const wxString*)param))))
{
return this;
}
else
{
return wxHtmlCell::Find(condition, param);
}
}
DECLARE_NO_COPY_CLASS(wxHtmlAnchorCell)
};
TAG_HANDLER_BEGIN(A, "A")
TAG_HANDLER_CONSTR(A) { }
TAG_HANDLER_PROC(tag)
{
if (tag.HasParam( wxT("NAME") ))
{
m_WParser->GetContainer()->InsertCell(new wxHtmlAnchorCell(tag.GetParam( wxT("NAME") )));
}
if (tag.HasParam( wxT("HREF") ))
{
wxHtmlLinkInfo oldlnk = m_WParser->GetLink();
wxColour oldclr = m_WParser->GetActualColor();
int oldund = m_WParser->GetFontUnderlined();
wxString name(tag.GetParam( wxT("HREF") )), target;
if (tag.HasParam( wxT("TARGET") )) target = tag.GetParam( wxT("TARGET") );
m_WParser->SetActualColor(m_WParser->GetLinkColor());
m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(m_WParser->GetLinkColor()));
m_WParser->SetFontUnderlined(true);
m_WParser->GetContainer()->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
m_WParser->SetLink(wxHtmlLinkInfo(name, target));
ParseInner(tag);
m_WParser->SetLink(oldlnk);
m_WParser->SetFontUnderlined(oldund);
m_WParser->GetContainer()->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
m_WParser->SetActualColor(oldclr);
m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(oldclr));
return true;
}
else return false;
}
TAG_HANDLER_END(A)
TAGS_MODULE_BEGIN(Links)
TAGS_MODULE_ADD(A)
TAGS_MODULE_END(Links)
#endif

View file

@ -0,0 +1,307 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_list.cpp
// Purpose: wxHtml module for lists
// Author: Vaclav Slavik
// RCS-ID: $Id: m_list.cpp 38788 2006-04-18 08:11:26Z ABX $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/brush.h"
#include "wx/dc.h"
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlcell.h"
FORCE_LINK_ME(m_list)
//-----------------------------------------------------------------------------
// wxHtmlListmarkCell
//-----------------------------------------------------------------------------
class wxHtmlListmarkCell : public wxHtmlCell
{
private:
wxBrush m_Brush;
public:
wxHtmlListmarkCell(wxDC *dc, const wxColour& clr);
void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
wxHtmlRenderingInfo& info);
DECLARE_NO_COPY_CLASS(wxHtmlListmarkCell)
};
wxHtmlListmarkCell::wxHtmlListmarkCell(wxDC* dc, const wxColour& clr) : wxHtmlCell(), m_Brush(clr, wxSOLID)
{
m_Width = dc->GetCharHeight();
m_Height = dc->GetCharHeight();
// bottom of list mark is lined with bottom of letters in next cell
m_Descent = m_Height / 3;
}
void wxHtmlListmarkCell::Draw(wxDC& dc, int x, int y,
int WXUNUSED(view_y1), int WXUNUSED(view_y2),
wxHtmlRenderingInfo& WXUNUSED(info))
{
dc.SetBrush(m_Brush);
dc.DrawEllipse(x + m_PosX + m_Width / 3, y + m_PosY + m_Height / 3,
(m_Width / 3), (m_Width / 3));
}
//-----------------------------------------------------------------------------
// wxHtmlListCell
//-----------------------------------------------------------------------------
struct wxHtmlListItemStruct
{
wxHtmlContainerCell *mark;
wxHtmlContainerCell *cont;
int minWidth;
int maxWidth;
};
class wxHtmlListCell : public wxHtmlContainerCell
{
private:
wxBrush m_Brush;
int m_NumRows;
wxHtmlListItemStruct *m_RowInfo;
void ReallocRows(int rows);
void ComputeMinMaxWidths();
int ComputeMaxBase(wxHtmlCell *cell);
int m_ListmarkWidth;
public:
wxHtmlListCell(wxHtmlContainerCell *parent);
virtual ~wxHtmlListCell();
void AddRow(wxHtmlContainerCell *mark, wxHtmlContainerCell *cont);
virtual void Layout(int w);
DECLARE_NO_COPY_CLASS(wxHtmlListCell)
};
wxHtmlListCell::wxHtmlListCell(wxHtmlContainerCell *parent) : wxHtmlContainerCell(parent)
{
m_NumRows = 0;
m_RowInfo = 0;
m_ListmarkWidth = 0;
}
wxHtmlListCell::~wxHtmlListCell()
{
if (m_RowInfo) free(m_RowInfo);
}
int wxHtmlListCell::ComputeMaxBase(wxHtmlCell *cell)
{
if(!cell)
return 0;
wxHtmlCell *child = cell->GetFirstChild();
while(child)
{
int base = ComputeMaxBase( child );
if ( base > 0 ) return base + child->GetPosY();
child = child->GetNext();
}
return cell->GetHeight() - cell->GetDescent();
}
void wxHtmlListCell::Layout(int w)
{
wxHtmlCell::Layout(w);
ComputeMinMaxWidths();
m_Width = wxMax(m_Width, wxMin(w, GetMaxTotalWidth()));
int s_width = m_Width - m_IndentLeft;
int vpos = 0;
for (int r = 0; r < m_NumRows; r++)
{
// do layout first time to layout contents and adjust pos
m_RowInfo[r].mark->Layout(m_ListmarkWidth);
m_RowInfo[r].cont->Layout(s_width - m_ListmarkWidth);
const int base_mark = ComputeMaxBase( m_RowInfo[r].mark );
const int base_cont = ComputeMaxBase( m_RowInfo[r].cont );
const int adjust_mark = vpos + wxMax(base_cont-base_mark,0);
const int adjust_cont = vpos + wxMax(base_mark-base_cont,0);
m_RowInfo[r].mark->SetPos(m_IndentLeft, adjust_mark);
m_RowInfo[r].cont->SetPos(m_IndentLeft + m_ListmarkWidth, adjust_cont);
vpos = wxMax(adjust_mark + m_RowInfo[r].mark->GetHeight(),
adjust_cont + m_RowInfo[r].cont->GetHeight());
}
m_Height = vpos;
}
void wxHtmlListCell::AddRow(wxHtmlContainerCell *mark, wxHtmlContainerCell *cont)
{
ReallocRows(++m_NumRows);
m_RowInfo[m_NumRows - 1].mark = mark;
m_RowInfo[m_NumRows - 1].cont = cont;
}
void wxHtmlListCell::ReallocRows(int rows)
{
m_RowInfo = (wxHtmlListItemStruct*) realloc(m_RowInfo, sizeof(wxHtmlListItemStruct) * rows);
m_RowInfo[rows - 1].mark = NULL;
m_RowInfo[rows - 1].cont = NULL;
m_RowInfo[rows - 1].minWidth = 0;
m_RowInfo[rows - 1].maxWidth = 0;
m_NumRows = rows;
}
void wxHtmlListCell::ComputeMinMaxWidths()
{
if (m_NumRows == 0) return;
m_MaxTotalWidth = 0;
m_Width = 0;
for (int r = 0; r < m_NumRows; r++)
{
wxHtmlListItemStruct& row = m_RowInfo[r];
row.mark->Layout(1);
row.cont->Layout(1);
int maxWidth = row.cont->GetMaxTotalWidth();
int width = row.cont->GetWidth();
if (row.mark->GetWidth() > m_ListmarkWidth)
m_ListmarkWidth = row.mark->GetWidth();
if (maxWidth > m_MaxTotalWidth)
m_MaxTotalWidth = maxWidth;
if (width > m_Width)
m_Width = width;
}
m_Width += m_ListmarkWidth + m_IndentLeft;
m_MaxTotalWidth += m_ListmarkWidth + m_IndentLeft;
}
//-----------------------------------------------------------------------------
// wxHtmlListcontentCell
//-----------------------------------------------------------------------------
class wxHtmlListcontentCell : public wxHtmlContainerCell
{
public:
wxHtmlListcontentCell(wxHtmlContainerCell *p) : wxHtmlContainerCell(p) {}
virtual void Layout(int w) {
// Reset top indentation, fixes <li><p>
SetIndent(0, wxHTML_INDENT_TOP);
wxHtmlContainerCell::Layout(w);
}
};
//-----------------------------------------------------------------------------
// The list handler:
//-----------------------------------------------------------------------------
TAG_HANDLER_BEGIN(OLULLI, "OL,UL,LI")
TAG_HANDLER_VARS
wxHtmlListCell *m_List;
int m_Numbering;
// this is number of actual item of list or 0 for dots
TAG_HANDLER_CONSTR(OLULLI)
{
m_List = NULL;
m_Numbering = 0;
}
TAG_HANDLER_PROC(tag)
{
wxHtmlContainerCell *c;
// List Item:
if (m_List && tag.GetName() == wxT("LI"))
{
c = m_WParser->SetContainer(new wxHtmlContainerCell(m_List));
c->SetAlignVer(wxHTML_ALIGN_TOP);
wxHtmlContainerCell *mark = c;
c->SetWidthFloat(2 * m_WParser->GetCharWidth(), wxHTML_UNITS_PIXELS);
if (m_Numbering == 0)
{
// Centering gives more space after the bullet
c->SetAlignHor(wxHTML_ALIGN_CENTER);
c->InsertCell(new wxHtmlListmarkCell(m_WParser->GetDC(), m_WParser->GetActualColor()));
}
else
{
c->SetAlignHor(wxHTML_ALIGN_RIGHT);
wxString markStr;
markStr.Printf(wxT("%i. "), m_Numbering);
c->InsertCell(new wxHtmlWordCell(markStr, *(m_WParser->GetDC())));
}
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
m_List->AddRow(mark, c);
c = m_WParser->OpenContainer();
m_WParser->SetContainer(new wxHtmlListcontentCell(c));
if (m_Numbering != 0) m_Numbering++;
}
// Begin of List (not-numbered): "UL", "OL"
else if (tag.GetName() == wxT("UL") || tag.GetName() == wxT("OL"))
{
int oldnum = m_Numbering;
if (tag.GetName() == wxT("UL")) m_Numbering = 0;
else m_Numbering = 1;
wxHtmlContainerCell *oldcont;
oldcont = c = m_WParser->OpenContainer();
wxHtmlListCell *oldList = m_List;
m_List = new wxHtmlListCell(c);
m_List->SetIndent(2 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT);
ParseInner(tag);
m_WParser->SetContainer(oldcont);
m_WParser->CloseContainer();
m_Numbering = oldnum;
m_List = oldList;
return true;
}
return false;
}
TAG_HANDLER_END(OLULLI)
TAGS_MODULE_BEGIN(List)
TAGS_MODULE_ADD(OLULLI)
TAGS_MODULE_END(List)
#endif

View file

@ -0,0 +1,144 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_pre.cpp
// Purpose: wxHtml module for <PRE> ... </PRE> tag (code citation)
// Author: Vaclav Slavik
// RCS-ID: $Id: m_pre.cpp 56547 2008-10-28 10:06:32Z VS $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlcell.h"
#include "wx/tokenzr.h"
#include "wx/encconv.h"
FORCE_LINK_ME(m_pre)
// replaces '\t', ' ' and '\n' with HTML markup:
static wxString LINKAGEMODE HtmlizeLinebreaks(const wxString& str)
{
wxString out;
out.reserve(str.length()); // we'll certainly need at least that
size_t len = str.Len();
for (size_t i = 0; i < len; i++)
{
switch (str[i])
{
case wxT('<'):
while (i < len && str[i] != wxT('>'))
{
out << str[i++];
}
out << wxT('>');
break;
// We need to translate any line break into exactly one <br>.
// Quoting HTML spec: "A line break is defined to be a carriage
// return (&#x000D;), a line feed (&#x000A;), or a carriage
// return/line feed pair."
case wxT('\r'):
{
size_t j = i + 1;
if ( j < len && str[j] == wxT('\n') )
i = j;
}
// fall through
case wxT('\n'):
out << wxT("<br>");
break;
default:
out << str[i];
break;
}
}
return out;
}
//-----------------------------------------------------------------------------
// The list handler:
//-----------------------------------------------------------------------------
TAG_HANDLER_BEGIN(PRE, "PRE")
TAG_HANDLER_CONSTR(PRE) { }
TAG_HANDLER_PROC(tag)
{
wxHtmlContainerCell *c;
const int fixed = m_WParser->GetFontFixed();
const int italic = m_WParser->GetFontItalic();
const int underlined = m_WParser->GetFontUnderlined();
const int bold = m_WParser->GetFontBold();
const int fsize = m_WParser->GetFontSize();
const wxHtmlWinParser::WhitespaceMode whitespace =
m_WParser->GetWhitespaceMode();
c = m_WParser->GetContainer();
m_WParser->SetWhitespaceMode(wxHtmlWinParser::Whitespace_Pre);
m_WParser->SetFontUnderlined(false);
m_WParser->SetFontBold(false);
m_WParser->SetFontItalic(false);
m_WParser->SetFontFixed(true);
m_WParser->SetFontSize(3);
c->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
c->SetWidthFloat(tag);
c = m_WParser->OpenContainer();
c->SetAlignHor(wxHTML_ALIGN_LEFT);
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
wxString srcMid = m_WParser->GetInnerSource(tag);
// setting Whitespace_Pre mode takes care of spaces and TABs, but
// not linebreaks, so we have to translate them into <br> by
// calling HtmlizeLinebreaks() here
ParseInnerSource(HtmlizeLinebreaks(srcMid));
m_WParser->CloseContainer();
m_WParser->CloseContainer();
c = m_WParser->OpenContainer();
m_WParser->SetWhitespaceMode(whitespace);
m_WParser->SetFontUnderlined(underlined);
m_WParser->SetFontBold(bold);
m_WParser->SetFontItalic(italic);
m_WParser->SetFontFixed(fixed);
m_WParser->SetFontSize(fsize);
c->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
return true;
}
TAG_HANDLER_END(PRE)
TAGS_MODULE_BEGIN(Pre)
TAGS_MODULE_ADD(PRE)
TAGS_MODULE_END(Pre)
#endif

View file

@ -0,0 +1,46 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_style.cpp
// Purpose: wxHtml module for parsing <style> tag
// Author: Vaclav Slavik
// RCS-ID: $Id: m_style.cpp 38788 2006-04-18 08:11:26Z ABX $
// Copyright: (c) 2002 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
FORCE_LINK_ME(m_style)
TAG_HANDLER_BEGIN(STYLE, "STYLE")
TAG_HANDLER_CONSTR(STYLE) { }
TAG_HANDLER_PROC(WXUNUSED(tag))
{
// VS: Ignore styles for now. We must have this handler present,
// because CSS style text would be rendered verbatim otherwise
return true;
}
TAG_HANDLER_END(STYLE)
TAGS_MODULE_BEGIN(StyleTag)
TAGS_MODULE_ADD(STYLE)
TAGS_MODULE_END(StyleTag)
#endif

View file

@ -0,0 +1,799 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/m_tables.cpp
// Purpose: wxHtml module for tables
// Author: Vaclav Slavik
// RCS-ID: $Id: m_tables.cpp 59687 2009-03-21 09:41:09Z VS $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#endif
#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlcell.h"
FORCE_LINK_ME(m_tables)
#define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
#define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
//-----------------------------------------------------------------------------
// wxHtmlTableCell
//-----------------------------------------------------------------------------
struct colStruct
{
int width, units;
// width of the column either in pixels or percents
// ('width' is the number, 'units' determines its meaning)
int minWidth, maxWidth;
// minimal/maximal column width. This is needed by HTML 4.0
// layouting algorithm and can be determined by trying to
// layout table cells with width=1 and width=infinity
int leftpos, pixwidth, maxrealwidth;
// temporary (depends on actual width of table)
};
enum cellState
{
cellSpan,
cellUsed,
cellFree
};
struct cellStruct
{
wxHtmlContainerCell *cont;
int colspan, rowspan;
int minheight, valign;
cellState flag;
bool nowrap;
};
class wxHtmlTableCell : public wxHtmlContainerCell
{
protected:
/* These are real attributes: */
// should we draw borders or not?
bool m_HasBorders;
// number of columns; rows
int m_NumCols, m_NumRows;
// array of column information
colStruct *m_ColsInfo;
// 2D array of all cells in the table : m_CellInfo[row][column]
cellStruct **m_CellInfo;
// spaces between cells
int m_Spacing;
// cells internal indentation
int m_Padding;
private:
/* ...and these are valid only when parsing the table: */
// number of actual column (ranging from 0..m_NumCols)
int m_ActualCol, m_ActualRow;
// default values (for table and row):
wxColour m_tBkg, m_rBkg;
wxString m_tValign, m_rValign;
double m_PixelScale;
public:
wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale = 1.0);
virtual ~wxHtmlTableCell();
virtual void RemoveExtraSpacing(bool top, bool bottom);
virtual void Layout(int w);
void AddRow(const wxHtmlTag& tag);
void AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag);
private:
// Reallocates memory to given number of cols/rows
// and changes m_NumCols/m_NumRows value to reflect this change
// NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!!
void ReallocCols(int cols);
void ReallocRows(int rows);
// Computes minimal and maximal widths of columns. Needs to be called
// only once, before first Layout().
void ComputeMinMaxWidths();
DECLARE_NO_COPY_CLASS(wxHtmlTableCell)
};
wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale)
: wxHtmlContainerCell(parent)
{
m_PixelScale = pixel_scale;
m_HasBorders =
(tag.HasParam(wxT("BORDER")) && tag.GetParam(wxT("BORDER")) != wxT("0"));
m_ColsInfo = NULL;
m_NumCols = m_NumRows = 0;
m_CellInfo = NULL;
m_ActualCol = m_ActualRow = -1;
/* scan params: */
if (tag.HasParam(wxT("BGCOLOR")))
{
tag.GetParamAsColour(wxT("BGCOLOR"), &m_tBkg);
if (m_tBkg.Ok())
SetBackgroundColour(m_tBkg);
}
if (tag.HasParam(wxT("VALIGN")))
m_tValign = tag.GetParam(wxT("VALIGN"));
else
m_tValign = wxEmptyString;
if (!tag.GetParamAsInt(wxT("CELLSPACING"), &m_Spacing))
m_Spacing = 2;
if (!tag.GetParamAsInt(wxT("CELLPADDING"), &m_Padding))
m_Padding = 3;
m_Spacing = (int)(m_PixelScale * (double)m_Spacing);
m_Padding = (int)(m_PixelScale * (double)m_Padding);
if (m_HasBorders)
SetBorder(TABLE_BORDER_CLR_1, TABLE_BORDER_CLR_2);
}
wxHtmlTableCell::~wxHtmlTableCell()
{
if (m_ColsInfo) free(m_ColsInfo);
if (m_CellInfo)
{
for (int i = 0; i < m_NumRows; i++)
free(m_CellInfo[i]);
free(m_CellInfo);
}
}
void wxHtmlTableCell::RemoveExtraSpacing(bool WXUNUSED(top),
bool WXUNUSED(bottom))
{
// Don't remove any spacing in the table -- it's always desirable,
// because it's part of table's definition.
// (If wxHtmlContainerCell::RemoveExtraSpacing() was applied to tables,
// then upper left cell of a table would be positioned above other cells
// if the table was the first element on the page.)
}
void wxHtmlTableCell::ReallocCols(int cols)
{
int i,j;
for (i = 0; i < m_NumRows; i++)
{
m_CellInfo[i] = (cellStruct*) realloc(m_CellInfo[i], sizeof(cellStruct) * cols);
for (j = m_NumCols; j < cols; j++)
m_CellInfo[i][j].flag = cellFree;
}
m_ColsInfo = (colStruct*) realloc(m_ColsInfo, sizeof(colStruct) * cols);
for (j = m_NumCols; j < cols; j++)
{
m_ColsInfo[j].width = 0;
m_ColsInfo[j].units = wxHTML_UNITS_PERCENT;
m_ColsInfo[j].minWidth = m_ColsInfo[j].maxWidth = -1;
}
m_NumCols = cols;
}
void wxHtmlTableCell::ReallocRows(int rows)
{
m_CellInfo = (cellStruct**) realloc(m_CellInfo, sizeof(cellStruct*) * rows);
for (int row = m_NumRows; row < rows ; row++)
{
if (m_NumCols == 0)
m_CellInfo[row] = NULL;
else
{
m_CellInfo[row] = (cellStruct*) malloc(sizeof(cellStruct) * m_NumCols);
for (int col = 0; col < m_NumCols; col++)
m_CellInfo[row][col].flag = cellFree;
}
}
m_NumRows = rows;
}
void wxHtmlTableCell::AddRow(const wxHtmlTag& tag)
{
m_ActualCol = -1;
// VS: real allocation of row entry is done in AddCell in order
// to correctly handle empty rows (i.e. "<tr></tr>")
// m_ActualCol == -1 indicates that AddCell has to allocate new row.
// scan params:
m_rBkg = m_tBkg;
if (tag.HasParam(wxT("BGCOLOR")))
tag.GetParamAsColour(wxT("BGCOLOR"), &m_rBkg);
if (tag.HasParam(wxT("VALIGN")))
m_rValign = tag.GetParam(wxT("VALIGN"));
else
m_rValign = m_tValign;
}
void wxHtmlTableCell::AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag)
{
// Is this cell in new row?
// VS: we can't do it in AddRow, see my comment there
if (m_ActualCol == -1)
{
if (m_ActualRow + 1 > m_NumRows - 1)
ReallocRows(m_ActualRow + 2);
m_ActualRow++;
}
// cells & columns:
do
{
m_ActualCol++;
} while ((m_ActualCol < m_NumCols) &&
(m_CellInfo[m_ActualRow][m_ActualCol].flag != cellFree));
if (m_ActualCol > m_NumCols - 1)
ReallocCols(m_ActualCol + 1);
int r = m_ActualRow, c = m_ActualCol;
m_CellInfo[r][c].cont = cell;
m_CellInfo[r][c].colspan = 1;
m_CellInfo[r][c].rowspan = 1;
m_CellInfo[r][c].flag = cellUsed;
m_CellInfo[r][c].minheight = 0;
m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
/* scan for parameters: */
// width:
{
if (tag.HasParam(wxT("WIDTH")))
{
wxString wd = tag.GetParam(wxT("WIDTH"));
if (wd[wd.length()-1] == wxT('%'))
{
if ( wxSscanf(wd.c_str(), wxT("%i%%"), &m_ColsInfo[c].width) == 1 )
{
m_ColsInfo[c].units = wxHTML_UNITS_PERCENT;
}
}
else
{
long width;
if ( wd.ToLong(&width) )
{
m_ColsInfo[c].width = (int)(m_PixelScale * (double)width);
m_ColsInfo[c].units = wxHTML_UNITS_PIXELS;
}
}
}
}
// spanning:
{
tag.GetParamAsInt(wxT("COLSPAN"), &m_CellInfo[r][c].colspan);
tag.GetParamAsInt(wxT("ROWSPAN"), &m_CellInfo[r][c].rowspan);
// VS: the standard says this about col/rowspan:
// "This attribute specifies the number of rows spanned by the
// current cell. The default value of this attribute is one ("1").
// The value zero ("0") means that the cell spans all rows from the
// current row to the last row of the table." All mainstream
// browsers act as if 0==1, though, and so does wxHTML.
if (m_CellInfo[r][c].colspan < 1)
m_CellInfo[r][c].colspan = 1;
if (m_CellInfo[r][c].rowspan < 1)
m_CellInfo[r][c].rowspan = 1;
if ((m_CellInfo[r][c].colspan > 1) || (m_CellInfo[r][c].rowspan > 1))
{
int i, j;
if (r + m_CellInfo[r][c].rowspan > m_NumRows)
ReallocRows(r + m_CellInfo[r][c].rowspan);
if (c + m_CellInfo[r][c].colspan > m_NumCols)
ReallocCols(c + m_CellInfo[r][c].colspan);
for (i = r; i < r + m_CellInfo[r][c].rowspan; i++)
for (j = c; j < c + m_CellInfo[r][c].colspan; j++)
m_CellInfo[i][j].flag = cellSpan;
m_CellInfo[r][c].flag = cellUsed;
}
}
//background color:
{
wxColour bk = m_rBkg;
if (tag.HasParam(wxT("BGCOLOR")))
tag.GetParamAsColour(wxT("BGCOLOR"), &bk);
if (bk.Ok())
cell->SetBackgroundColour(bk);
}
if (m_HasBorders)
cell->SetBorder(TABLE_BORDER_CLR_2, TABLE_BORDER_CLR_1);
// vertical alignment:
{
wxString valign;
if (tag.HasParam(wxT("VALIGN")))
valign = tag.GetParam(wxT("VALIGN"));
else
valign = m_tValign;
valign.MakeUpper();
if (valign == wxT("TOP"))
m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
else if (valign == wxT("BOTTOM"))
m_CellInfo[r][c].valign = wxHTML_ALIGN_BOTTOM;
else m_CellInfo[r][c].valign = wxHTML_ALIGN_CENTER;
}
// nowrap
if (tag.HasParam(wxT("NOWRAP")))
m_CellInfo[r][c].nowrap = true;
else
m_CellInfo[r][c].nowrap = false;
cell->SetIndent(m_Padding, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
}
void wxHtmlTableCell::ComputeMinMaxWidths()
{
if (m_NumCols == 0 || m_ColsInfo[0].minWidth != wxDefaultCoord) return;
m_MaxTotalWidth = 0;
int percentage = 0;
for (int c = 0; c < m_NumCols; c++)
{
for (int r = 0; r < m_NumRows; r++)
{
cellStruct& cell = m_CellInfo[r][c];
if (cell.flag == cellUsed)
{
cell.cont->Layout(2*m_Padding + 1);
int maxWidth = cell.cont->GetMaxTotalWidth();
int width = cell.nowrap?maxWidth:cell.cont->GetWidth();
width -= (cell.colspan-1) * m_Spacing;
maxWidth -= (cell.colspan-1) * m_Spacing;
// HTML 4.0 says it is acceptable to distribute min/max
width /= cell.colspan;
maxWidth /= cell.colspan;
for (int j = 0; j < cell.colspan; j++) {
if (width > m_ColsInfo[c+j].minWidth)
m_ColsInfo[c+j].minWidth = width;
if (maxWidth > m_ColsInfo[c+j].maxWidth)
m_ColsInfo[c+j].maxWidth = maxWidth;
}
}
}
// Calculate maximum table width, required for nested tables
if (m_ColsInfo[c].units == wxHTML_UNITS_PIXELS)
m_MaxTotalWidth += wxMax(m_ColsInfo[c].width, m_ColsInfo[c].minWidth);
else if ((m_ColsInfo[c].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[c].width != 0))
percentage += m_ColsInfo[c].width;
else
m_MaxTotalWidth += m_ColsInfo[c].maxWidth;
}
if (percentage >= 100)
{
// Table would have infinite length
// Make it ridiculous large
m_MaxTotalWidth = 0xFFFFFF;
}
else
m_MaxTotalWidth = m_MaxTotalWidth * 100 / (100 - percentage);
m_MaxTotalWidth += (m_NumCols + 1) * m_Spacing;
}
void wxHtmlTableCell::Layout(int w)
{
ComputeMinMaxWidths();
wxHtmlCell::Layout(w);
/*
WIDTH ADJUSTING :
*/
if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
{
if (m_WidthFloat < 0)
{
if (m_WidthFloat < -100)
m_WidthFloat = -100;
m_Width = (100 + m_WidthFloat) * w / 100;
}
else
{
if (m_WidthFloat > 100)
m_WidthFloat = 100;
m_Width = m_WidthFloat * w / 100;
}
}
else
{
if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
else m_Width = m_WidthFloat;
}
/*
LAYOUTING :
*/
/* 1. setup columns widths:
The algorithm tries to keep the table size less than w if possible.
*/
{
int wpix = m_Width - (m_NumCols + 1) * m_Spacing;
int i, j;
// 1a. setup fixed-width columns:
for (i = 0; i < m_NumCols; i++)
if (m_ColsInfo[i].units == wxHTML_UNITS_PIXELS)
{
m_ColsInfo[i].pixwidth = wxMax(m_ColsInfo[i].width,
m_ColsInfo[i].minWidth);
wpix -= m_ColsInfo[i].pixwidth;
}
// 1b. Calculate maximum possible width if line wrapping would be disabled
// Recalculate total width if m_WidthFloat is zero to keep tables as small
// as possible.
int maxWidth = 0;
for (i = 0; i < m_NumCols; i++)
if (m_ColsInfo[i].width == 0)
{
maxWidth += m_ColsInfo[i].maxWidth;
}
if (!m_WidthFloat)
{
// Recalculate table width since no table width was initially given
int newWidth = m_Width - wpix + maxWidth;
// Make sure that floating-width columns will have the right size.
// Calculate sum of all floating-width columns
int percentage = 0;
for (i = 0; i < m_NumCols; i++)
if ((m_ColsInfo[i].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
percentage += m_ColsInfo[i].width;
if (percentage >= 100)
newWidth = w;
else
newWidth = newWidth * 100 / (100 - percentage);
newWidth = wxMin(newWidth, w - (m_NumCols + 1) * m_Spacing);
wpix -= m_Width - newWidth;
m_Width = newWidth;
}
// 1c. setup floating-width columns:
int wtemp = wpix;
for (i = 0; i < m_NumCols; i++)
if ((m_ColsInfo[i].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
{
m_ColsInfo[i].pixwidth = wxMin(m_ColsInfo[i].width, 100) * wpix / 100;
// Make sure to leave enough space for the other columns
int minRequired = 0;
for (j = 0; j < m_NumCols; j++)
{
if ((m_ColsInfo[j].units == wxHTML_UNITS_PERCENT && j > i) ||
!m_ColsInfo[j].width)
minRequired += m_ColsInfo[j].minWidth;
}
m_ColsInfo[i].pixwidth = wxMax(wxMin(wtemp - minRequired, m_ColsInfo[i].pixwidth), m_ColsInfo[i].minWidth);
wtemp -= m_ColsInfo[i].pixwidth;
}
wpix = wtemp;
// 1d. setup default columns (no width specification supplied):
// The algorithm assigns calculates the maximum possible width if line
// wrapping would be disabled and assigns column width as a fraction
// based upon the maximum width of a column
// FIXME: I'm not sure if this algorithm is conform to HTML standard,
// though it seems to be much better than the old one
for (i = j = 0; i < m_NumCols; i++)
if (m_ColsInfo[i].width == 0) j++;
if (wpix < 0)
wpix = 0;
// Assign widths
for (i = 0; i < m_NumCols; i++)
if (m_ColsInfo[i].width == 0)
{
// Assign with, make sure not to drop below minWidth
if (maxWidth)
m_ColsInfo[i].pixwidth = (int)(wpix * (m_ColsInfo[i].maxWidth / (float)maxWidth) + 0.5);
else
m_ColsInfo[i].pixwidth = wpix / j;
// Make sure to leave enough space for the other columns
int minRequired = 0;
int r;
for (r = i + 1; r < m_NumCols; r++)
{
if (!m_ColsInfo[r].width)
minRequired += m_ColsInfo[r].minWidth;
}
m_ColsInfo[i].pixwidth = wxMax(wxMin(wpix - minRequired, m_ColsInfo[i].pixwidth), m_ColsInfo[i].minWidth);
if (maxWidth)
{
if (m_ColsInfo[i].pixwidth > (wpix * (m_ColsInfo[i].maxWidth / (float)maxWidth) + 0.5))
{
int diff = (int)(m_ColsInfo[i].pixwidth - (wpix * m_ColsInfo[i].maxWidth / (float)maxWidth + 0.5));
maxWidth += diff - m_ColsInfo[i].maxWidth;
}
else
maxWidth -= m_ColsInfo[i].maxWidth;
}
wpix -= m_ColsInfo[i].pixwidth;
}
}
/* 2. compute positions of columns: */
{
int wpos = m_Spacing;
for (int i = 0; i < m_NumCols; i++)
{
m_ColsInfo[i].leftpos = wpos;
wpos += m_ColsInfo[i].pixwidth + m_Spacing;
}
// add the remaining space to the last column
if (m_NumCols > 0 && wpos < m_Width)
m_ColsInfo[m_NumCols-1].pixwidth += m_Width - wpos;
}
/* 3. sub-layout all cells: */
{
int *ypos = new int[m_NumRows + 1];
int actcol, actrow;
int fullwid;
wxHtmlContainerCell *actcell;
ypos[0] = m_Spacing;
for (actrow = 1; actrow <= m_NumRows; actrow++) ypos[actrow] = -1;
for (actrow = 0; actrow < m_NumRows; actrow++)
{
if (ypos[actrow] == -1) ypos[actrow] = ypos[actrow-1];
// 3a. sub-layout and detect max height:
for (actcol = 0; actcol < m_NumCols; actcol++) {
if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
actcell = m_CellInfo[actrow][actcol].cont;
fullwid = 0;
for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
fullwid += m_ColsInfo[i].pixwidth;
fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
actcell->SetMinHeight(m_CellInfo[actrow][actcol].minheight, m_CellInfo[actrow][actcol].valign);
actcell->Layout(fullwid);
if (ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing > ypos[actrow + m_CellInfo[actrow][actcol].rowspan])
ypos[actrow + m_CellInfo[actrow][actcol].rowspan] =
ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing;
}
}
for (actrow = 0; actrow < m_NumRows; actrow++)
{
// 3b. place cells in row & let'em all have same height:
for (actcol = 0; actcol < m_NumCols; actcol++)
{
if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
actcell = m_CellInfo[actrow][actcol].cont;
actcell->SetMinHeight(
ypos[actrow + m_CellInfo[actrow][actcol].rowspan] - ypos[actrow] - m_Spacing,
m_CellInfo[actrow][actcol].valign);
fullwid = 0;
for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
fullwid += m_ColsInfo[i].pixwidth;
fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
actcell->Layout(fullwid);
actcell->SetPos(m_ColsInfo[actcol].leftpos, ypos[actrow]);
}
}
m_Height = ypos[m_NumRows];
delete[] ypos;
}
/* 4. adjust table's width if it was too small: */
if (m_NumCols > 0)
{
int twidth = m_ColsInfo[m_NumCols-1].leftpos +
m_ColsInfo[m_NumCols-1].pixwidth + m_Spacing;
if (twidth > m_Width)
m_Width = twidth;
}
}
//-----------------------------------------------------------------------------
// The tables handler:
//-----------------------------------------------------------------------------
TAG_HANDLER_BEGIN(TABLE, "TABLE,TR,TD,TH")
TAG_HANDLER_VARS
wxHtmlTableCell* m_Table;
wxString m_tAlign, m_rAlign;
wxHtmlContainerCell *m_enclosingContainer;
TAG_HANDLER_CONSTR(TABLE)
{
m_Table = NULL;
m_enclosingContainer = NULL;
m_tAlign = m_rAlign = wxEmptyString;
}
TAG_HANDLER_PROC(tag)
{
wxHtmlContainerCell *c;
// new table started, backup upper-level table (if any) and create new:
if (tag.GetName() == wxT("TABLE"))
{
wxHtmlTableCell *oldt = m_Table;
wxHtmlContainerCell *oldEnclosing = m_enclosingContainer;
m_enclosingContainer = c = m_WParser->OpenContainer();
m_Table = new wxHtmlTableCell(c, tag, m_WParser->GetPixelScale());
// width:
{
if (tag.HasParam(wxT("WIDTH")))
{
wxString wd = tag.GetParam(wxT("WIDTH"));
if (wd[wd.length()-1] == wxT('%'))
{
int width = 0;
wxSscanf(wd.c_str(), wxT("%i%%"), &width);
m_Table->SetWidthFloat(width, wxHTML_UNITS_PERCENT);
}
else
{
int width = 0;
wxSscanf(wd.c_str(), wxT("%i"), &width);
m_Table->SetWidthFloat((int)(m_WParser->GetPixelScale() * width), wxHTML_UNITS_PIXELS);
}
}
else
m_Table->SetWidthFloat(0, wxHTML_UNITS_PIXELS);
}
int oldAlign = m_WParser->GetAlign();
m_tAlign = wxEmptyString;
if (tag.HasParam(wxT("ALIGN")))
m_tAlign = tag.GetParam(wxT("ALIGN"));
ParseInner(tag);
m_WParser->SetAlign(oldAlign);
m_WParser->SetContainer(m_enclosingContainer);
m_WParser->CloseContainer();
m_Table = oldt;
m_enclosingContainer = oldEnclosing;
return true; // ParseInner() called
}
else if (m_Table)
{
// new row in table
if (tag.GetName() == wxT("TR"))
{
m_Table->AddRow(tag);
m_rAlign = m_tAlign;
if (tag.HasParam(wxT("ALIGN")))
m_rAlign = tag.GetParam(wxT("ALIGN"));
}
// new cell
else
{
c = m_WParser->SetContainer(new wxHtmlContainerCell(m_Table));
m_Table->AddCell(c, tag);
m_WParser->OpenContainer();
if (tag.GetName() == wxT("TH")) /*header style*/
m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
else
m_WParser->SetAlign(wxHTML_ALIGN_LEFT);
wxString als;
als = m_rAlign;
if (tag.HasParam(wxT("ALIGN")))
als = tag.GetParam(wxT("ALIGN"));
als.MakeUpper();
if (als == wxT("RIGHT"))
m_WParser->SetAlign(wxHTML_ALIGN_RIGHT);
else if (als == wxT("LEFT"))
m_WParser->SetAlign(wxHTML_ALIGN_LEFT);
else if (als == wxT("CENTER"))
m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
m_WParser->OpenContainer();
ParseInner(tag);
// set the current container back to the enclosing one so that
// text outside of <th> and <td> isn't included in any cell
// (this happens often enough in practice because it's common
// to use whitespace between </td> and the next <td>):
m_WParser->SetContainer(m_enclosingContainer);
return true; // ParseInner() called
}
}
return false;
}
TAG_HANDLER_END(TABLE)
TAGS_MODULE_BEGIN(Tables)
TAGS_MODULE_ADD(TABLE)
TAGS_MODULE_END(Tables)
#endif

View file

@ -0,0 +1,853 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/html/winpars.cpp
// Purpose: wxHtmlParser class (generic parser)
// Author: Vaclav Slavik
// RCS-ID: $Id: winpars.cpp 58846 2009-02-12 19:38:20Z VS $
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WXPRECOMP
#include "wx/intl.h"
#include "wx/dc.h"
#include "wx/log.h"
#include "wx/settings.h"
#endif
#include "wx/html/htmldefs.h"
#include "wx/html/winpars.h"
#include "wx/html/htmlwin.h"
#include "wx/fontmap.h"
#include "wx/uri.h"
//-----------------------------------------------------------------------------
// wxHtmlWordWithTabsCell
//-----------------------------------------------------------------------------
// NB: this is backported from wx-2.9 and moved to this file so that it
// stays private; trunk version is in htmlcell.h/cpp.
// wxHtmlWordCell specialization for storing text fragments with embedded
// '\t's; these differ from normal words in that the displayed text is
// different from the text copied to clipboard
class WXDLLIMPEXP_HTML wxHtmlWordWithTabsCell : public wxHtmlWordCell
{
public:
wxHtmlWordWithTabsCell(const wxString& word,
const wxString& wordOrig,
size_t linepos,
const wxDC& dc)
: wxHtmlWordCell(word, dc),
m_wordOrig(wordOrig),
m_linepos(linepos)
{}
virtual wxString ConvertToText(wxHtmlSelection *sel) const;
protected:
wxString GetPartAsText(int begin, int end) const;
wxString m_wordOrig;
size_t m_linepos;
};
wxString wxHtmlWordWithTabsCell::ConvertToText(wxHtmlSelection *s) const
{
if ( s && (this == s->GetFromCell() || this == s->GetToCell()) )
{
wxPoint priv = this == s->GetFromCell() ? s->GetFromPrivPos()
: s->GetToPrivPos();
// VZ: we may be called before we had a chance to re-render ourselves
// and in this case GetFrom/ToPrivPos() is not set yet -- assume
// that this only happens in case of a double/triple click (which
// seems to be the case now) and so it makes sense to select the
// entire contents of the cell in this case
//
// TODO: but this really needs to be fixed in some better way later...
if ( priv != wxDefaultPosition )
{
int part1 = priv.x;
int part2 = priv.y;
if ( part1 == part2 )
return wxEmptyString;
return GetPartAsText(part1, part2);
}
//else: return the whole word below
}
return m_wordOrig;
}
wxString wxHtmlWordWithTabsCell::GetPartAsText(int begin, int end) const
{
// NB: The 'begin' and 'end' positions are in the _displayed_ text
// (stored in m_Word) and not in the text with tabs that should
// be copied to clipboard (m_wordOrig).
//
// NB: Because selection is performed on displayed text, it's possible
// to select e.g. "half of TAB character" -- IOW, 'begin' and 'end'
// may be in the middle of TAB character expansion into ' 's. In this
// case, we copy the TAB character to clipboard once.
wxASSERT( begin < end );
const unsigned SPACES_PER_TAB = 8;
wxString sel;
int pos = 0;
wxString::const_iterator i = m_wordOrig.begin();
// find the beginning of text to copy:
for ( ; pos < begin; ++i )
{
if ( *i == '\t' )
{
pos += 8 - (m_linepos + pos) % SPACES_PER_TAB;
if ( pos >= begin )
{
sel += '\t';
}
}
else
{
++pos;
}
}
// copy the content until we reach 'end':
for ( ; pos < end; ++i )
{
const wxChar c = *i;
sel += c;
if ( c == '\t' )
pos += 8 - (m_linepos + pos) % SPACES_PER_TAB;
else
++pos;
}
return sel;
}
//-----------------------------------------------------------------------------
// wxHtmlWinParser
//-----------------------------------------------------------------------------
struct wxHtmlWinParser_TextParsingState
{
// current whitespace handling mode
wxHtmlWinParser::WhitespaceMode m_whitespaceMode;
wxHtmlWordCell *m_lastWordCell;
// current position on line, in num. of characters; used to properly
// expand TABs; only updated while inside <pre>
int m_posColumn;
};
IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinParser, wxHtmlParser)
wxList wxHtmlWinParser::m_Modules;
wxHtmlWinParser::wxHtmlWinParser(wxHtmlWindowInterface *wndIface)
{
m_textParsingState = new wxHtmlWinParser_TextParsingState;
m_textParsingState->m_whitespaceMode = Whitespace_Normal;
m_textParsingState->m_lastWordCell = NULL;
m_textParsingState->m_posColumn = 0;
m_tmpStrBuf = NULL;
m_tmpStrBufSize = 0;
m_windowInterface = wndIface;
m_Container = NULL;
m_DC = NULL;
m_CharHeight = m_CharWidth = 0;
m_UseLink = false;
#if !wxUSE_UNICODE
m_EncConv = NULL;
m_InputEnc = wxFONTENCODING_ISO8859_1;
m_OutputEnc = wxFONTENCODING_DEFAULT;
#endif
{
int i, j, k, l, m;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
for (k = 0; k < 2; k++)
for (l = 0; l < 2; l++)
for (m = 0; m < 7; m++)
{
m_FontsTable[i][j][k][l][m] = NULL;
m_FontsFacesTable[i][j][k][l][m] = wxEmptyString;
#if !wxUSE_UNICODE
m_FontsEncTable[i][j][k][l][m] = wxFONTENCODING_DEFAULT;
#endif
}
SetFonts(wxEmptyString, wxEmptyString, NULL);
}
// fill in wxHtmlParser's tables:
wxList::compatibility_iterator node = m_Modules.GetFirst();
while (node)
{
wxHtmlTagsModule *mod = (wxHtmlTagsModule*) node->GetData();
mod->FillHandlersTable(this);
node = node->GetNext();
}
}
wxHtmlWinParser::~wxHtmlWinParser()
{
int i, j, k, l, m;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
for (k = 0; k < 2; k++)
for (l = 0; l < 2; l++)
for (m = 0; m < 7; m++)
{
if (m_FontsTable[i][j][k][l][m] != NULL)
delete m_FontsTable[i][j][k][l][m];
}
#if !wxUSE_UNICODE
delete m_EncConv;
#endif
delete[] m_tmpStrBuf;
delete m_textParsingState;
}
void wxHtmlWinParser::AddModule(wxHtmlTagsModule *module)
{
m_Modules.Append(module);
}
void wxHtmlWinParser::RemoveModule(wxHtmlTagsModule *module)
{
m_Modules.DeleteObject(module);
}
// build all HTML font sizes (1..7) from the given base size
static void wxBuildFontSizes(int *sizes, int size)
{
// using a fixed factor (1.2, from CSS2) is a bad idea as explained at
// http://www.w3.org/TR/CSS21/fonts.html#font-size-props but this is by far
// simplest thing to do so still do it like this for now
sizes[0] = int(size * 0.75); // exception to 1.2 rule, otherwise too small
sizes[1] = int(size * 0.83);
sizes[2] = size;
sizes[3] = int(size * 1.2);
sizes[4] = int(size * 1.44);
sizes[5] = int(size * 1.73);
sizes[6] = int(size * 2);
}
static int wxGetDefaultHTMLFontSize()
{
// base the default font size on the size of the default system font but
// also ensure that we have a font of reasonable size, otherwise small HTML
// fonts are unreadable
int size = wxNORMAL_FONT->GetPointSize();
if ( size < 10 )
size = 10;
return size;
}
void wxHtmlWinParser::SetFonts(const wxString& normal_face,
const wxString& fixed_face,
const int *sizes)
{
static int default_sizes[7] = { 0 };
if ( !sizes )
{
if ( !default_sizes[0] )
wxBuildFontSizes(default_sizes, wxGetDefaultHTMLFontSize());
sizes = default_sizes;
}
int i, j, k, l, m;
for (i = 0; i < 7; i++)
m_FontsSizes[i] = sizes[i];
m_FontFaceFixed = fixed_face;
m_FontFaceNormal = normal_face;
#if !wxUSE_UNICODE
SetInputEncoding(m_InputEnc);
#endif
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
for (k = 0; k < 2; k++)
for (l = 0; l < 2; l++)
for (m = 0; m < 7; m++) {
if (m_FontsTable[i][j][k][l][m] != NULL)
{
delete m_FontsTable[i][j][k][l][m];
m_FontsTable[i][j][k][l][m] = NULL;
}
}
}
void wxHtmlWinParser::SetStandardFonts(int size,
const wxString& normal_face,
const wxString& fixed_face)
{
if (size == -1)
size = wxGetDefaultHTMLFontSize();
int f_sizes[7];
wxBuildFontSizes(f_sizes, size);
wxString normal = normal_face;
if ( normal.empty() )
normal = wxNORMAL_FONT->GetFaceName();
SetFonts(normal, fixed_face, f_sizes);
}
void wxHtmlWinParser::InitParser(const wxString& source)
{
wxHtmlParser::InitParser(source);
wxASSERT_MSG(m_DC != NULL, wxT("no DC assigned to wxHtmlWinParser!!"));
m_FontBold = m_FontItalic = m_FontUnderlined = m_FontFixed = FALSE;
m_FontSize = 3; //default one
CreateCurrentFont(); // we're selecting default font into
m_DC->GetTextExtent( wxT("H"), &m_CharWidth, &m_CharHeight);
/* NOTE : we're not using GetCharWidth/Height() because
of differences under X and win
*/
m_UseLink = false;
m_Link = wxHtmlLinkInfo( wxEmptyString );
m_LinkColor.Set(0, 0, 0xFF);
m_ActualColor.Set(0, 0, 0);
m_Align = wxHTML_ALIGN_LEFT;
m_ScriptMode = wxHTML_SCRIPT_NORMAL;
m_ScriptBaseline = 0;
m_tmpLastWasSpace = false;
m_textParsingState->m_lastWordCell = NULL;
// open the toplevel container that contains everything else and that
// is never closed (this makes parser's life easier):
OpenContainer();
// then open the first container into which page's content will go:
OpenContainer();
#if !wxUSE_UNICODE
wxString charset = ExtractCharsetInformation(source);
if (!charset.empty())
{
wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(charset);
if (enc != wxFONTENCODING_SYSTEM)
SetInputEncoding(enc);
}
#endif
m_Container->InsertCell(new wxHtmlColourCell(m_ActualColor));
wxColour windowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW) ;
m_Container->InsertCell
(
new wxHtmlColourCell
(
m_windowInterface
? m_windowInterface->GetHTMLBackgroundColour()
: windowColour,
wxHTML_CLR_BACKGROUND
)
);
m_Container->InsertCell(new wxHtmlFontCell(CreateCurrentFont()));
}
void wxHtmlWinParser::DoneParser()
{
m_Container = NULL;
#if !wxUSE_UNICODE
SetInputEncoding(wxFONTENCODING_ISO8859_1); // for next call
#endif
wxHtmlParser::DoneParser();
}
#if WXWIN_COMPATIBILITY_2_6
wxHtmlWindow *wxHtmlWinParser::GetWindow()
{
if (!m_windowInterface)
return NULL;
return wxDynamicCast(m_windowInterface->GetHTMLWindow(), wxHtmlWindow);
}
#endif
wxObject* wxHtmlWinParser::GetProduct()
{
wxHtmlContainerCell *top;
CloseContainer();
OpenContainer();
top = m_Container;
while (top->GetParent()) top = top->GetParent();
top->RemoveExtraSpacing(true, true);
return top;
}
wxFSFile *wxHtmlWinParser::OpenURL(wxHtmlURLType type,
const wxString& url) const
{
if ( !m_windowInterface )
return wxHtmlParser::OpenURL(type, url);
wxString myurl(url);
wxHtmlOpeningStatus status;
for (;;)
{
wxString myfullurl(myurl);
// consider url as absolute path first
wxURI current(myurl);
myfullurl = current.BuildUnescapedURI();
// if not absolute then ...
if( current.IsReference() )
{
wxString basepath = GetFS()->GetPath();
wxURI base(basepath);
// ... try to apply base path if valid ...
if( !base.IsReference() )
{
wxURI path(myfullurl);
path.Resolve( base );
myfullurl = path.BuildUnescapedURI();
}
else
{
// ... or force such addition if not included already
if( !current.GetPath().Contains(base.GetPath()) )
{
basepath += myurl;
wxURI connected( basepath );
myfullurl = connected.BuildUnescapedURI();
}
}
}
wxString redirect;
status = m_windowInterface->OnHTMLOpeningURL(type, myfullurl, &redirect);
if ( status != wxHTML_REDIRECT )
break;
myurl = redirect;
}
if ( status == wxHTML_BLOCK )
return NULL;
int flags = wxFS_READ;
if (type == wxHTML_URL_IMAGE)
flags |= wxFS_SEEKABLE;
return GetFS()->OpenFile(myurl, flags);
}
void wxHtmlWinParser::SetWhitespaceMode(wxHtmlWinParser::WhitespaceMode mode)
{
m_textParsingState->m_whitespaceMode = mode;
}
wxHtmlWinParser::WhitespaceMode wxHtmlWinParser::GetWhitespaceMode() const
{
return m_textParsingState->m_whitespaceMode;
}
void wxHtmlWinParser::AddText(const wxChar* txt)
{
const wxChar nbsp = GetEntitiesParser()->GetCharForCode(160 /* nbsp */);
if ( m_textParsingState->m_whitespaceMode == Whitespace_Normal )
{
size_t i = 0,
x,
lng = wxStrlen(txt);
int templen = 0;
if (lng+1 > m_tmpStrBufSize)
{
delete[] m_tmpStrBuf;
m_tmpStrBuf = new wxChar[lng+1];
m_tmpStrBufSize = lng+1;
}
wxChar *temp = m_tmpStrBuf;
if (m_tmpLastWasSpace)
{
while ((i < lng) &&
((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) || (txt[i] == wxT(' ')) ||
(txt[i] == wxT('\t')))) i++;
}
while (i < lng)
{
x = 0;
const wxChar d = temp[templen++] = txt[i];
if ((d == wxT('\n')) || (d == wxT('\r')) || (d == wxT(' ')) || (d == wxT('\t')))
{
i++, x++;
while ((i < lng) && ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) ||
(txt[i] == wxT(' ')) || (txt[i] == wxT('\t')))) i++, x++;
}
else i++;
if (x)
{
temp[templen-1] = wxT(' ');
FlushWordBuf(temp, templen, nbsp);
m_tmpLastWasSpace = true;
}
}
if (templen && (templen > 1 || temp[0] != wxT(' ')))
{
FlushWordBuf(temp, templen, nbsp);
m_tmpLastWasSpace = false;
}
}
else // m_whitespaceMode == Whitespace_Pre
{
if ( wxStrchr(txt, nbsp) != NULL )
{
// we need to substitute spaces for &nbsp; here just like we
// did in the Whitespace_Normal branch above
wxString txt2(txt);
wxChar nbsp_str[2];
nbsp_str[0] = nbsp;
nbsp_str[1] = 0;
txt2.Replace(nbsp_str, wxT(" "));
AddPreBlock(txt2);
}
else
{
AddPreBlock(txt);
}
// don't eat any whitespace in <pre> block
m_tmpLastWasSpace = false;
}
}
void wxHtmlWinParser::FlushWordBuf(wxChar *buf, int& len, wxChar nbsp)
{
buf[len] = 0;
for ( int i = 0; i < len; i++ )
{
if ( buf[i] == nbsp )
buf[i] = ' ';
}
#if !wxUSE_UNICODE
if (m_EncConv)
m_EncConv->Convert(buf);
#endif
AddWord(wxString(buf, len));
len = 0;
}
void wxHtmlWinParser::AddWord(const wxString& word)
{
AddWord(new wxHtmlWordCell(word, *(GetDC())));
}
void wxHtmlWinParser::AddWord(wxHtmlWordCell *c)
{
ApplyStateToCell(c);
m_Container->InsertCell(c);
c->SetPreviousWord(m_textParsingState->m_lastWordCell);
m_textParsingState->m_lastWordCell = c;
}
void wxHtmlWinParser::AddPreBlock(const wxString& text)
{
if ( text.find(wxT('\t')) != wxString::npos )
{
wxString text2;
text2.reserve(text.length());
const wxString::const_iterator end = text.end();
wxString::const_iterator copyFrom = text.begin();
size_t posFrom = 0;
size_t pos = 0;
int posColumn = m_textParsingState->m_posColumn;
for ( wxString::const_iterator i = copyFrom; i != end; ++i, ++pos )
{
if ( *i == wxT('\t') )
{
if ( copyFrom != i )
text2.append(copyFrom, i);
const unsigned SPACES_PER_TAB = 8;
const size_t expandTo = SPACES_PER_TAB - posColumn % SPACES_PER_TAB;
text2.append(expandTo, wxT(' '));
posColumn += expandTo;
copyFrom = i + 1;
posFrom = pos + 1;
}
else
{
++posColumn;
}
}
if ( copyFrom != text.end() )
text2.append(copyFrom, text.end());
AddWord(new wxHtmlWordWithTabsCell(text2, text,
m_textParsingState->m_posColumn,
*(GetDC())));
m_textParsingState->m_posColumn = posColumn;
}
else
{
// no special formatting needed
AddWord(text);
m_textParsingState->m_posColumn += text.length();
}
}
wxHtmlContainerCell* wxHtmlWinParser::OpenContainer()
{
m_Container = new wxHtmlContainerCell(m_Container);
m_Container->SetAlignHor(m_Align);
m_textParsingState->m_posColumn = 0;
m_tmpLastWasSpace = true;
/* to avoid space being first character in paragraph */
return m_Container;
}
wxHtmlContainerCell* wxHtmlWinParser::SetContainer(wxHtmlContainerCell *c)
{
m_tmpLastWasSpace = true;
/* to avoid space being first character in paragraph */
return m_Container = c;
}
wxHtmlContainerCell* wxHtmlWinParser::CloseContainer()
{
m_Container = m_Container->GetParent();
return m_Container;
}
void wxHtmlWinParser::SetFontSize(int s)
{
if (s < 1) s = 1;
else if (s > 7) s = 7;
m_FontSize = s;
}
wxFont* wxHtmlWinParser::CreateCurrentFont()
{
int fb = GetFontBold(),
fi = GetFontItalic(),
fu = GetFontUnderlined(),
ff = GetFontFixed(),
fs = GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ;
wxString face = ff ? m_FontFaceFixed : m_FontFaceNormal;
wxString *faceptr = &(m_FontsFacesTable[fb][fi][fu][ff][fs]);
wxFont **fontptr = &(m_FontsTable[fb][fi][fu][ff][fs]);
#if !wxUSE_UNICODE
wxFontEncoding *encptr = &(m_FontsEncTable[fb][fi][fu][ff][fs]);
#endif
if (*fontptr != NULL && (*faceptr != face
#if !wxUSE_UNICODE
|| *encptr != m_OutputEnc
#endif
))
{
delete *fontptr;
*fontptr = NULL;
}
if (*fontptr == NULL)
{
*faceptr = face;
*fontptr = new wxFont(
(int) (m_FontsSizes[fs] * m_PixelScale),
ff ? wxMODERN : wxSWISS,
fi ? wxITALIC : wxNORMAL,
fb ? wxBOLD : wxNORMAL,
fu ? true : false, face
#if wxUSE_UNICODE
);
#else
, m_OutputEnc);
*encptr = m_OutputEnc;
#endif
}
m_DC->SetFont(**fontptr);
return (*fontptr);
}
void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo& link)
{
m_Link = link;
m_UseLink = (link.GetHref() != wxEmptyString);
}
void wxHtmlWinParser::SetFontFace(const wxString& face)
{
if (GetFontFixed()) m_FontFaceFixed = face;
else m_FontFaceNormal = face;
#if !wxUSE_UNICODE
if (m_InputEnc != wxFONTENCODING_DEFAULT)
SetInputEncoding(m_InputEnc);
#endif
}
void wxHtmlWinParser::ApplyStateToCell(wxHtmlCell *cell)
{
// set the link:
if (m_UseLink)
cell->SetLink(GetLink());
// apply current script mode settings:
cell->SetScriptMode(GetScriptMode(), GetScriptBaseline());
}
#if !wxUSE_UNICODE
void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc)
{
m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
if (m_EncConv)
{
delete m_EncConv;
m_EncConv = NULL;
}
if (enc == wxFONTENCODING_DEFAULT) return;
wxFontEncoding altfix, altnorm;
bool availfix, availnorm;
// exact match?
availnorm = wxFontMapper::Get()->IsEncodingAvailable(enc, m_FontFaceNormal);
availfix = wxFontMapper::Get()->IsEncodingAvailable(enc, m_FontFaceFixed);
if (availnorm && availfix)
m_OutputEnc = enc;
// alternatives?
else if (wxFontMapper::Get()->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, false) &&
wxFontMapper::Get()->GetAltForEncoding(enc, &altfix, m_FontFaceFixed, false) &&
altnorm == altfix)
m_OutputEnc = altnorm;
// at least normal face?
else if (availnorm)
m_OutputEnc = enc;
else if (wxFontMapper::Get()->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, false))
m_OutputEnc = altnorm;
else
{
#ifndef __WXMAC__
// okay, let's convert to ISO_8859-1, available always
m_OutputEnc = wxFONTENCODING_DEFAULT;
#else
m_OutputEnc = wxLocale::GetSystemEncoding() ;
#endif
}
m_InputEnc = enc;
if (m_OutputEnc == wxFONTENCODING_DEFAULT)
GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM);
else
GetEntitiesParser()->SetEncoding(m_OutputEnc);
if (m_InputEnc == m_OutputEnc) return;
m_EncConv = new wxEncodingConverter();
if (!m_EncConv->Init(m_InputEnc,
(m_OutputEnc == wxFONTENCODING_DEFAULT) ?
wxFONTENCODING_ISO8859_1 : m_OutputEnc,
wxCONVERT_SUBSTITUTE))
{ // total failure :-(
wxLogError(_("Failed to display HTML document in %s encoding"),
wxFontMapper::GetEncodingName(enc).c_str());
m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
delete m_EncConv;
m_EncConv = NULL;
}
}
#endif
//-----------------------------------------------------------------------------
// wxHtmlWinTagHandler
//-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler, wxHtmlTagHandler)
//-----------------------------------------------------------------------------
// wxHtmlTagsModule
//-----------------------------------------------------------------------------
// NB: This is *NOT* winpars.cpp's initialization and shutdown code!!
// This module is an ancestor for tag handlers modules defined
// in m_*.cpp files with TAGS_MODULE_BEGIN...TAGS_MODULE_END construct.
//
// Do not add any winpars.cpp shutdown or initialization code to it,
// create a new module instead!
IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule, wxModule)
bool wxHtmlTagsModule::OnInit()
{
wxHtmlWinParser::AddModule(this);
return true;
}
void wxHtmlTagsModule::OnExit()
{
wxHtmlWinParser::RemoveModule(this);
}
#endif