This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
709 lines
22 KiB
C++
709 lines
22 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/richtext/richtexthtml.cpp
|
|
// Purpose: HTML I/O for wxRichTextCtrl
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 2005-09-30
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_RICHTEXT
|
|
|
|
#include "wx/richtext/richtexthtml.h"
|
|
#include "wx/richtext/richtextstyles.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#endif
|
|
|
|
#include "wx/filename.h"
|
|
#include "wx/wfstream.h"
|
|
#include "wx/txtstrm.h"
|
|
|
|
#if wxUSE_FILESYSTEM
|
|
#include "wx/filesys.h"
|
|
#include "wx/fs_mem.h"
|
|
#endif
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxRichTextHTMLHandler, wxRichTextFileHandler)
|
|
|
|
int wxRichTextHTMLHandler::sm_fileCounter = 1;
|
|
|
|
wxRichTextHTMLHandler::wxRichTextHTMLHandler(const wxString& name, const wxString& ext, int type)
|
|
: wxRichTextFileHandler(name, ext, type), m_buffer(NULL), m_font(false), m_inTable(false)
|
|
{
|
|
m_fontSizeMapping.Add(8);
|
|
m_fontSizeMapping.Add(10);
|
|
m_fontSizeMapping.Add(13);
|
|
m_fontSizeMapping.Add(17);
|
|
m_fontSizeMapping.Add(22);
|
|
m_fontSizeMapping.Add(30);
|
|
m_fontSizeMapping.Add(100);
|
|
}
|
|
|
|
/// Can we handle this filename (if using files)? By default, checks the extension.
|
|
bool wxRichTextHTMLHandler::CanHandle(const wxString& filename) const
|
|
{
|
|
wxString path, file, ext;
|
|
wxFileName::SplitPath(filename, & path, & file, & ext);
|
|
|
|
return (ext.Lower() == wxT("html") || ext.Lower() == wxT("htm"));
|
|
}
|
|
|
|
|
|
#if wxUSE_STREAMS
|
|
bool wxRichTextHTMLHandler::DoLoadFile(wxRichTextBuffer *WXUNUSED(buffer), wxInputStream& WXUNUSED(stream))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* We need to output only _changes_ in character formatting.
|
|
*/
|
|
|
|
bool wxRichTextHTMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
|
|
{
|
|
m_buffer = buffer;
|
|
|
|
ClearTemporaryImageLocations();
|
|
|
|
wxRichTextDrawingContext context(buffer);
|
|
buffer->Defragment(context);
|
|
|
|
#if wxUSE_UNICODE
|
|
wxCSConv* customEncoding = NULL;
|
|
wxMBConv* conv = NULL;
|
|
if (!GetEncoding().IsEmpty())
|
|
{
|
|
customEncoding = new wxCSConv(GetEncoding());
|
|
if (!customEncoding->IsOk())
|
|
{
|
|
wxDELETE(customEncoding);
|
|
}
|
|
}
|
|
if (customEncoding)
|
|
conv = customEncoding;
|
|
else
|
|
conv = & wxConvUTF8;
|
|
#endif
|
|
|
|
{
|
|
#if wxUSE_UNICODE
|
|
wxTextOutputStream str(stream, wxEOL_NATIVE, *conv);
|
|
#else
|
|
wxTextOutputStream str(stream, wxEOL_NATIVE);
|
|
#endif
|
|
|
|
wxRichTextAttr currentParaStyle = buffer->GetAttributes();
|
|
wxRichTextAttr currentCharStyle = buffer->GetAttributes();
|
|
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_NO_HEADER_FOOTER) == 0)
|
|
str << wxT("<html><head></head><body>\n");
|
|
|
|
OutputFont(currentParaStyle, str);
|
|
|
|
m_font = false;
|
|
m_inTable = false;
|
|
|
|
m_indents.Clear();
|
|
m_listTypes.Clear();
|
|
|
|
wxRichTextObjectList::compatibility_iterator node = buffer->GetChildren().GetFirst();
|
|
while (node)
|
|
{
|
|
wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
|
|
wxASSERT (para != NULL);
|
|
|
|
if (para)
|
|
{
|
|
wxRichTextAttr paraStyle(para->GetCombinedAttributes());
|
|
|
|
BeginParagraphFormatting(currentParaStyle, paraStyle, str);
|
|
|
|
wxRichTextObjectList::compatibility_iterator node2 = para->GetChildren().GetFirst();
|
|
while (node2)
|
|
{
|
|
wxRichTextObject* obj = node2->GetData();
|
|
wxRichTextPlainText* textObj = wxDynamicCast(obj, wxRichTextPlainText);
|
|
if (textObj && !textObj->IsEmpty())
|
|
{
|
|
wxRichTextAttr charStyle(para->GetCombinedAttributes(obj->GetAttributes()));
|
|
BeginCharacterFormatting(currentCharStyle, charStyle, paraStyle, str);
|
|
|
|
wxString text = textObj->GetText();
|
|
|
|
if (charStyle.HasTextEffects() && (charStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
|
text.MakeUpper();
|
|
|
|
wxString toReplace = wxRichTextLineBreakChar;
|
|
text.Replace(toReplace, wxT("<br>"));
|
|
|
|
str << text;
|
|
|
|
EndCharacterFormatting(currentCharStyle, charStyle, paraStyle, str);
|
|
}
|
|
|
|
wxRichTextImage* image = wxDynamicCast(obj, wxRichTextImage);
|
|
if( image && (!image->IsEmpty() || image->GetImageBlock().GetData()))
|
|
WriteImage( image, stream );
|
|
|
|
node2 = node2->GetNext();
|
|
}
|
|
|
|
EndParagraphFormatting(currentParaStyle, paraStyle, str);
|
|
|
|
str << wxT("\n");
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
|
|
CloseLists(-1, str);
|
|
|
|
str << wxT("</font>");
|
|
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_NO_HEADER_FOOTER) == 0)
|
|
str << wxT("</body></html>");
|
|
|
|
str << wxT("\n");
|
|
}
|
|
|
|
#if wxUSE_UNICODE
|
|
if (customEncoding)
|
|
delete customEncoding;
|
|
#endif
|
|
|
|
m_buffer = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxRichTextHTMLHandler::BeginCharacterFormatting(const wxRichTextAttr& currentStyle, const wxRichTextAttr& thisStyle, const wxRichTextAttr& WXUNUSED(paraStyle), wxTextOutputStream& str)
|
|
{
|
|
wxString style;
|
|
|
|
// Is there any change in the font properties of the item?
|
|
if (thisStyle.GetFontFaceName() != currentStyle.GetFontFaceName())
|
|
{
|
|
wxString faceName(thisStyle.GetFontFaceName());
|
|
style += wxString::Format(wxT(" face=\"%s\""), faceName.c_str());
|
|
}
|
|
if (thisStyle.GetFontSize() != currentStyle.GetFontSize())
|
|
style += wxString::Format(wxT(" size=\"%ld\""), PtToSize(thisStyle.GetFontSize()));
|
|
|
|
bool bTextColourChanged = (thisStyle.GetTextColour() != currentStyle.GetTextColour());
|
|
bool bBackgroundColourChanged = (thisStyle.GetBackgroundColour() != currentStyle.GetBackgroundColour());
|
|
if (bTextColourChanged || bBackgroundColourChanged)
|
|
{
|
|
style += wxT(" style=\"");
|
|
|
|
if (bTextColourChanged)
|
|
{
|
|
wxString color(thisStyle.GetTextColour().GetAsString(wxC2S_HTML_SYNTAX));
|
|
style += wxString::Format(wxT("color: %s"), color.c_str());
|
|
}
|
|
if (bTextColourChanged && bBackgroundColourChanged)
|
|
style += wxT(";");
|
|
if (bBackgroundColourChanged)
|
|
{
|
|
wxString color(thisStyle.GetBackgroundColour().GetAsString(wxC2S_HTML_SYNTAX));
|
|
style += wxString::Format(wxT("background-color: %s"), color.c_str());
|
|
}
|
|
|
|
style += wxT("\"");
|
|
}
|
|
|
|
if (style.size())
|
|
{
|
|
str << wxString::Format(wxT("<font %s >"), style.c_str());
|
|
m_font = true;
|
|
}
|
|
|
|
if (thisStyle.GetFontWeight() == wxFONTWEIGHT_BOLD)
|
|
str << wxT("<b>");
|
|
if (thisStyle.GetFontStyle() == wxFONTSTYLE_ITALIC)
|
|
str << wxT("<i>");
|
|
if (thisStyle.GetFontUnderlined())
|
|
str << wxT("<u>");
|
|
|
|
if (thisStyle.HasURL())
|
|
str << wxT("<a href=\"") << thisStyle.GetURL() << wxT("\">");
|
|
|
|
if (thisStyle.HasTextEffects())
|
|
{
|
|
if (thisStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH)
|
|
str << wxT("<del>");
|
|
if (thisStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT)
|
|
str << wxT("<sup>");
|
|
if (thisStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT)
|
|
str << wxT("<sub>");
|
|
}
|
|
}
|
|
|
|
void wxRichTextHTMLHandler::EndCharacterFormatting(const wxRichTextAttr& WXUNUSED(currentStyle), const wxRichTextAttr& thisStyle, const wxRichTextAttr& WXUNUSED(paraStyle), wxTextOutputStream& stream)
|
|
{
|
|
if (thisStyle.HasURL())
|
|
stream << wxT("</a>");
|
|
|
|
if (thisStyle.GetFontUnderlined())
|
|
stream << wxT("</u>");
|
|
if (thisStyle.GetFontStyle() == wxFONTSTYLE_ITALIC)
|
|
stream << wxT("</i>");
|
|
if (thisStyle.GetFontWeight() == wxFONTWEIGHT_BOLD)
|
|
stream << wxT("</b>");
|
|
|
|
if (thisStyle.HasTextEffects())
|
|
{
|
|
if (thisStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH)
|
|
stream << wxT("</del>");
|
|
if (thisStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT)
|
|
stream << wxT("</sup>");
|
|
if (thisStyle.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT)
|
|
stream << wxT("</sub>");
|
|
}
|
|
|
|
if (m_font)
|
|
{
|
|
m_font = false;
|
|
stream << wxT("</font>");
|
|
}
|
|
}
|
|
|
|
/// Begin paragraph formatting
|
|
void wxRichTextHTMLHandler::BeginParagraphFormatting(const wxRichTextAttr& WXUNUSED(currentStyle), const wxRichTextAttr& thisStyle, wxTextOutputStream& str)
|
|
{
|
|
if (thisStyle.HasPageBreak())
|
|
{
|
|
str << wxT("<div style=\"page-break-after:always\"></div>\n");
|
|
}
|
|
|
|
if (thisStyle.HasLeftIndent() && thisStyle.GetLeftIndent() != 0)
|
|
{
|
|
if (thisStyle.HasBulletStyle())
|
|
{
|
|
int indent = thisStyle.GetLeftIndent();
|
|
|
|
// Close levels high than this
|
|
CloseLists(indent, str);
|
|
|
|
if (m_indents.GetCount() > 0 && indent == m_indents.Last())
|
|
{
|
|
// Same level, no need to start a new list
|
|
}
|
|
else if (m_indents.GetCount() == 0 || indent > m_indents.Last())
|
|
{
|
|
m_indents.Add(indent);
|
|
|
|
wxString tag;
|
|
int listType = TypeOfList(thisStyle, tag);
|
|
m_listTypes.Add(listType);
|
|
|
|
// wxHTML needs an extra <p> before a list when using <p> ... </p> in previous paragraphs.
|
|
// TODO: pass a flag that indicates we're using wxHTML.
|
|
str << wxT("<p>\n");
|
|
|
|
str << tag;
|
|
}
|
|
|
|
str << wxT("<li> ");
|
|
}
|
|
else
|
|
{
|
|
CloseLists(-1, str);
|
|
|
|
wxString align = GetAlignment(thisStyle);
|
|
str << wxString::Format(wxT("<p align=\"%s\""), align.c_str());
|
|
|
|
wxString styleStr;
|
|
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && thisStyle.HasParagraphSpacingBefore())
|
|
{
|
|
float spacingBeforeMM = thisStyle.GetParagraphSpacingBefore() / 10.0;
|
|
|
|
styleStr += wxString::Format(wxT("margin-top: %.2fmm; "), spacingBeforeMM);
|
|
}
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && thisStyle.HasParagraphSpacingAfter())
|
|
{
|
|
float spacingAfterMM = thisStyle.GetParagraphSpacingAfter() / 10.0;
|
|
|
|
styleStr += wxString::Format(wxT("margin-bottom: %.2fmm; "), spacingAfterMM);
|
|
}
|
|
|
|
float indentLeftMM = (thisStyle.GetLeftIndent() + thisStyle.GetLeftSubIndent())/10.0;
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && (indentLeftMM > 0.0))
|
|
{
|
|
styleStr += wxString::Format(wxT("margin-left: %.2fmm; "), indentLeftMM);
|
|
}
|
|
float indentRightMM = thisStyle.GetRightIndent()/10.0;
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && thisStyle.HasRightIndent() && (indentRightMM > 0.0))
|
|
{
|
|
styleStr += wxString::Format(wxT("margin-right: %.2fmm; "), indentRightMM);
|
|
}
|
|
// First line indentation
|
|
float firstLineIndentMM = - thisStyle.GetLeftSubIndent() / 10.0;
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && (firstLineIndentMM > 0.0))
|
|
{
|
|
styleStr += wxString::Format(wxT("text-indent: %.2fmm; "), firstLineIndentMM);
|
|
}
|
|
|
|
if (!styleStr.IsEmpty())
|
|
str << wxT(" style=\"") << styleStr << wxT("\"");
|
|
|
|
str << wxT(">");
|
|
|
|
// TODO: convert to pixels
|
|
int indentPixels = static_cast<int>(indentLeftMM*10/4);
|
|
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) == 0)
|
|
{
|
|
// Use a table to do indenting if we don't have CSS
|
|
str << wxString::Format(wxT("<table border=0 cellpadding=0 cellspacing=0><tr><td width=\"%d\"></td><td>"), indentPixels);
|
|
m_inTable = true;
|
|
}
|
|
|
|
if (((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) == 0) && (thisStyle.GetLeftSubIndent() < 0))
|
|
{
|
|
str << SymbolicIndent( - thisStyle.GetLeftSubIndent());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseLists(-1, str);
|
|
|
|
wxString align = GetAlignment(thisStyle);
|
|
str << wxString::Format(wxT("<p align=\"%s\""), align.c_str());
|
|
|
|
wxString styleStr;
|
|
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && thisStyle.HasParagraphSpacingBefore())
|
|
{
|
|
float spacingBeforeMM = thisStyle.GetParagraphSpacingBefore() / 10.0;
|
|
|
|
styleStr += wxString::Format(wxT("margin-top: %.2fmm; "), spacingBeforeMM);
|
|
}
|
|
if ((GetFlags() & wxRICHTEXT_HANDLER_USE_CSS) && thisStyle.HasParagraphSpacingAfter())
|
|
{
|
|
float spacingAfterMM = thisStyle.GetParagraphSpacingAfter() / 10.0;
|
|
|
|
styleStr += wxString::Format(wxT("margin-bottom: %.2fmm; "), spacingAfterMM);
|
|
}
|
|
|
|
if (!styleStr.IsEmpty())
|
|
str << wxT(" style=\"") << styleStr << wxT("\"");
|
|
|
|
str << wxT(">");
|
|
}
|
|
OutputFont(thisStyle, str);
|
|
}
|
|
|
|
/// End paragraph formatting
|
|
void wxRichTextHTMLHandler::EndParagraphFormatting(const wxRichTextAttr& WXUNUSED(currentStyle), const wxRichTextAttr& thisStyle, wxTextOutputStream& stream)
|
|
{
|
|
if (thisStyle.HasFont())
|
|
stream << wxT("</font>");
|
|
|
|
if (m_inTable)
|
|
{
|
|
stream << wxT("</td></tr></table></p>\n");
|
|
m_inTable = false;
|
|
}
|
|
else if (!thisStyle.HasBulletStyle())
|
|
stream << wxT("</p>\n");
|
|
}
|
|
|
|
/// Closes lists to level (-1 means close all)
|
|
void wxRichTextHTMLHandler::CloseLists(int level, wxTextOutputStream& str)
|
|
{
|
|
// Close levels high than this
|
|
int i = m_indents.GetCount()-1;
|
|
while (i >= 0)
|
|
{
|
|
int l = m_indents[i];
|
|
if (l > level)
|
|
{
|
|
if (m_listTypes[i] == 0)
|
|
str << wxT("</ol>");
|
|
else
|
|
str << wxT("</ul>");
|
|
m_indents.RemoveAt(i);
|
|
m_listTypes.RemoveAt(i);
|
|
}
|
|
else
|
|
break;
|
|
i --;
|
|
}
|
|
}
|
|
|
|
/// Output font tag
|
|
void wxRichTextHTMLHandler::OutputFont(const wxRichTextAttr& style, wxTextOutputStream& stream)
|
|
{
|
|
if (style.HasFont())
|
|
{
|
|
stream << wxString::Format(wxT("<font face=\"%s\" size=\"%ld\""), style.GetFontFaceName().c_str(), PtToSize(style.GetFontSize()));
|
|
if (style.HasTextColour())
|
|
stream << wxString::Format(wxT(" color=\"%s\""), style.GetTextColour().GetAsString(wxC2S_HTML_SYNTAX).c_str());
|
|
stream << wxT(" >");
|
|
}
|
|
}
|
|
|
|
int wxRichTextHTMLHandler::TypeOfList( const wxRichTextAttr& thisStyle, wxString& tag )
|
|
{
|
|
// We can use number attribute of li tag but not all the browsers support it.
|
|
// also wxHtmlWindow doesn't support type attribute.
|
|
|
|
bool m_is_ul = false;
|
|
if (thisStyle.GetBulletStyle() == (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD))
|
|
tag = wxT("<ol type=\"1\">");
|
|
else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER)
|
|
tag = wxT("<ol type=\"A\">");
|
|
else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER)
|
|
tag = wxT("<ol type=\"a\">");
|
|
else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER)
|
|
tag = wxT("<ol type=\"I\">");
|
|
else if (thisStyle.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)
|
|
tag = wxT("<ol type=\"i\">");
|
|
else
|
|
{
|
|
tag = wxT("<ul>");
|
|
m_is_ul = true;
|
|
}
|
|
|
|
if (m_is_ul)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
wxString wxRichTextHTMLHandler::GetAlignment( const wxRichTextAttr& thisStyle )
|
|
{
|
|
switch( thisStyle.GetAlignment() )
|
|
{
|
|
case wxTEXT_ALIGNMENT_LEFT:
|
|
return wxT("left");
|
|
case wxTEXT_ALIGNMENT_RIGHT:
|
|
return wxT("right");
|
|
case wxTEXT_ALIGNMENT_CENTER:
|
|
return wxT("center");
|
|
case wxTEXT_ALIGNMENT_JUSTIFIED:
|
|
return wxT("justify");
|
|
default:
|
|
return wxT("left");
|
|
}
|
|
}
|
|
|
|
void wxRichTextHTMLHandler::WriteImage(wxRichTextImage* image, wxOutputStream& stream)
|
|
{
|
|
wxTextOutputStream str(stream);
|
|
|
|
str << wxT("<img src=\"");
|
|
|
|
#if wxUSE_FILESYSTEM
|
|
if (GetFlags() & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY)
|
|
{
|
|
#if 0
|
|
if (!image->GetImage().IsOk() && image->GetImageBlock().GetData())
|
|
image->LoadFromBlock();
|
|
if (image->GetImage().IsOk() && !image->GetImageBlock().GetData())
|
|
image->MakeBlock();
|
|
#endif
|
|
|
|
if (image->GetImageBlock().IsOk())
|
|
{
|
|
wxImage img;
|
|
image->GetImageBlock().Load(img);
|
|
if (img.IsOk())
|
|
{
|
|
wxString ext(image->GetImageBlock().GetExtension());
|
|
wxString tempFilename(wxString::Format(wxT("image%d.%s"), sm_fileCounter, ext.c_str()));
|
|
wxMemoryFSHandler::AddFile(tempFilename, img, image->GetImageBlock().GetImageType());
|
|
|
|
m_imageLocations.Add(tempFilename);
|
|
|
|
str << wxT("memory:") << tempFilename;
|
|
}
|
|
}
|
|
else
|
|
str << wxT("memory:?");
|
|
|
|
sm_fileCounter ++;
|
|
}
|
|
else if (GetFlags() & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_FILES)
|
|
{
|
|
#if 0
|
|
if (!image->GetImage().IsOk() && image->GetImageBlock().GetData())
|
|
image->LoadFromBlock();
|
|
if (image->GetImage().IsOk() && !image->GetImageBlock().GetData())
|
|
image->MakeBlock();
|
|
#endif
|
|
|
|
if (image->GetImageBlock().IsOk())
|
|
{
|
|
wxString tempDir(GetTempDir());
|
|
if (tempDir.IsEmpty())
|
|
tempDir = wxFileName::GetTempDir();
|
|
|
|
wxString ext(image->GetImageBlock().GetExtension());
|
|
wxString tempFilename(wxString::Format(wxT("%s/image%d.%s"), tempDir.c_str(), sm_fileCounter, ext.c_str()));
|
|
image->GetImageBlock().Write(tempFilename);
|
|
|
|
m_imageLocations.Add(tempFilename);
|
|
|
|
str << wxFileSystem::FileNameToURL(tempFilename);
|
|
}
|
|
else
|
|
str << wxT("file:?");
|
|
|
|
sm_fileCounter ++;
|
|
}
|
|
else // if (GetFlags() & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_BASE64) // this is implied
|
|
#endif
|
|
{
|
|
str << wxT("data:");
|
|
str << GetMimeType(image->GetImageBlock().GetImageType());
|
|
str << wxT(";base64,");
|
|
#if 0
|
|
if (image->GetImage().IsOk() && !image->GetImageBlock().GetData())
|
|
image->MakeBlock();
|
|
#endif
|
|
if (image->GetImageBlock().IsOk())
|
|
{
|
|
wxChar* data = b64enc( image->GetImageBlock().GetData(), image->GetImageBlock().GetDataSize() );
|
|
str << data;
|
|
|
|
delete[] data;
|
|
}
|
|
}
|
|
|
|
str << wxT("\" />");
|
|
}
|
|
|
|
long wxRichTextHTMLHandler::PtToSize(long size)
|
|
{
|
|
int i;
|
|
int len = m_fontSizeMapping.GetCount();
|
|
for (i = 0; i < len; i++)
|
|
if (size <= m_fontSizeMapping[i])
|
|
return i+1;
|
|
return 7;
|
|
}
|
|
|
|
wxString wxRichTextHTMLHandler::SymbolicIndent(long indent)
|
|
{
|
|
wxString in;
|
|
for(;indent > 0; indent -= 20)
|
|
in.Append( wxT(" ") );
|
|
return in;
|
|
}
|
|
|
|
const wxChar* wxRichTextHTMLHandler::GetMimeType(int imageType)
|
|
{
|
|
switch(imageType)
|
|
{
|
|
case wxBITMAP_TYPE_BMP:
|
|
return wxT("image/bmp");
|
|
case wxBITMAP_TYPE_TIFF:
|
|
return wxT("image/tiff");
|
|
case wxBITMAP_TYPE_GIF:
|
|
return wxT("image/gif");
|
|
case wxBITMAP_TYPE_PNG:
|
|
return wxT("image/png");
|
|
case wxBITMAP_TYPE_JPEG:
|
|
return wxT("image/jpeg");
|
|
default:
|
|
return wxT("image/unknown");
|
|
}
|
|
}
|
|
|
|
// exim-style base64 encoder
|
|
wxChar* wxRichTextHTMLHandler::b64enc( unsigned char* input, size_t in_len )
|
|
{
|
|
// elements of enc64 array must be 8 bit values
|
|
// otherwise encoder will fail
|
|
// hmmm.. Does wxT macro define a char as 16 bit value
|
|
// when compiling with UNICODE option?
|
|
static const wxChar enc64[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
|
wxChar* output = new wxChar[4*((in_len+2)/3)+1];
|
|
wxChar* p = output;
|
|
|
|
while( in_len-- > 0 )
|
|
{
|
|
register wxChar a, b;
|
|
|
|
a = *input++;
|
|
|
|
*p++ = enc64[ (a >> 2) & 0x3f ];
|
|
|
|
if( in_len-- == 0 )
|
|
{
|
|
*p++ = enc64[ (a << 4 ) & 0x30 ];
|
|
*p++ = '=';
|
|
*p++ = '=';
|
|
break;
|
|
}
|
|
|
|
b = *input++;
|
|
|
|
*p++ = enc64[(( a << 4 ) | ((b >> 4) &0xf )) & 0x3f];
|
|
|
|
if( in_len-- == 0 )
|
|
{
|
|
*p++ = enc64[ (b << 2) & 0x3f ];
|
|
*p++ = '=';
|
|
break;
|
|
}
|
|
|
|
a = *input++;
|
|
|
|
*p++ = enc64[ ((( b << 2 ) & 0x3f ) | ((a >> 6)& 0x3)) & 0x3f ];
|
|
|
|
*p++ = enc64[ a & 0x3f ];
|
|
}
|
|
*p = 0;
|
|
|
|
return output;
|
|
}
|
|
#endif
|
|
// wxUSE_STREAMS
|
|
|
|
/// Delete the in-memory or temporary files generated by the last operation
|
|
bool wxRichTextHTMLHandler::DeleteTemporaryImages()
|
|
{
|
|
return DeleteTemporaryImages(GetFlags(), m_imageLocations);
|
|
}
|
|
|
|
/// Delete the in-memory or temporary files generated by the last operation
|
|
bool wxRichTextHTMLHandler::DeleteTemporaryImages(int flags, const wxArrayString& imageLocations)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < imageLocations.GetCount(); i++)
|
|
{
|
|
wxString location = imageLocations[i];
|
|
|
|
if (flags & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY)
|
|
{
|
|
#if wxUSE_FILESYSTEM
|
|
wxMemoryFSHandler::RemoveFile(location);
|
|
#endif
|
|
}
|
|
else if (flags & wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_FILES)
|
|
{
|
|
if (wxFileExists(location))
|
|
wxRemoveFile(location);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#endif
|
|
// wxUSE_RICHTEXT
|
|
|