From 68a73dff4207ce8959c56692ef7de9339771c58c Mon Sep 17 00:00:00 2001 From: cxl Date: Sun, 19 Jul 2009 13:12:18 +0000 Subject: [PATCH] Draw: headless draw final milestone reached git-svn-id: svn://ultimatepp.org/upp/trunk@1436 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/CtrlCore/Ctrl.cpp | 21 +- uppsrc/CtrlCore/CtrlCore.h | 7 + uppsrc/CtrlCore/CtrlCore.upp | 26 +- uppsrc/{RichText => CtrlCore}/EncodeRTF.cpp | 1326 +++++------ uppsrc/CtrlCore/ImageWin32.cpp | 8 +- uppsrc/CtrlCore/ImageX11.cpp | 872 ++++---- uppsrc/{RichText => CtrlCore}/ParseRTF.cpp | 2228 +++++++++---------- uppsrc/CtrlCore/SystemDraw.cpp | 142 +- uppsrc/CtrlCore/init | 3 +- uppsrc/CtrlLib/CtrlLib.h | 1 - uppsrc/CtrlLib/CtrlLib.upp | 3 +- uppsrc/CtrlLib/init | 3 +- uppsrc/Draw/Draw.h | 46 + uppsrc/Draw/Draw.upp | 15 +- uppsrc/Draw/Image.cpp | 1417 ++++++------ uppsrc/Draw/Image.h | 688 +++--- uppsrc/Draw/ImageAnyDraw.cpp | 164 ++ uppsrc/Painter/DrawOp.cpp | 17 + uppsrc/Painter/FontX11.cpp | 9 +- uppsrc/Painter/Painter.upp | 3 +- uppsrc/RichText/Object.cpp | 4 +- uppsrc/RichText/RichImage.icpp | 32 +- uppsrc/RichText/RichText.h | 10 +- uppsrc/RichText/RichText.upp | 8 +- uppsrc/RichText/Util.cpp | 17 +- uppsrc/RichText/init | 4 +- uppsrc/ide/Browser/Item.cpp | 356 +-- 27 files changed, 3902 insertions(+), 3528 deletions(-) rename uppsrc/{RichText => CtrlCore}/EncodeRTF.cpp (96%) rename uppsrc/{RichText => CtrlCore}/ParseRTF.cpp (96%) create mode 100644 uppsrc/Draw/ImageAnyDraw.cpp diff --git a/uppsrc/CtrlCore/Ctrl.cpp b/uppsrc/CtrlCore/Ctrl.cpp index 9cf21269a..a93214717 100644 --- a/uppsrc/CtrlCore/Ctrl.cpp +++ b/uppsrc/CtrlCore/Ctrl.cpp @@ -749,15 +749,23 @@ const char *Ctrl::GetZoomText() Size Ctrl::Dsize; Size Ctrl::Csize; +void InitRichTextZoom() +{ + SetRichTextStdScreenZoom(Ctrl::HorzLayoutZoom(96), 600); +} + inline void Ctrl::Csizeinit() { GuiLock __; - if(Csize.cx == 0) - Csize = GetTextSize(sZoomText, StdFont()); - if(Dsize.cx == 0) - Dsize = Size(99, 13); - Csize.cx = max(Csize.cx, Dsize.cx); - Csize.cy = max(Csize.cy, Dsize.cy); + if(Csize.cx == 0 || Dsize.cx == 0) { + if(Csize.cx == 0) + Csize = GetTextSize(sZoomText, StdFont()); + if(Dsize.cx == 0) + Dsize = Size(99, 13); + Csize.cx = max(Csize.cx, Dsize.cx); + Csize.cy = max(Csize.cy, Dsize.cy); + InitRichTextZoom(); + } } void Ctrl::SetZoomSize(Size sz, Size bsz) @@ -765,6 +773,7 @@ void Ctrl::SetZoomSize(Size sz, Size bsz) GuiLock __; Csize = sz; Dsize = bsz; + } void Ctrl::NoLayoutZoom() diff --git a/uppsrc/CtrlCore/CtrlCore.h b/uppsrc/CtrlCore/CtrlCore.h index 805d1613d..476827d21 100644 --- a/uppsrc/CtrlCore/CtrlCore.h +++ b/uppsrc/CtrlCore/CtrlCore.h @@ -1,6 +1,8 @@ #ifndef CTRLCORE_H #define CTRLCORE_H +#include + #include "SystemDraw.h" NAMESPACE_UPP @@ -1693,6 +1695,11 @@ inline void WriteClipboardImage(const Image& img) bool (*&DisplayErrorFn())(const Value& v); inline bool DisplayError(const Value& v) { return DisplayErrorFn()(v); } +void EncodeRTF(Stream& stream, const RichText& richtext, byte charset); +String EncodeRTF(const RichText& richtext, byte charset); +String EncodeRTF(const RichText& richtext); +RichText ParseRTF(const char *rtf); + #ifdef PLATFORM_WIN32 Vector& coreCmdLine__(); diff --git a/uppsrc/CtrlCore/CtrlCore.upp b/uppsrc/CtrlCore/CtrlCore.upp index 37bec5c00..349a9b36c 100644 --- a/uppsrc/CtrlCore/CtrlCore.upp +++ b/uppsrc/CtrlCore/CtrlCore.upp @@ -2,10 +2,31 @@ description "GUI core system\377B0,0,255"; uses Draw, - plugin\bmp; + plugin\bmp, + RichText; library(WIN32 !MSC8ARM) "advapi32 comdlg32 comctl32"; +library((LINUX | BSD) & !NOGTK) "gtk-x11-2.0 gdk-x11-2.0 atk-1.0 gdk_pixbuf-2.0 m pangocairo-1.0 fontconfig Xext Xrender Xinerama Xi Xrandr Xcursor Xfixes pango-1.0 cairo X11 gobject-2.0 gmodule-2.0 glib-2.0"; + +library(WIN32 !MSC8ARM) "user32 gdi32"; + +library(LINUX) X11; + +library(LINUX) dl; + +library(LINUX !XLFD) Xft; + +library(BSD) "X11 Xau Xdmcp"; + +library(BSD !XLFD) "Xft fontconfig Xrender freetype expat"; + +library(LINUX !XLFD !SHARED) "fontconfig Xrender freetype expat"; + +library(OSX11) "X11 Xft fontconfig Xrender freetype expat"; + +library(FREEBSD) xcb; + file SystemDraw readonly separator, DrawWin32.h, @@ -65,6 +86,9 @@ file X11App.cpp, X11DHCtrl.cpp, X11Event.i, + "RTF support" readonly separator, + ParseRTF.cpp, + EncodeRTF.cpp, Info readonly separator, src.tpp, srcdoc.tpp, diff --git a/uppsrc/RichText/EncodeRTF.cpp b/uppsrc/CtrlCore/EncodeRTF.cpp similarity index 96% rename from uppsrc/RichText/EncodeRTF.cpp rename to uppsrc/CtrlCore/EncodeRTF.cpp index e9eeacde2..8603474b6 100644 --- a/uppsrc/RichText/EncodeRTF.cpp +++ b/uppsrc/CtrlCore/EncodeRTF.cpp @@ -1,663 +1,663 @@ -#include "RichText.h" - -#define LLOG(x) - -#include - -NAMESPACE_UPP - -static int GetParaHeight(const Array& parts) -{ - int ht = 0; - for(int i = 0; i < parts.GetCount(); i++) { - int pht = 0; - const RichPara::Part& part = parts[i]; - if(part.object) - pht = part.object.GetSize().cy; - else if(part.field) - pht = GetParaHeight(part.fieldpart); - else - pht = tabs(part.format.GetHeight()); - if(pht > ht) - ht = pht; - } - return ht; -} - -class RTFEncoder { -public: - RTFEncoder(Stream& stream, const RichText& richtext, byte charset); - - void Run(); - -private: - void FacesAddFormat(const RichPara::CharFormat& format); - void GetFaces(); - void GetTxtFaces(const RichTxt& txt); - - void PutHeader(); - void PutDocument(); - void PutTxt(const RichTxt& txt, int nesting, int dot_width); - void PutTable(const RichTable& table, int nesting, int dot_width); - void PutParts(const Array& parts, - RichPara::CharFormat& base, int bpart, int boff, int epart, int eoff); - - void Begin() { stream.Put('{'); } - void Begin(const char *cmd) { Begin(); Command(cmd); } - void Begin(const char *cmd, int param) { Begin(); Command(cmd, param); } - void End() { stream.Put('}'); } - - void Command(const char *cmd); - void Command(const char *cmd, int param); - void Space() { stream.Put(' '); } - void PutText(const char *text); - void PutObject(const RichObject& object); - void PutTabs(const Vector& tabs); - void PutBinHex(const byte *data, int count); - void PutBinHex(const String& s) { PutBinHex(s, s.GetLength()); } - - bool PutParaFormat(const RichPara::Format& pf, const RichPara::Format& difpf); - bool PutCharFormat(const RichPara::CharFormat& cf, const RichPara::CharFormat& difcf, bool pn); - - struct Group; - - friend struct Group; - - struct Group { - Group(RTFEncoder *owner) : owner(owner) { owner->Begin(); } - Group(RTFEncoder *owner, const char *cmd) : owner(owner) { owner->Begin(cmd); } - Group(RTFEncoder *owner, const char *cmd, int param) : owner(owner) { owner->Begin(cmd, param); } - ~Group() { owner->End(); } - RTFEncoder *owner; - }; - -private: - Stream& stream; - const RichText& richtext; - byte charset; - - RichPara::CharFormat charfmt; - RichPara::Format parafmt; - Uuid oldstyle; - int old_ht; - int para_ht; - - Index used_faces; - enum { SYMBOL_INDEX = 1, WINGDINGS_INDEX = 2 }; - VectorMap used_ink, used_paper; - Index phys_colors; - Index styleid; -}; - -void EncodeRTF(Stream& stream, const RichText& richtext, byte charset) -{ - RTFEncoder(stream, richtext, charset).Run(); -} - -String EncodeRTF(const RichText& richtext, byte charset) -{ - StringStream out; - EncodeRTF(out, richtext, charset); - String s = out.GetResult(); - LLOG("EncodeRTF <<<<<\n" << s << "\n>>>>> EncodeRTF"); - return s; -} - -String EncodeRTF(const RichText& richtext) -{ - return EncodeRTF(richtext, GetDefaultCharset() == CHARSET_UTF8 ? GetLNGCharset(GetSystemLNG()) - : GetDefaultCharset()); -} - -RTFEncoder::RTFEncoder(Stream& stream, const RichText& richtext, byte charset) -: stream(stream) -, richtext(richtext) -, charset(charset) -{ - for(int i = 0; i < richtext.GetStyleCount(); i++) - styleid.Add(richtext.GetStyleId(i)); -} - -void RTFEncoder::Run() -{ - GetFaces(); - Group docgrp(this, "rtf"); - PutHeader(); - PutDocument(); -} - -void RTFEncoder::FacesAddFormat(const RichPara::CharFormat& format) -{ - used_faces.FindAdd(format.GetFace()); - if(used_ink.Find(format.ink) < 0) { - Color i(format.ink.GetR(), format.ink.GetG(), format.ink.GetB()); - int x = used_ink.Get(i, -1); - if(x < 0) - x = phys_colors.FindAdd(i); - used_ink.Add(format.ink, x); - } - if(used_paper.Find(format.paper) < 0) { - Color p(format.paper.GetR(), format.paper.GetG(), format.paper.GetB()); - int x = used_paper.Get(p, -1); - if(x < 0) - x = phys_colors.FindAdd(p); - used_paper.Add(format.paper, x); - } -} - -void RTFEncoder::GetFaces() -{ - used_faces.Add(Font::ARIAL); // default font -#ifdef PLATFORM_WIN32 - used_faces.Add(Font::SYMBOL); // used for bullets - used_faces.Add(Font::WINGDINGS); // used for bullets -#endif - phys_colors.Add(Null); - used_ink.Add(Null, 0); - used_paper.Add(Null, 0); - used_ink.Add(Black(), 0); - used_paper.Add(White(), 0); - GetTxtFaces(richtext); - for(int i = 0; i < richtext.GetStyleCount(); i++) - FacesAddFormat(richtext.GetStyle(i).format); -} - -void RTFEncoder::GetTxtFaces(const RichTxt& rt) -{ - for(int i = 0; i < rt.GetPartCount(); i++) { - if(rt.IsTable(i)) { - const RichTable& table = rt.GetTable(i); - const RichTable::Format& tfmt = table.GetFormat(); - phys_colors.FindAdd(tfmt.framecolor); - phys_colors.FindAdd(tfmt.gridcolor); - for(int r = 0; r < table.GetRows(); r++) - for(int c = 0; c < table.GetColumns(); c++) { - const RichCell& cell = table.cell[r][c]; - phys_colors.FindAdd(cell.format.color); - phys_colors.FindAdd(cell.format.bordercolor); - GetTxtFaces(cell.text); - } - } - else { - const RichPara& para = rt.Get(i, richtext.GetStyles()); - FacesAddFormat(para.format); - for(int p = 0; p < para.part.GetCount(); p++) { - const RichPara::Part& part = para.part[p]; - if(part.IsText()) - FacesAddFormat(part.format); - } - } - } -} - -void RTFEncoder::Command(const char *cmd) -{ - stream.Put('\\'); - stream.Put(cmd); -} - -void RTFEncoder::Command(const char *cmd, int param) -{ - stream.Put('\\'); - stream.Put(cmd); - stream.Put(IntStr(param)); -} - -void RTFEncoder::PutText(const char *text) -{ - while(*text) { - if(*text == '{' || *text == '}' || *text == '\\') - stream.Put('\\'); - stream.Put(*text++); - } -} - -void RTFEncoder::PutBinHex(const byte *b, int count) -{ - enum { BLOCK = 32 }; - for(int l = count; l > 0; l -= BLOCK) { - stream.PutCrLf(); - for(const byte *e = b + min(l, BLOCK); b < e; b++) { - static const char binhex[] = "0123456789abcdef"; - stream.Put(binhex[*b >> 4]); - stream.Put(binhex[*b & 15]); - } - } -} - -bool RTFEncoder::PutCharFormat(const RichPara::CharFormat& cf, const RichPara::CharFormat& difcf, bool pn) -{ - int64 pos = stream.GetPos(); - int pn2 = (pn ? 0 : 2); - bool f; - int t; - if(cf.GetFace() != difcf.GetFace()) - Command("pnf" + pn2, used_faces.Find(cf.GetFace())); - if((t = DotPoints(2 * tabs(cf.GetHeight()))) != DotPoints(2 * tabs(difcf.GetHeight()))) - Command("pnfs" + pn2, t); - if(!pn && dword(t = cf.sscript) != difcf.sscript) - Command(t == 0 ? "nosupersub" : t == 1 ? "super" : "sub"); - if((f = cf.IsBold()) != difcf.IsBold()) Command((f ? "pnb" : "pnb0") + pn2); - if((f = cf.IsItalic()) != difcf.IsItalic()) Command((f ? "pni" : "pni0") + pn2); - if((f = cf.IsUnderline()) != difcf.IsUnderline()) Command((f ? "pnul" : "pnul0") + pn2); - if((f = cf.IsStrikeout()) != difcf.IsStrikeout()) Command((f ? "pnstrike" : "pnstrike0") + pn2); - if((f = cf.capitals) != difcf.capitals) Command((f ? "pncaps" : "pncaps0") + pn2); - if((t = used_ink.Get(cf.ink)) != used_ink.Get(difcf.ink)) Command("pncf" + pn2, t); - if((t = used_paper.Get(cf.paper)) != used_paper.Get(difcf.paper)) Command("pncb" + pn2, t); -#ifdef PLATFORM_WIN32 //zapoznamkoval Fidler kdyz chtel zkompilovat pod Linuxem... - if(!pn && cf.language != difcf.language) Command("lang", GetLanguageLCID(cf.language)); -#endif - // todo: link - return stream.GetPos() != pos; -} - -void RTFEncoder::PutObject(const RichObject& object) -{ -#ifdef PLATFORM_WIN32 -#ifndef PLATFORM_WINCE - Size log_size = object.GetPixelSize(), out_size = object.GetSize(); - if(log_size.cx <= 0 || log_size.cy <= 0) log_size = out_size; -// Size scale = out_size * 100 / log_size; - Group pict_grp(this, "pict"); - Command("picw", log_size.cx); - Command("pich", log_size.cy); - Command("picwgoal", DotTwips(out_size.cx)); - Command("pichgoal", DotTwips(out_size.cy)); -// Command("picscalex", scale.cx); -// Command("picscaley", scale.cy); - - if(object.GetTypeName() == "PING") { - Command("pngblip"); - PutBinHex(object.GetData()); - } - else { - Command("wmetafile", 8); - WinMetaFileDraw wmd(log_size.cx, log_size.cy); - object.Paint(wmd, log_size); - WinMetaFile wmf = wmd.Close(); - HENHMETAFILE hemf = wmf.GetHEMF(); - int size = GetWinMetaFileBits(hemf, 0, 0, MM_ANISOTROPIC, ScreenHDC()); - if(size > 0) { - Buffer buffer(size); - GetWinMetaFileBits(hemf, size, buffer, MM_ANISOTROPIC, ScreenHDC()); - PutBinHex(buffer, size); - } - } -#endif -#endif -} - -bool RTFEncoder::PutParaFormat(const RichPara::Format& pf, const RichPara::Format& difpf) -{ - int64 pos = stream.GetPos(); - if(pf.align != difpf.align) - switch(pf.align) { - case ALIGN_NULL: - case ALIGN_LEFT: Command("ql"); break; - case ALIGN_CENTER: Command("qc"); break; - case ALIGN_RIGHT: Command("qr"); break; - case ALIGN_JUSTIFY: Command("qj"); break; - default: NEVER(); - } - int oind = difpf.indent, olm = difpf.lm; - if(difpf.bullet != RichPara::BULLET_NONE) { - olm += oind; - oind = -oind; - } - int nind = pf.indent, nlm = pf.lm; - if(pf.bullet != RichPara::BULLET_NONE) { - nlm += nind; - nind = -nind; - } - if(nind != oind) Command("fi", DotTwips(nind)); - if(nlm != olm) Command("li", DotTwips(nlm)); - if(pf.rm != difpf.rm) Command("ri", DotTwips(pf.rm)); - if(pf.newpage) - Command("pagebb"); - if(pf.before != difpf.before) Command("sb", DotTwips(pf.before)); - if(pf.after != difpf.after) Command("sa", DotTwips(pf.after)); - if(pf.tab != difpf.tab) PutTabs(pf.tab); - return stream.GetPos() != pos; -} - -void RTFEncoder::PutTabs(const Vector& tabs) -{ - for(int i = 0; i < tabs.GetCount(); i++) { - RichPara::Tab t = tabs[i]; - switch(t.align) { - case ALIGN_NULL: - case ALIGN_LEFT: break; - case ALIGN_CENTER: Command("tqc"); break; - case ALIGN_RIGHT: Command("tqr"); break; - default: NEVER(); - } - switch(t.fillchar) { - case 0: break; - case 1: Command("tldot"); break; - case 2: Command("tlhyph"); break; - case 3: Command("tlul"); break; - default: NEVER(); - } - Command("tx", DotTwips(t.pos)); - } -} - -void RTFEncoder::PutParts(const Array& parts, - RichPara::CharFormat& base, int bpart, int boff, int epart, int eoff) -{ - if(epart >= parts.GetCount()) { - epart = parts.GetCount() - 1; - eoff = INT_MAX; - } - ASSERT(boff >= 0 && bpart >= 0); - for(int p = bpart; p <= epart; p++) { - const RichPara::Part& part = parts[p]; - if(part.IsText()) { - WString px = part.text; - if(p == epart && px.GetLength() > eoff) - px.Trim(eoff); - if(p == bpart) - px.Remove(0, boff); - if(!px.IsEmpty()) { - if(PutCharFormat(part.format, base, false) || p == 0) - Space(); - base = part.format; - PutText(FromUnicode(px, charset)); - } - } - else if(part.object) - PutObject(part.object); - } - -} - -void RTFEncoder::PutHeader() -{ - static const short ansicpg[][2] = { - { CHARSET_WIN1250, 1250 }, - { CHARSET_WIN1251, 1251 }, - { CHARSET_WIN1252, 1252 }, - { CHARSET_WIN1253, 1253 }, - { CHARSET_WIN1254, 1254 }, - { CHARSET_WIN1255, 1255 }, - { CHARSET_WIN1256, 1256 }, - { CHARSET_WIN1257, 1257 }, - { CHARSET_WIN1258, 1258 }, - }; - int i; - for(i = __countof(ansicpg); --i >= 0;) - if(charset == ansicpg[i][0]) { - Command("ansicpg", ansicpg[i][1]); - break; - } - - Command("deff", 0); - { - Group ftbl(this, "fonttbl"); - for(int i = 0; i < used_faces.GetCount(); i++) { - Group fnt(this, "f", i); - int fn = used_faces[i]; - dword info = Font::GetFaceInfo(fn); -#ifdef PLATFORM_WIN32 - if(fn == Font::SYMBOL) - Command("ftech"); - else -#endif - if(info & Font::FIXEDPITCH) - Command("fmodern"); - else if(fn == Font::ROMAN) - Command("froman"); - else if(fn == Font::ARIAL -#ifdef PLATFORM_WIN32 - || fn == Font::TAHOMA -#endif - ) - Command("fswiss"); - Space(); - stream.Put(Font::GetFaceName(fn)); - stream.Put(';'); - } - } - - if(phys_colors.GetCount() > 1) { - Group ctbl(this, "colortbl"); - stream.Put(';'); - for(int i = 1; i < phys_colors.GetCount(); i++) { - Color rgb = phys_colors[i]; - Command("red", rgb.GetR()); - Command("green", rgb.GetG()); - Command("blue", rgb.GetB()); - stream.Put(';'); - } - } - - Begin("stylesheet"); - RichPara::CharFormat empcfmt; - RichPara::Format emppfmt; - - for(i = 0; i < richtext.GetStyleCount(); i++) { - const RichStyle& style = richtext.GetStyle(i); - Begin("s", i); - PutParaFormat(style.format, emppfmt); - PutCharFormat(style.format, empcfmt, false); - Command("sbasedon", 222); - if(style.next != richtext.GetStyleId(i)) - Command("snext", styleid.Find(style.next)); - Space(); - for(const char *n = style.name; *n; n++) - stream.Put(*n == ';' ? '_' : *n); - stream.Put(';'); - End(); - } - End(); -} - -void RTFEncoder::PutTable(const RichTable& table, int nesting, int dot_width) -{ - Vector vspan_counts; - const RichTable::Format& tfmt = table.GetFormat(); - Vector column_pos; - column_pos.SetCount(tfmt.column.GetCount() + 1); - column_pos[0] = tfmt.lm; - int sum = 0; - for(int c = 0; c < tfmt.column.GetCount(); c++) - sum += tfmt.column[c]; - int rem_width = dot_width - tfmt.lm - tfmt.rm; - for(int c = 0; c < tfmt.column.GetCount(); c++) { - int part = iscale(tfmt.column[c], rem_width, max(sum, 1)); - sum -= tfmt.column[c]; - rem_width -= part; - column_pos[c + 1] = column_pos[c] + part; - } - for(int r = 0; r < table.GetRows(); r++) { - String rowfmt; - if(nesting) - rowfmt << "\\*\\nesttableprops"; - rowfmt << "\\trowd" - "\\trleft" << DotTwips(tfmt.lm) - // trbrdr[ltrbv] - ; - Vector cellindex; - Rect dflt_margin(600, 600, 600, 600); - for(int c = 0; c < table.GetColumns(); c++) { - const RichCell& cell = table.cell[r][c]; - dflt_margin.left = min(dflt_margin.left, cell.format.margin.left); - dflt_margin.top = min(dflt_margin.top, cell.format.margin.top); - dflt_margin.right = min(dflt_margin.right, cell.format.margin.right); - dflt_margin.bottom = min(dflt_margin.bottom, cell.format.margin.bottom); - c += cell.hspan; - } -/* - rowfmt << - "\\trpaddl" << DotTwips(dflt_margin.left) << "\\trpaddfl3" - "\\trpaddt" << DotTwips(dflt_margin.top) << "\\trpaddft3" - "\\trpaddr" << DotTwips(dflt_margin.right) << "\\trpaddfr3" - "\\trpaddb" << DotTwips(dflt_margin.bottom) << "\\trpaddfb3"; -*/ - for(int c = 0; c < table.GetColumns(); c++) { - const RichCell& cell = table.cell[r][c]; -/* - if(cell.format.margin.left != dflt_margin.left) - rowfmt << "\\clpadl" << DotTwips(cell.format.margin.left) << "\\clpadfl3"; - if(cell.format.margin.top != dflt_margin.top) - rowfmt << "\\clpadt" << DotTwips(cell.format.margin.top) << "\\clpadft3"; - if(cell.format.margin.right != dflt_margin.right) - rowfmt << "\\clpadr" << DotTwips(cell.format.margin.right) << "\\clpadfr3"; - if(cell.format.margin.bottom != dflt_margin.bottom) - rowfmt << "\\clpadb" << DotTwips(cell.format.margin.bottom) << "\\clpadfb3"; -*/ - switch(cell.format.align) { - case ALIGN_TOP: rowfmt << "\\clvertalt"; break; - default: - case ALIGN_CENTER: rowfmt << "\\clvertalc"; break; - case ALIGN_BOTTOM: rowfmt << "\\clvertalb"; break; - } - cellindex.Add(c); - if(cell.hspan) - c += cell.hspan; - int cell_end = column_pos[c + 1]; - if(cell.vspan) { - vspan_counts.At(c, 0) = cell.vspan; - rowfmt << "\\clvmgf"; - } - else if(c < vspan_counts.GetCount() && vspan_counts[c] > 0) - rowfmt << "\\clvmrg"; - if(!IsNull(cell.format.color)) - rowfmt << "\\clcbpat" << phys_colors.Find(cell.format.color); - rowfmt << "\\cellx" << DotTwips(cell_end); - } - Begin(); - Command("pard"); - Command("intbl"); - parafmt = RichPara::Format(); - charfmt = RichPara::CharFormat(); - if(nesting) - Command("itap", nesting + 1); - if(!nesting) - stream.Put(rowfmt); - for(int c = 0; c < cellindex.GetCount(); c++) { - int cx = cellindex[c]; - const RichCell& cell = table.cell[r][cx]; - int cell_wd = column_pos[cx + cell.hspan + 1] - column_pos[cx]; - PutTxt(cell.text, nesting + 1, cell_wd); - Command(nesting ? "nestcell" : "cell"); - } - stream.Put(rowfmt); - Command(nesting ? "nestrow" : "row"); - End(); - } -} - -void RTFEncoder::PutTxt(const RichTxt& txt, int nesting, int dot_width) -{ - for(int i = 0; i < txt.GetPartCount(); i++) { - if(txt.IsTable(i)) - PutTable(txt.GetTable(i), nesting, dot_width); - else { - const RichPara& para = txt.Get(i, richtext.GetStyles()); - Uuid pstyle = txt.GetParaStyle(i); - int para_ht = GetParaHeight(para.part); - int first_part = 0, first_ind = 0; - bool hdiff = (para.format.bullet != RichPara::BULLET_NONE - && para.format.bullet != RichPara::BULLET_TEXT && para_ht != para_ht); - if(pstyle != oldstyle - || para.format.bullet != parafmt.bullet || para.format.bullet == RichPara::BULLET_TEXT - || hdiff || para.format.tab != parafmt.tab || para.format.newpage || parafmt.newpage) { - Command("s", styleid.Find(pstyle)); - oldstyle = pstyle; - parafmt = richtext.GetStyle(pstyle).format; - Command("pard"); - if(nesting) - Command("intbl"); - if(nesting > 1) - Command("itap", nesting); - parafmt = RichPara::Format(); - para_ht = 0; - } - if(para.format.bullet == RichPara::BULLET_TEXT) { - int epart = 0, eoff = 0; - while(epart < para.part.GetCount() && (eoff = para.part[epart].text.Find('\t')) < 0) - epart++; - - RichPara::CharFormat rcf = charfmt; - rcf.Height(0); - Begin("pntext"); - PutParts(para.part, rcf, 0, 0, epart, eoff); - stream.Put('\t'); - End(); - - Begin("*\\pn"); - Command("pnhang"); - Command("pnql"); - rcf = charfmt; - if(epart > 0 || eoff > 0) - PutCharFormat(para.part[0].format, rcf, true); - Begin("pntxta"); - End(); - Begin("pntxtb"); - Space(); - PutParts(para.part, rcf, 0, 0, epart, eoff); - stream.Put('\t'); - End(); - End(); - } - else if(para.format.bullet != RichPara::BULLET_NONE) { - int sym_face = SYMBOL_INDEX; - byte sym_char = 0xB7; - - switch(para.format.bullet) { - default: - NEVER(); - - case RichPara::BULLET_ROUND: sym_face = SYMBOL_INDEX; sym_char = 0xB7; break; - case RichPara::BULLET_ROUNDWHITE: sym_face = WINGDINGS_INDEX; sym_char = 0xA1; break; - case RichPara::BULLET_BOX: sym_face = WINGDINGS_INDEX; sym_char = 'n'; break; - case RichPara::BULLET_BOXWHITE: sym_face = WINGDINGS_INDEX; sym_char = 'o'; break; - } - - Begin("pntext"); - // Command("tqr"); - // Command("tx", DotTwips(para.format.indent)); - // Command("qr"); - Command("f", sym_face); - Command("fs", DotPoints(2 * para_ht)); - Space(); - stream.Put(sym_char); - stream.Put('\t'); - End(); - - Begin("*\\pn"); - Command("pnlvlblt"); - Command("pnf", sym_face); - Command("pnfs", DotPoints(2 * para_ht)); - Command("pnql"); - Begin("pntxtb"); - Space(); - stream.Put(sym_char); - // stream.Put('\t'); - End(); - Begin("pntxta"); - End(); - End(); - } - PutParaFormat(para.format, parafmt); - para_ht = para_ht; - parafmt = para.format; - PutParts(para.part, charfmt, first_part, first_ind, para.part.GetCount(), 0); - if(i + 1 < txt.GetPartCount()) - Command("par"); - } - } -} - -void RTFEncoder::PutDocument() -{ - charfmt.Height(PointDots(0)); - charfmt.language = 0; - old_ht = DotPoints(2 * tabs(charfmt.GetHeight())); - para_ht = 0; - oldstyle = Uuid::Create(); - PutTxt(richtext, 0, 3600); -} - -END_UPP_NAMESPACE +#include "CtrlCore.h" + +#define LLOG(x) + +#include + +NAMESPACE_UPP + +static int GetParaHeight(const Array& parts) +{ + int ht = 0; + for(int i = 0; i < parts.GetCount(); i++) { + int pht = 0; + const RichPara::Part& part = parts[i]; + if(part.object) + pht = part.object.GetSize().cy; + else if(part.field) + pht = GetParaHeight(part.fieldpart); + else + pht = tabs(part.format.GetHeight()); + if(pht > ht) + ht = pht; + } + return ht; +} + +class RTFEncoder { +public: + RTFEncoder(Stream& stream, const RichText& richtext, byte charset); + + void Run(); + +private: + void FacesAddFormat(const RichPara::CharFormat& format); + void GetFaces(); + void GetTxtFaces(const RichTxt& txt); + + void PutHeader(); + void PutDocument(); + void PutTxt(const RichTxt& txt, int nesting, int dot_width); + void PutTable(const RichTable& table, int nesting, int dot_width); + void PutParts(const Array& parts, + RichPara::CharFormat& base, int bpart, int boff, int epart, int eoff); + + void Begin() { stream.Put('{'); } + void Begin(const char *cmd) { Begin(); Command(cmd); } + void Begin(const char *cmd, int param) { Begin(); Command(cmd, param); } + void End() { stream.Put('}'); } + + void Command(const char *cmd); + void Command(const char *cmd, int param); + void Space() { stream.Put(' '); } + void PutText(const char *text); + void PutObject(const RichObject& object); + void PutTabs(const Vector& tabs); + void PutBinHex(const byte *data, int count); + void PutBinHex(const String& s) { PutBinHex(s, s.GetLength()); } + + bool PutParaFormat(const RichPara::Format& pf, const RichPara::Format& difpf); + bool PutCharFormat(const RichPara::CharFormat& cf, const RichPara::CharFormat& difcf, bool pn); + + struct Group; + + friend struct Group; + + struct Group { + Group(RTFEncoder *owner) : owner(owner) { owner->Begin(); } + Group(RTFEncoder *owner, const char *cmd) : owner(owner) { owner->Begin(cmd); } + Group(RTFEncoder *owner, const char *cmd, int param) : owner(owner) { owner->Begin(cmd, param); } + ~Group() { owner->End(); } + RTFEncoder *owner; + }; + +private: + Stream& stream; + const RichText& richtext; + byte charset; + + RichPara::CharFormat charfmt; + RichPara::Format parafmt; + Uuid oldstyle; + int old_ht; + int para_ht; + + Index used_faces; + enum { SYMBOL_INDEX = 1, WINGDINGS_INDEX = 2 }; + VectorMap used_ink, used_paper; + Index phys_colors; + Index styleid; +}; + +void EncodeRTF(Stream& stream, const RichText& richtext, byte charset) +{ + RTFEncoder(stream, richtext, charset).Run(); +} + +String EncodeRTF(const RichText& richtext, byte charset) +{ + StringStream out; + EncodeRTF(out, richtext, charset); + String s = out.GetResult(); + LLOG("EncodeRTF <<<<<\n" << s << "\n>>>>> EncodeRTF"); + return s; +} + +String EncodeRTF(const RichText& richtext) +{ + return EncodeRTF(richtext, GetDefaultCharset() == CHARSET_UTF8 ? GetLNGCharset(GetSystemLNG()) + : GetDefaultCharset()); +} + +RTFEncoder::RTFEncoder(Stream& stream, const RichText& richtext, byte charset) +: stream(stream) +, richtext(richtext) +, charset(charset) +{ + for(int i = 0; i < richtext.GetStyleCount(); i++) + styleid.Add(richtext.GetStyleId(i)); +} + +void RTFEncoder::Run() +{ + GetFaces(); + Group docgrp(this, "rtf"); + PutHeader(); + PutDocument(); +} + +void RTFEncoder::FacesAddFormat(const RichPara::CharFormat& format) +{ + used_faces.FindAdd(format.GetFace()); + if(used_ink.Find(format.ink) < 0) { + Color i(format.ink.GetR(), format.ink.GetG(), format.ink.GetB()); + int x = used_ink.Get(i, -1); + if(x < 0) + x = phys_colors.FindAdd(i); + used_ink.Add(format.ink, x); + } + if(used_paper.Find(format.paper) < 0) { + Color p(format.paper.GetR(), format.paper.GetG(), format.paper.GetB()); + int x = used_paper.Get(p, -1); + if(x < 0) + x = phys_colors.FindAdd(p); + used_paper.Add(format.paper, x); + } +} + +void RTFEncoder::GetFaces() +{ + used_faces.Add(Font::ARIAL); // default font +#ifdef PLATFORM_WIN32 + used_faces.Add(Font::SYMBOL); // used for bullets + used_faces.Add(Font::WINGDINGS); // used for bullets +#endif + phys_colors.Add(Null); + used_ink.Add(Null, 0); + used_paper.Add(Null, 0); + used_ink.Add(Black(), 0); + used_paper.Add(White(), 0); + GetTxtFaces(richtext); + for(int i = 0; i < richtext.GetStyleCount(); i++) + FacesAddFormat(richtext.GetStyle(i).format); +} + +void RTFEncoder::GetTxtFaces(const RichTxt& rt) +{ + for(int i = 0; i < rt.GetPartCount(); i++) { + if(rt.IsTable(i)) { + const RichTable& table = rt.GetTable(i); + const RichTable::Format& tfmt = table.GetFormat(); + phys_colors.FindAdd(tfmt.framecolor); + phys_colors.FindAdd(tfmt.gridcolor); + for(int r = 0; r < table.GetRows(); r++) + for(int c = 0; c < table.GetColumns(); c++) { + const RichCell& cell = table.cell[r][c]; + phys_colors.FindAdd(cell.format.color); + phys_colors.FindAdd(cell.format.bordercolor); + GetTxtFaces(cell.text); + } + } + else { + const RichPara& para = rt.Get(i, richtext.GetStyles()); + FacesAddFormat(para.format); + for(int p = 0; p < para.part.GetCount(); p++) { + const RichPara::Part& part = para.part[p]; + if(part.IsText()) + FacesAddFormat(part.format); + } + } + } +} + +void RTFEncoder::Command(const char *cmd) +{ + stream.Put('\\'); + stream.Put(cmd); +} + +void RTFEncoder::Command(const char *cmd, int param) +{ + stream.Put('\\'); + stream.Put(cmd); + stream.Put(IntStr(param)); +} + +void RTFEncoder::PutText(const char *text) +{ + while(*text) { + if(*text == '{' || *text == '}' || *text == '\\') + stream.Put('\\'); + stream.Put(*text++); + } +} + +void RTFEncoder::PutBinHex(const byte *b, int count) +{ + enum { BLOCK = 32 }; + for(int l = count; l > 0; l -= BLOCK) { + stream.PutCrLf(); + for(const byte *e = b + min(l, BLOCK); b < e; b++) { + static const char binhex[] = "0123456789abcdef"; + stream.Put(binhex[*b >> 4]); + stream.Put(binhex[*b & 15]); + } + } +} + +bool RTFEncoder::PutCharFormat(const RichPara::CharFormat& cf, const RichPara::CharFormat& difcf, bool pn) +{ + int64 pos = stream.GetPos(); + int pn2 = (pn ? 0 : 2); + bool f; + int t; + if(cf.GetFace() != difcf.GetFace()) + Command("pnf" + pn2, used_faces.Find(cf.GetFace())); + if((t = DotPoints(2 * tabs(cf.GetHeight()))) != DotPoints(2 * tabs(difcf.GetHeight()))) + Command("pnfs" + pn2, t); + if(!pn && dword(t = cf.sscript) != difcf.sscript) + Command(t == 0 ? "nosupersub" : t == 1 ? "super" : "sub"); + if((f = cf.IsBold()) != difcf.IsBold()) Command((f ? "pnb" : "pnb0") + pn2); + if((f = cf.IsItalic()) != difcf.IsItalic()) Command((f ? "pni" : "pni0") + pn2); + if((f = cf.IsUnderline()) != difcf.IsUnderline()) Command((f ? "pnul" : "pnul0") + pn2); + if((f = cf.IsStrikeout()) != difcf.IsStrikeout()) Command((f ? "pnstrike" : "pnstrike0") + pn2); + if((f = cf.capitals) != difcf.capitals) Command((f ? "pncaps" : "pncaps0") + pn2); + if((t = used_ink.Get(cf.ink)) != used_ink.Get(difcf.ink)) Command("pncf" + pn2, t); + if((t = used_paper.Get(cf.paper)) != used_paper.Get(difcf.paper)) Command("pncb" + pn2, t); +#ifdef PLATFORM_WIN32 //zapoznamkoval Fidler kdyz chtel zkompilovat pod Linuxem... + if(!pn && cf.language != difcf.language) Command("lang", GetLanguageLCID(cf.language)); +#endif + // todo: link + return stream.GetPos() != pos; +} + +void RTFEncoder::PutObject(const RichObject& object) +{ +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + Size log_size = object.GetPixelSize(), out_size = object.GetSize(); + if(log_size.cx <= 0 || log_size.cy <= 0) log_size = out_size; +// Size scale = out_size * 100 / log_size; + Group pict_grp(this, "pict"); + Command("picw", log_size.cx); + Command("pich", log_size.cy); + Command("picwgoal", DotTwips(out_size.cx)); + Command("pichgoal", DotTwips(out_size.cy)); +// Command("picscalex", scale.cx); +// Command("picscaley", scale.cy); + + if(object.GetTypeName() == "PING") { + Command("pngblip"); + PutBinHex(object.GetData()); + } + else { + Command("wmetafile", 8); + WinMetaFileDraw wmd(log_size.cx, log_size.cy); + object.Paint(wmd, log_size); + WinMetaFile wmf = wmd.Close(); + HENHMETAFILE hemf = wmf.GetHEMF(); + int size = GetWinMetaFileBits(hemf, 0, 0, MM_ANISOTROPIC, ScreenHDC()); + if(size > 0) { + Buffer buffer(size); + GetWinMetaFileBits(hemf, size, buffer, MM_ANISOTROPIC, ScreenHDC()); + PutBinHex(buffer, size); + } + } +#endif +#endif +} + +bool RTFEncoder::PutParaFormat(const RichPara::Format& pf, const RichPara::Format& difpf) +{ + int64 pos = stream.GetPos(); + if(pf.align != difpf.align) + switch(pf.align) { + case ALIGN_NULL: + case ALIGN_LEFT: Command("ql"); break; + case ALIGN_CENTER: Command("qc"); break; + case ALIGN_RIGHT: Command("qr"); break; + case ALIGN_JUSTIFY: Command("qj"); break; + default: NEVER(); + } + int oind = difpf.indent, olm = difpf.lm; + if(difpf.bullet != RichPara::BULLET_NONE) { + olm += oind; + oind = -oind; + } + int nind = pf.indent, nlm = pf.lm; + if(pf.bullet != RichPara::BULLET_NONE) { + nlm += nind; + nind = -nind; + } + if(nind != oind) Command("fi", DotTwips(nind)); + if(nlm != olm) Command("li", DotTwips(nlm)); + if(pf.rm != difpf.rm) Command("ri", DotTwips(pf.rm)); + if(pf.newpage) + Command("pagebb"); + if(pf.before != difpf.before) Command("sb", DotTwips(pf.before)); + if(pf.after != difpf.after) Command("sa", DotTwips(pf.after)); + if(pf.tab != difpf.tab) PutTabs(pf.tab); + return stream.GetPos() != pos; +} + +void RTFEncoder::PutTabs(const Vector& tabs) +{ + for(int i = 0; i < tabs.GetCount(); i++) { + RichPara::Tab t = tabs[i]; + switch(t.align) { + case ALIGN_NULL: + case ALIGN_LEFT: break; + case ALIGN_CENTER: Command("tqc"); break; + case ALIGN_RIGHT: Command("tqr"); break; + default: NEVER(); + } + switch(t.fillchar) { + case 0: break; + case 1: Command("tldot"); break; + case 2: Command("tlhyph"); break; + case 3: Command("tlul"); break; + default: NEVER(); + } + Command("tx", DotTwips(t.pos)); + } +} + +void RTFEncoder::PutParts(const Array& parts, + RichPara::CharFormat& base, int bpart, int boff, int epart, int eoff) +{ + if(epart >= parts.GetCount()) { + epart = parts.GetCount() - 1; + eoff = INT_MAX; + } + ASSERT(boff >= 0 && bpart >= 0); + for(int p = bpart; p <= epart; p++) { + const RichPara::Part& part = parts[p]; + if(part.IsText()) { + WString px = part.text; + if(p == epart && px.GetLength() > eoff) + px.Trim(eoff); + if(p == bpart) + px.Remove(0, boff); + if(!px.IsEmpty()) { + if(PutCharFormat(part.format, base, false) || p == 0) + Space(); + base = part.format; + PutText(FromUnicode(px, charset)); + } + } + else if(part.object) + PutObject(part.object); + } + +} + +void RTFEncoder::PutHeader() +{ + static const short ansicpg[][2] = { + { CHARSET_WIN1250, 1250 }, + { CHARSET_WIN1251, 1251 }, + { CHARSET_WIN1252, 1252 }, + { CHARSET_WIN1253, 1253 }, + { CHARSET_WIN1254, 1254 }, + { CHARSET_WIN1255, 1255 }, + { CHARSET_WIN1256, 1256 }, + { CHARSET_WIN1257, 1257 }, + { CHARSET_WIN1258, 1258 }, + }; + int i; + for(i = __countof(ansicpg); --i >= 0;) + if(charset == ansicpg[i][0]) { + Command("ansicpg", ansicpg[i][1]); + break; + } + + Command("deff", 0); + { + Group ftbl(this, "fonttbl"); + for(int i = 0; i < used_faces.GetCount(); i++) { + Group fnt(this, "f", i); + int fn = used_faces[i]; + dword info = Font::GetFaceInfo(fn); +#ifdef PLATFORM_WIN32 + if(fn == Font::SYMBOL) + Command("ftech"); + else +#endif + if(info & Font::FIXEDPITCH) + Command("fmodern"); + else if(fn == Font::ROMAN) + Command("froman"); + else if(fn == Font::ARIAL +#ifdef PLATFORM_WIN32 + || fn == Font::TAHOMA +#endif + ) + Command("fswiss"); + Space(); + stream.Put(Font::GetFaceName(fn)); + stream.Put(';'); + } + } + + if(phys_colors.GetCount() > 1) { + Group ctbl(this, "colortbl"); + stream.Put(';'); + for(int i = 1; i < phys_colors.GetCount(); i++) { + Color rgb = phys_colors[i]; + Command("red", rgb.GetR()); + Command("green", rgb.GetG()); + Command("blue", rgb.GetB()); + stream.Put(';'); + } + } + + Begin("stylesheet"); + RichPara::CharFormat empcfmt; + RichPara::Format emppfmt; + + for(i = 0; i < richtext.GetStyleCount(); i++) { + const RichStyle& style = richtext.GetStyle(i); + Begin("s", i); + PutParaFormat(style.format, emppfmt); + PutCharFormat(style.format, empcfmt, false); + Command("sbasedon", 222); + if(style.next != richtext.GetStyleId(i)) + Command("snext", styleid.Find(style.next)); + Space(); + for(const char *n = style.name; *n; n++) + stream.Put(*n == ';' ? '_' : *n); + stream.Put(';'); + End(); + } + End(); +} + +void RTFEncoder::PutTable(const RichTable& table, int nesting, int dot_width) +{ + Vector vspan_counts; + const RichTable::Format& tfmt = table.GetFormat(); + Vector column_pos; + column_pos.SetCount(tfmt.column.GetCount() + 1); + column_pos[0] = tfmt.lm; + int sum = 0; + for(int c = 0; c < tfmt.column.GetCount(); c++) + sum += tfmt.column[c]; + int rem_width = dot_width - tfmt.lm - tfmt.rm; + for(int c = 0; c < tfmt.column.GetCount(); c++) { + int part = iscale(tfmt.column[c], rem_width, max(sum, 1)); + sum -= tfmt.column[c]; + rem_width -= part; + column_pos[c + 1] = column_pos[c] + part; + } + for(int r = 0; r < table.GetRows(); r++) { + String rowfmt; + if(nesting) + rowfmt << "\\*\\nesttableprops"; + rowfmt << "\\trowd" + "\\trleft" << DotTwips(tfmt.lm) + // trbrdr[ltrbv] + ; + Vector cellindex; + Rect dflt_margin(600, 600, 600, 600); + for(int c = 0; c < table.GetColumns(); c++) { + const RichCell& cell = table.cell[r][c]; + dflt_margin.left = min(dflt_margin.left, cell.format.margin.left); + dflt_margin.top = min(dflt_margin.top, cell.format.margin.top); + dflt_margin.right = min(dflt_margin.right, cell.format.margin.right); + dflt_margin.bottom = min(dflt_margin.bottom, cell.format.margin.bottom); + c += cell.hspan; + } +/* + rowfmt << + "\\trpaddl" << DotTwips(dflt_margin.left) << "\\trpaddfl3" + "\\trpaddt" << DotTwips(dflt_margin.top) << "\\trpaddft3" + "\\trpaddr" << DotTwips(dflt_margin.right) << "\\trpaddfr3" + "\\trpaddb" << DotTwips(dflt_margin.bottom) << "\\trpaddfb3"; +*/ + for(int c = 0; c < table.GetColumns(); c++) { + const RichCell& cell = table.cell[r][c]; +/* + if(cell.format.margin.left != dflt_margin.left) + rowfmt << "\\clpadl" << DotTwips(cell.format.margin.left) << "\\clpadfl3"; + if(cell.format.margin.top != dflt_margin.top) + rowfmt << "\\clpadt" << DotTwips(cell.format.margin.top) << "\\clpadft3"; + if(cell.format.margin.right != dflt_margin.right) + rowfmt << "\\clpadr" << DotTwips(cell.format.margin.right) << "\\clpadfr3"; + if(cell.format.margin.bottom != dflt_margin.bottom) + rowfmt << "\\clpadb" << DotTwips(cell.format.margin.bottom) << "\\clpadfb3"; +*/ + switch(cell.format.align) { + case ALIGN_TOP: rowfmt << "\\clvertalt"; break; + default: + case ALIGN_CENTER: rowfmt << "\\clvertalc"; break; + case ALIGN_BOTTOM: rowfmt << "\\clvertalb"; break; + } + cellindex.Add(c); + if(cell.hspan) + c += cell.hspan; + int cell_end = column_pos[c + 1]; + if(cell.vspan) { + vspan_counts.At(c, 0) = cell.vspan; + rowfmt << "\\clvmgf"; + } + else if(c < vspan_counts.GetCount() && vspan_counts[c] > 0) + rowfmt << "\\clvmrg"; + if(!IsNull(cell.format.color)) + rowfmt << "\\clcbpat" << phys_colors.Find(cell.format.color); + rowfmt << "\\cellx" << DotTwips(cell_end); + } + Begin(); + Command("pard"); + Command("intbl"); + parafmt = RichPara::Format(); + charfmt = RichPara::CharFormat(); + if(nesting) + Command("itap", nesting + 1); + if(!nesting) + stream.Put(rowfmt); + for(int c = 0; c < cellindex.GetCount(); c++) { + int cx = cellindex[c]; + const RichCell& cell = table.cell[r][cx]; + int cell_wd = column_pos[cx + cell.hspan + 1] - column_pos[cx]; + PutTxt(cell.text, nesting + 1, cell_wd); + Command(nesting ? "nestcell" : "cell"); + } + stream.Put(rowfmt); + Command(nesting ? "nestrow" : "row"); + End(); + } +} + +void RTFEncoder::PutTxt(const RichTxt& txt, int nesting, int dot_width) +{ + for(int i = 0; i < txt.GetPartCount(); i++) { + if(txt.IsTable(i)) + PutTable(txt.GetTable(i), nesting, dot_width); + else { + const RichPara& para = txt.Get(i, richtext.GetStyles()); + Uuid pstyle = txt.GetParaStyle(i); + int para_ht = GetParaHeight(para.part); + int first_part = 0, first_ind = 0; + bool hdiff = (para.format.bullet != RichPara::BULLET_NONE + && para.format.bullet != RichPara::BULLET_TEXT && para_ht != para_ht); + if(pstyle != oldstyle + || para.format.bullet != parafmt.bullet || para.format.bullet == RichPara::BULLET_TEXT + || hdiff || para.format.tab != parafmt.tab || para.format.newpage || parafmt.newpage) { + Command("s", styleid.Find(pstyle)); + oldstyle = pstyle; + parafmt = richtext.GetStyle(pstyle).format; + Command("pard"); + if(nesting) + Command("intbl"); + if(nesting > 1) + Command("itap", nesting); + parafmt = RichPara::Format(); + para_ht = 0; + } + if(para.format.bullet == RichPara::BULLET_TEXT) { + int epart = 0, eoff = 0; + while(epart < para.part.GetCount() && (eoff = para.part[epart].text.Find('\t')) < 0) + epart++; + + RichPara::CharFormat rcf = charfmt; + rcf.Height(0); + Begin("pntext"); + PutParts(para.part, rcf, 0, 0, epart, eoff); + stream.Put('\t'); + End(); + + Begin("*\\pn"); + Command("pnhang"); + Command("pnql"); + rcf = charfmt; + if(epart > 0 || eoff > 0) + PutCharFormat(para.part[0].format, rcf, true); + Begin("pntxta"); + End(); + Begin("pntxtb"); + Space(); + PutParts(para.part, rcf, 0, 0, epart, eoff); + stream.Put('\t'); + End(); + End(); + } + else if(para.format.bullet != RichPara::BULLET_NONE) { + int sym_face = SYMBOL_INDEX; + byte sym_char = 0xB7; + + switch(para.format.bullet) { + default: + NEVER(); + + case RichPara::BULLET_ROUND: sym_face = SYMBOL_INDEX; sym_char = 0xB7; break; + case RichPara::BULLET_ROUNDWHITE: sym_face = WINGDINGS_INDEX; sym_char = 0xA1; break; + case RichPara::BULLET_BOX: sym_face = WINGDINGS_INDEX; sym_char = 'n'; break; + case RichPara::BULLET_BOXWHITE: sym_face = WINGDINGS_INDEX; sym_char = 'o'; break; + } + + Begin("pntext"); + // Command("tqr"); + // Command("tx", DotTwips(para.format.indent)); + // Command("qr"); + Command("f", sym_face); + Command("fs", DotPoints(2 * para_ht)); + Space(); + stream.Put(sym_char); + stream.Put('\t'); + End(); + + Begin("*\\pn"); + Command("pnlvlblt"); + Command("pnf", sym_face); + Command("pnfs", DotPoints(2 * para_ht)); + Command("pnql"); + Begin("pntxtb"); + Space(); + stream.Put(sym_char); + // stream.Put('\t'); + End(); + Begin("pntxta"); + End(); + End(); + } + PutParaFormat(para.format, parafmt); + para_ht = para_ht; + parafmt = para.format; + PutParts(para.part, charfmt, first_part, first_ind, para.part.GetCount(), 0); + if(i + 1 < txt.GetPartCount()) + Command("par"); + } + } +} + +void RTFEncoder::PutDocument() +{ + charfmt.Height(PointDots(0)); + charfmt.language = 0; + old_ht = DotPoints(2 * tabs(charfmt.GetHeight())); + para_ht = 0; + oldstyle = Uuid::Create(); + PutTxt(richtext, 0, 3600); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/CtrlCore/ImageWin32.cpp b/uppsrc/CtrlCore/ImageWin32.cpp index d7b4075f6..fbf0290d2 100644 --- a/uppsrc/CtrlCore/ImageWin32.cpp +++ b/uppsrc/CtrlCore/ImageWin32.cpp @@ -155,14 +155,14 @@ DrawSurface::~DrawSurface() ::DeleteDC(dcMem); } -void Image::Data::SysInit() +void Image::Data::SysInitImp() { SystemData& sd = Sys(); sd.hbmp = sd.hmask = sd.himg = NULL; sd.cursor_cheat = NULL; } -void Image::Data::SysRelease() +void Image::Data::SysReleaseImp() { SystemData& sd = Sys(); if(sd.hbmp) { @@ -219,7 +219,7 @@ Image::Data::SystemData& Image::Data::Sys() const return *(SystemData *)system_buffer; } -int Image::Data::GetResCount() const +int Image::Data::GetResCountImp() const { SystemData& sd = Sys(); return !!sd.hbmp + !!sd.hmask + !!sd.himg; @@ -248,7 +248,7 @@ void Image::Data::CreateHBMP(HDC dc, const RGBA *data) ResCount++; } -void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c) +void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c) { GuiLock __; SystemData& sd = Sys(); diff --git a/uppsrc/CtrlCore/ImageX11.cpp b/uppsrc/CtrlCore/ImageX11.cpp index 5ad19e149..39ae18525 100644 --- a/uppsrc/CtrlCore/ImageX11.cpp +++ b/uppsrc/CtrlCore/ImageX11.cpp @@ -1,436 +1,436 @@ -#include "SystemDraw.h" - -NAMESPACE_UPP - -#ifdef PLATFORM_X11 - -struct Image::Data::SystemData { - int cursor_cheat; - XPicture picture; - XPicture picture8; -}; - -Image::Data::SystemData& Image::Data::Sys() const -{ - ASSERT(sizeof(system_buffer) >= sizeof(SystemData)); - return *(SystemData *)system_buffer; -} - -void Image::SetCursorCheat(int id) -{ - data->Sys().cursor_cheat = id; -} - -int Image::GetCursorCheat() const -{ - return data ? data->Sys().cursor_cheat : -1; -} - -static void sInitXImage(XImage& ximg, Size sz) -{ - Zero(ximg); - ximg.width = sz.cx; - ximg.height = sz.cy; - ximg.xoffset = 0; - ximg.format = ZPixmap; - ximg.bitmap_bit_order = MSBFirst; -#ifdef CPU_LITTLE_ENDIAN - ximg.byte_order = LSBFirst; -#else - ximg.byte_order = MSBFirst; -#endif -} - -void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels) -{ - GuiLock __; - Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, cx, cy, 24); - XPicture picture = XRenderCreatePicture( - Xdisplay, pixmap, - XRenderFindStandardFormat(Xdisplay, PictStandardRGB24), - 0, 0 - ); - XImage ximg; - sInitXImage(ximg, Size(cx, cy)); - ximg.bitmap_pad = 32; - ximg.bytes_per_line = 4 * cx; - ximg.bits_per_pixel = 32; - ximg.blue_mask = 0x00ff0000; - ximg.green_mask = 0x0000ff00; - ximg.red_mask = 0x000000ff; - Buffer pma; - ximg.bitmap_unit = 32; - ximg.depth = 24; - ximg.data = (char *)pixels; - XInitImage(&ximg); - GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); - XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, cx, cy); - XFreeGC(Xdisplay, gc); - XFreePixmap(Xdisplay, pixmap); - XRenderComposite(Xdisplay, PictOpOver, - picture, 0, XftDrawPicture(w.GetXftDraw()), - 0, 0, 0, 0, x, y, cx, cy); - XRenderFreePicture(Xdisplay, picture); -} - -int Image::Data::GetResCount() const -{ - return !!Sys().picture + !!Sys().picture8; -} - -void Image::Data::SysInit() -{ - SystemData& sd = Sys(); - sd.picture = 0; - sd.picture8 = 0; - sd.cursor_cheat = -1; -} - -void Image::Data::SysRelease() -{ - SystemData& sd = Sys(); - if(sd.picture) { - GuiLock __; - if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture); - ResCount -= !paintonly; - sd.picture = 0; - } - if(sd.picture8) { - GuiLock __; - if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture8); - ResCount -= !paintonly; - sd.picture8 = 0; - } -} - -struct XRSolidFill { - Color color; - XPicture picture; - Pixmap pixmap; -}; - -enum { XRSolidFillCount = 67 }; - -static XRSolidFill sFill[XRSolidFillCount]; - -inline int s255d16(int x) -{ - return (x << 8)|x; -} - -static XPicture sGetSolidFill(Color c) -{ - GuiLock __; - int q = GetHashValue(c) % (int)XRSolidFillCount; - XRSolidFill& f = sFill[q]; - if(f.color == c && f.picture) - return f.picture; - if(f.picture) - XRenderFreePicture(Xdisplay, f.picture); - if(f.pixmap) - XFreePixmap(Xdisplay, f.pixmap); - f.pixmap = XCreatePixmap(Xdisplay, Xroot, 1, 1, 32); - XRenderPictureAttributes attr; - attr.repeat = XTrue; - f.picture = XRenderCreatePicture(Xdisplay, f.pixmap, - XRenderFindStandardFormat(Xdisplay, PictStandardARGB32), - CPRepeat, &attr); - f.color = c; - XRenderColor xc; - xc.red = s255d16(c.GetR()); - xc.green = s255d16(c.GetG()); - xc.blue = s255d16(c.GetB()); - xc.alpha = 65535; - XRenderFillRectangle(Xdisplay, PictOpSrc, f.picture, &xc, 0, 0, 1, 1); - return f.picture; -} - -void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c) -{ - GuiLock __; - SystemData& sd = Sys(); - while(ResCount > 512) { - Image::Data *l = ResData->GetPrev(); - l->SysRelease(); - l->Unlink(); - } - x += w.GetOffset().x; - y += w.GetOffset().y; - Size sz = buffer.GetSize(); - int len = sz.cx * sz.cy; - Rect sr = src & sz; - Size ssz = sr.Size(); - if(sr.IsEmpty()) - return; - if(GetKind() == IMAGE_EMPTY) - return; - if(GetKind() == IMAGE_OPAQUE && !IsNull(c)) { - w.DrawRect(x, y, sz.cx, sz.cy, c); - return; - } - if(GetKind() == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz)) { - SetSurface(w, x, y, sz.cx, sz.cy, buffer); - paintcount++; - return; - } - Unlink(); - LinkAfter(ResData); - if(IsNull(c)) { - if(!sd.picture) { - bool opaque = GetKind() == IMAGE_OPAQUE; - Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, opaque ? 24 : 32); - sd.picture = XRenderCreatePicture( - Xdisplay, pixmap, - XRenderFindStandardFormat(Xdisplay, opaque ? PictStandardRGB24 - : PictStandardARGB32), - 0, 0 - ); - ResCount++; - XImage ximg; - sInitXImage(ximg, sz); - ximg.bitmap_pad = 32; - ximg.bytes_per_line = 4 * sz.cx; - ximg.bits_per_pixel = 32; - ximg.blue_mask = 0x00ff0000; - ximg.green_mask = 0x0000ff00; - ximg.red_mask = 0x000000ff; - ximg.bitmap_unit = 32; - ximg.data = (char *)~buffer; - ximg.depth = opaque ? 24 : 32; - XInitImage(&ximg); - GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); - XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); - XFreeGC(Xdisplay, gc); - XFreePixmap(Xdisplay, pixmap); - PaintOnlyShrink(); - } - XRenderComposite(Xdisplay, PictOpOver, - sd.picture, 0, XftDrawPicture(w.GetXftDraw()), - sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy); - } - else { - ASSERT(!paintonly); - if(!sd.picture8) { - Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 8); - sd.picture8 = XRenderCreatePicture(Xdisplay, pixmap, - XRenderFindStandardFormat(Xdisplay, PictStandardA8), - 0, 0); - ResCount++; - Buffer ab(len); - byte *t = ab; - const RGBA *s = buffer; - const RGBA *e = s + len; - while(s < e) - *t++ = (s++)->a; - XImage ximg; - sInitXImage(ximg, sz); - ximg.data = (char *)~ab; - ximg.bitmap_unit = 8; - ximg.bitmap_pad = 8; - ximg.depth = 8; - ximg.bytes_per_line = sz.cx; - ximg.bits_per_pixel = 8; - XInitImage(&ximg); - GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); - XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); - XFreeGC(Xdisplay, gc); - XFreePixmap(Xdisplay, pixmap); - } - XRenderComposite(Xdisplay, PictOpOver, - sGetSolidFill(c), sd.picture8, XftDrawPicture(w.GetXftDraw()), - sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy); - } -} - -void ImageDraw::Init() -{ - GuiLock __; - dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth); - gc = XCreateGC(Xdisplay, dw, 0, 0); - xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); - - alpha.dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth); - alpha.gc = XCreateGC(Xdisplay, alpha.dw, 0, 0); - alpha.xftdraw = XftDrawCreate(Xdisplay, (Drawable) alpha.dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); - - Vector clip; - clip.Add(RectC(0, 0, size.cx, size.cy)); - SystemDraw::Init(clip, Point(0, 0)); - alpha.Init(clip, Point(0, 0)); - - has_alpha = false; -} - -ImageDraw::operator Image() const -{ - GuiLock __; - XImage *xim = XGetImage(Xdisplay, dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap); - Visual *v = DefaultVisual(Xdisplay, Xscreenno); - RasterFormat fmt; - - RGBA palette[256]; - - switch(xim->depth) { - case 15: - case 16: - if(xim->byte_order == LSBFirst) - fmt.Set16le(v->red_mask, v->green_mask, v->blue_mask); - else - fmt.Set16be(v->red_mask, v->green_mask, v->blue_mask); - break; - case 8: { - int n = min(v->map_entries, 256); - XColor colors[256]; - for(int i = 0; i < 256; i++) { - colors[i].pixel = i; - colors[i].flags = DoRed|DoGreen|DoBlue; - } - XQueryColors(Xdisplay, Xcolormap, colors, n); - XColor *s = colors; - XColor *e = s + n; - while(s < e) { - RGBA& t = palette[s->pixel]; - t.r = s->red >> 8; - t.g = s->green >> 8; - t.b = s->blue >> 8; - t.a = 255; - s++; - } - fmt.Set8(); - break; - } - default: - if(xim->bits_per_pixel == 32) - if(xim->byte_order == LSBFirst) - fmt.Set32le(v->red_mask, v->green_mask, v->blue_mask); - else - fmt.Set32be(v->red_mask, v->green_mask, v->blue_mask); - else - if(xim->byte_order == LSBFirst) - fmt.Set24le(v->red_mask, v->green_mask, v->blue_mask); - else - fmt.Set24be(v->red_mask, v->green_mask, v->blue_mask); - break; - } - - ImageBuffer ib(size); - const byte *s = (const byte *)xim->data; - RGBA *t = ib; - for(int y = 0; y < size.cy; y++) { - fmt.Read(t, s, size.cx, palette); - s += xim->bytes_per_line; - t += size.cx; - } - XDestroyImage(xim); - if(has_alpha) { - xim = XGetImage(Xdisplay, alpha.dw, 0, 0, size.cx, size.cy, AllPlanes, ZPixmap); - const byte *s = (const byte *)xim->data; - t = ib; - Buffer line(size.cx); - for(int y = 0; y < size.cy; y++) { - fmt.Read(line, s, size.cx, palette); - for(int x = 0; x < size.cx; x++) - (t++)->a = line[x].r; - s += xim->bytes_per_line; - } - XDestroyImage(xim); - } - Premultiply(ib); - return ib; -} - -ImageDraw::ImageDraw(Size sz) -{ - size = sz; - Init(); -} - -ImageDraw::ImageDraw(int cx, int cy) -{ - size = Size(cx, cy); - Init(); -} - -ImageDraw::~ImageDraw() -{ - GuiLock __; - XftDrawDestroy(xftdraw); - XFreePixmap(Xdisplay, dw); - XFreeGC(Xdisplay, gc); - XftDrawDestroy(alpha.xftdraw); - XFreePixmap(Xdisplay, alpha.dw); - XFreeGC(Xdisplay, alpha.gc); -} - -Image sX11Cursor__(int c) -{ - ImageBuffer b(32, 32); - Image m(b); - m.SetCursorCheat(c); - return m; -} - -#include - -#define FCURSOR_(x) { Image h; INTERLOCKED { static Image m = sX11Cursor__(x); h = m; } return h; } - -Image Image::Arrow() FCURSOR_(XC_left_ptr) -Image Image::Wait() FCURSOR_(XC_watch) -Image Image::IBeam() FCURSOR_(XC_xterm) -Image Image::No() FCURSOR_(XC_circle) -Image Image::SizeAll() FCURSOR_(XC_fleur) -Image Image::SizeHorz() FCURSOR_(XC_sb_h_double_arrow) -Image Image::SizeVert() FCURSOR_(XC_double_arrow) -Image Image::SizeTopLeft() FCURSOR_(XC_top_left_corner) -Image Image::SizeTop() FCURSOR_(XC_top_side) -Image Image::SizeTopRight() FCURSOR_(XC_top_right_corner) -Image Image::SizeLeft() FCURSOR_(XC_left_side) -Image Image::SizeRight() FCURSOR_(XC_right_side) -Image Image::SizeBottomLeft() FCURSOR_(XC_bottom_left_corner) -Image Image::SizeBottom() FCURSOR_(XC_bottom_side) -Image Image::SizeBottomRight() FCURSOR_(XC_bottom_right_corner) -Image Image::Cross() FCURSOR_(XC_crosshair) -Image Image::Hand() FCURSOR_(XC_hand1) - -void *X11Cursor(const Image& img) -{ - GuiLock __; - int q = img.GetCursorCheat(); - if(q >= 0) - return (void *)XCreateFontCursor(Xdisplay, q); - int len = img.GetLength(); - Size sz = img.GetSize(); - Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 32); - XPicture picture = XRenderCreatePicture( - Xdisplay, pixmap, - XRenderFindStandardFormat(Xdisplay, PictStandardARGB32), - 0, 0 - ); - XImage ximg; - sInitXImage(ximg, sz); - ximg.bitmap_pad = 32; - ximg.bytes_per_line = 4 * sz.cx; - ximg.bits_per_pixel = 32; - ximg.blue_mask = 0x00ff0000; - ximg.green_mask = 0x0000ff00; - ximg.red_mask = 0x000000ff; - Buffer pma; - pma.Alloc(len); - memcpy(pma, ~img, len * sizeof(RGBA)); - ximg.bitmap_unit = 32; - ximg.depth = 32; - ximg.data = (char *)~pma; - XInitImage(&ximg); - GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); - XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); - XFreeGC(Xdisplay, gc); - XFreePixmap(Xdisplay, pixmap); - Point p = img.GetHotSpot(); - Cursor c = XRenderCreateCursor(Xdisplay, picture, p.x, p.y); - XRenderFreePicture(Xdisplay, picture); - return (void *)c; -} - -#endif - -END_UPP_NAMESPACE +#include "SystemDraw.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +struct Image::Data::SystemData { + int cursor_cheat; + XPicture picture; + XPicture picture8; +}; + +Image::Data::SystemData& Image::Data::Sys() const +{ + ASSERT(sizeof(system_buffer) >= sizeof(SystemData)); + return *(SystemData *)system_buffer; +} + +void Image::SetCursorCheat(int id) +{ + data->Sys().cursor_cheat = id; +} + +int Image::GetCursorCheat() const +{ + return data ? data->Sys().cursor_cheat : -1; +} + +static void sInitXImage(XImage& ximg, Size sz) +{ + Zero(ximg); + ximg.width = sz.cx; + ximg.height = sz.cy; + ximg.xoffset = 0; + ximg.format = ZPixmap; + ximg.bitmap_bit_order = MSBFirst; +#ifdef CPU_LITTLE_ENDIAN + ximg.byte_order = LSBFirst; +#else + ximg.byte_order = MSBFirst; +#endif +} + +void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels) +{ + GuiLock __; + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, cx, cy, 24); + XPicture picture = XRenderCreatePicture( + Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardRGB24), + 0, 0 + ); + XImage ximg; + sInitXImage(ximg, Size(cx, cy)); + ximg.bitmap_pad = 32; + ximg.bytes_per_line = 4 * cx; + ximg.bits_per_pixel = 32; + ximg.blue_mask = 0x00ff0000; + ximg.green_mask = 0x0000ff00; + ximg.red_mask = 0x000000ff; + Buffer pma; + ximg.bitmap_unit = 32; + ximg.depth = 24; + ximg.data = (char *)pixels; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, cx, cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + XRenderComposite(Xdisplay, PictOpOver, + picture, 0, XftDrawPicture(w.GetXftDraw()), + 0, 0, 0, 0, x, y, cx, cy); + XRenderFreePicture(Xdisplay, picture); +} + +int Image::Data::GetResCountImp() const +{ + return !!Sys().picture + !!Sys().picture8; +} + +void Image::Data::SysInitImp() +{ + SystemData& sd = Sys(); + sd.picture = 0; + sd.picture8 = 0; + sd.cursor_cheat = -1; +} + +void Image::Data::SysReleaseImp() +{ + SystemData& sd = Sys(); + if(sd.picture) { + GuiLock __; + if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture); + ResCount -= !paintonly; + sd.picture = 0; + } + if(sd.picture8) { + GuiLock __; + if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture8); + ResCount -= !paintonly; + sd.picture8 = 0; + } +} + +struct XRSolidFill { + Color color; + XPicture picture; + Pixmap pixmap; +}; + +enum { XRSolidFillCount = 67 }; + +static XRSolidFill sFill[XRSolidFillCount]; + +inline int s255d16(int x) +{ + return (x << 8)|x; +} + +static XPicture sGetSolidFill(Color c) +{ + GuiLock __; + int q = GetHashValue(c) % (int)XRSolidFillCount; + XRSolidFill& f = sFill[q]; + if(f.color == c && f.picture) + return f.picture; + if(f.picture) + XRenderFreePicture(Xdisplay, f.picture); + if(f.pixmap) + XFreePixmap(Xdisplay, f.pixmap); + f.pixmap = XCreatePixmap(Xdisplay, Xroot, 1, 1, 32); + XRenderPictureAttributes attr; + attr.repeat = XTrue; + f.picture = XRenderCreatePicture(Xdisplay, f.pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardARGB32), + CPRepeat, &attr); + f.color = c; + XRenderColor xc; + xc.red = s255d16(c.GetR()); + xc.green = s255d16(c.GetG()); + xc.blue = s255d16(c.GetB()); + xc.alpha = 65535; + XRenderFillRectangle(Xdisplay, PictOpSrc, f.picture, &xc, 0, 0, 1, 1); + return f.picture; +} + +void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c) +{ + GuiLock __; + SystemData& sd = Sys(); + while(ResCount > 512) { + Image::Data *l = ResData->GetPrev(); + l->SysRelease(); + l->Unlink(); + } + x += w.GetOffset().x; + y += w.GetOffset().y; + Size sz = buffer.GetSize(); + int len = sz.cx * sz.cy; + Rect sr = src & sz; + Size ssz = sr.Size(); + if(sr.IsEmpty()) + return; + if(GetKind() == IMAGE_EMPTY) + return; + if(GetKind() == IMAGE_OPAQUE && !IsNull(c)) { + w.DrawRect(x, y, sz.cx, sz.cy, c); + return; + } + if(GetKind() == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz)) { + SetSurface(w, x, y, sz.cx, sz.cy, buffer); + paintcount++; + return; + } + Unlink(); + LinkAfter(ResData); + if(IsNull(c)) { + if(!sd.picture) { + bool opaque = GetKind() == IMAGE_OPAQUE; + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, opaque ? 24 : 32); + sd.picture = XRenderCreatePicture( + Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, opaque ? PictStandardRGB24 + : PictStandardARGB32), + 0, 0 + ); + ResCount++; + XImage ximg; + sInitXImage(ximg, sz); + ximg.bitmap_pad = 32; + ximg.bytes_per_line = 4 * sz.cx; + ximg.bits_per_pixel = 32; + ximg.blue_mask = 0x00ff0000; + ximg.green_mask = 0x0000ff00; + ximg.red_mask = 0x000000ff; + ximg.bitmap_unit = 32; + ximg.data = (char *)~buffer; + ximg.depth = opaque ? 24 : 32; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + PaintOnlyShrink(); + } + XRenderComposite(Xdisplay, PictOpOver, + sd.picture, 0, XftDrawPicture(w.GetXftDraw()), + sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy); + } + else { + ASSERT(!paintonly); + if(!sd.picture8) { + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 8); + sd.picture8 = XRenderCreatePicture(Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardA8), + 0, 0); + ResCount++; + Buffer ab(len); + byte *t = ab; + const RGBA *s = buffer; + const RGBA *e = s + len; + while(s < e) + *t++ = (s++)->a; + XImage ximg; + sInitXImage(ximg, sz); + ximg.data = (char *)~ab; + ximg.bitmap_unit = 8; + ximg.bitmap_pad = 8; + ximg.depth = 8; + ximg.bytes_per_line = sz.cx; + ximg.bits_per_pixel = 8; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + } + XRenderComposite(Xdisplay, PictOpOver, + sGetSolidFill(c), sd.picture8, XftDrawPicture(w.GetXftDraw()), + sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy); + } +} + +void ImageDraw::Init() +{ + GuiLock __; + dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth); + gc = XCreateGC(Xdisplay, dw, 0, 0); + xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); + + alpha.dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth); + alpha.gc = XCreateGC(Xdisplay, alpha.dw, 0, 0); + alpha.xftdraw = XftDrawCreate(Xdisplay, (Drawable) alpha.dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); + + Vector clip; + clip.Add(RectC(0, 0, size.cx, size.cy)); + SystemDraw::Init(clip, Point(0, 0)); + alpha.Init(clip, Point(0, 0)); + + has_alpha = false; +} + +ImageDraw::operator Image() const +{ + GuiLock __; + XImage *xim = XGetImage(Xdisplay, dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap); + Visual *v = DefaultVisual(Xdisplay, Xscreenno); + RasterFormat fmt; + + RGBA palette[256]; + + switch(xim->depth) { + case 15: + case 16: + if(xim->byte_order == LSBFirst) + fmt.Set16le(v->red_mask, v->green_mask, v->blue_mask); + else + fmt.Set16be(v->red_mask, v->green_mask, v->blue_mask); + break; + case 8: { + int n = min(v->map_entries, 256); + XColor colors[256]; + for(int i = 0; i < 256; i++) { + colors[i].pixel = i; + colors[i].flags = DoRed|DoGreen|DoBlue; + } + XQueryColors(Xdisplay, Xcolormap, colors, n); + XColor *s = colors; + XColor *e = s + n; + while(s < e) { + RGBA& t = palette[s->pixel]; + t.r = s->red >> 8; + t.g = s->green >> 8; + t.b = s->blue >> 8; + t.a = 255; + s++; + } + fmt.Set8(); + break; + } + default: + if(xim->bits_per_pixel == 32) + if(xim->byte_order == LSBFirst) + fmt.Set32le(v->red_mask, v->green_mask, v->blue_mask); + else + fmt.Set32be(v->red_mask, v->green_mask, v->blue_mask); + else + if(xim->byte_order == LSBFirst) + fmt.Set24le(v->red_mask, v->green_mask, v->blue_mask); + else + fmt.Set24be(v->red_mask, v->green_mask, v->blue_mask); + break; + } + + ImageBuffer ib(size); + const byte *s = (const byte *)xim->data; + RGBA *t = ib; + for(int y = 0; y < size.cy; y++) { + fmt.Read(t, s, size.cx, palette); + s += xim->bytes_per_line; + t += size.cx; + } + XDestroyImage(xim); + if(has_alpha) { + xim = XGetImage(Xdisplay, alpha.dw, 0, 0, size.cx, size.cy, AllPlanes, ZPixmap); + const byte *s = (const byte *)xim->data; + t = ib; + Buffer line(size.cx); + for(int y = 0; y < size.cy; y++) { + fmt.Read(line, s, size.cx, palette); + for(int x = 0; x < size.cx; x++) + (t++)->a = line[x].r; + s += xim->bytes_per_line; + } + XDestroyImage(xim); + } + Premultiply(ib); + return ib; +} + +ImageDraw::ImageDraw(Size sz) +{ + size = sz; + Init(); +} + +ImageDraw::ImageDraw(int cx, int cy) +{ + size = Size(cx, cy); + Init(); +} + +ImageDraw::~ImageDraw() +{ + GuiLock __; + XftDrawDestroy(xftdraw); + XFreePixmap(Xdisplay, dw); + XFreeGC(Xdisplay, gc); + XftDrawDestroy(alpha.xftdraw); + XFreePixmap(Xdisplay, alpha.dw); + XFreeGC(Xdisplay, alpha.gc); +} + +Image sX11Cursor__(int c) +{ + ImageBuffer b(32, 32); + Image m(b); + m.SetCursorCheat(c); + return m; +} + +#include + +#define FCURSOR_(x) { Image h; INTERLOCKED { static Image m = sX11Cursor__(x); h = m; } return h; } + +Image Image::Arrow() FCURSOR_(XC_left_ptr) +Image Image::Wait() FCURSOR_(XC_watch) +Image Image::IBeam() FCURSOR_(XC_xterm) +Image Image::No() FCURSOR_(XC_circle) +Image Image::SizeAll() FCURSOR_(XC_fleur) +Image Image::SizeHorz() FCURSOR_(XC_sb_h_double_arrow) +Image Image::SizeVert() FCURSOR_(XC_double_arrow) +Image Image::SizeTopLeft() FCURSOR_(XC_top_left_corner) +Image Image::SizeTop() FCURSOR_(XC_top_side) +Image Image::SizeTopRight() FCURSOR_(XC_top_right_corner) +Image Image::SizeLeft() FCURSOR_(XC_left_side) +Image Image::SizeRight() FCURSOR_(XC_right_side) +Image Image::SizeBottomLeft() FCURSOR_(XC_bottom_left_corner) +Image Image::SizeBottom() FCURSOR_(XC_bottom_side) +Image Image::SizeBottomRight() FCURSOR_(XC_bottom_right_corner) +Image Image::Cross() FCURSOR_(XC_crosshair) +Image Image::Hand() FCURSOR_(XC_hand1) + +void *X11Cursor(const Image& img) +{ + GuiLock __; + int q = img.GetCursorCheat(); + if(q >= 0) + return (void *)XCreateFontCursor(Xdisplay, q); + int len = img.GetLength(); + Size sz = img.GetSize(); + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 32); + XPicture picture = XRenderCreatePicture( + Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardARGB32), + 0, 0 + ); + XImage ximg; + sInitXImage(ximg, sz); + ximg.bitmap_pad = 32; + ximg.bytes_per_line = 4 * sz.cx; + ximg.bits_per_pixel = 32; + ximg.blue_mask = 0x00ff0000; + ximg.green_mask = 0x0000ff00; + ximg.red_mask = 0x000000ff; + Buffer pma; + pma.Alloc(len); + memcpy(pma, ~img, len * sizeof(RGBA)); + ximg.bitmap_unit = 32; + ximg.depth = 32; + ximg.data = (char *)~pma; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + Point p = img.GetHotSpot(); + Cursor c = XRenderCreateCursor(Xdisplay, picture, p.x, p.y); + XRenderFreePicture(Xdisplay, picture); + return (void *)c; +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppsrc/RichText/ParseRTF.cpp b/uppsrc/CtrlCore/ParseRTF.cpp similarity index 96% rename from uppsrc/RichText/ParseRTF.cpp rename to uppsrc/CtrlCore/ParseRTF.cpp index 95c90f7fb..f146a1039 100644 --- a/uppsrc/RichText/ParseRTF.cpp +++ b/uppsrc/CtrlCore/ParseRTF.cpp @@ -1,1114 +1,1114 @@ -#include "RichText.h" - -NAMESPACE_UPP - -#define LLOG(x) LOG(x) - -static int TwipDotsLim(int twips) { return minmax(TwipDots(twips), 0, MAX_DOTS); } - -static String FromCString(const char *p, const char **endptr = NULL) -{ - if(endptr) { - const char *e = p; - if(*e == '\"') - e++; - while(*e && *e != '\"') - if(*e++ == '\\' && *e) - e++; - if(*e == '\"') - e++; - *endptr = e; - } - - try { - CParser parser(p); - return parser.ReadOneString(); - } - catch(Exc e) { - return Null; - } -} - -class RTFParser -{ -public: - RTFParser(const char *rtf); - - RichText Run(); - -private: - enum TOKEN { T_EOF, T_TEXT, T_COMMAND, T_GROUP, T_END_GROUP }; - - void Flush(bool force, int itap); - void OpenTable(int level); - void FlushTable(int level); - TOKEN Fetch(); - void Skip(); - TOKEN Token() { if(!is_full) Fetch(); return token; } - bool PassIf(bool c) { is_full &= !c; return c; } - bool PassText() { return PassIf(Token() == T_TEXT); } - bool PassGroup() { return PassIf(Token() == T_GROUP); } - bool PassEndGroup() { return PassIf(Token() == T_END_GROUP || token == T_EOF); } - bool PassEndGroup(int level); - bool PassCmd(const char *cmd) { return PassIf(Token() == T_COMMAND && command == cmd); } - bool PassQ(const char *cmd) { return PassIf(command == cmd); } - - void SkipGroup() { SkipGroup(stack.GetCount()); } - void SkipGroup(int level); - int Level() const { return stack.GetCount(); } - - void ReadItem(); - void ReadItemGroup(int level); - void ReadItemGroup() { ReadItemGroup(Level()); } - void ReadText(); - void ReadText(const WString& text); - void ReadChar(word ch) { ReadText(WString(ch, 1)); } - void ReadCommand(); - - void ReadHeader(); - void ReadFaceTable(); - void ReadColorTable(); - void ReadCharSet(); - - void ReadMisc(); - void ReadField(); - bool ReadField(const char *def); - void ReadPict(); - void ReadShape(); - - void ReadParaStyle(); - void ReadTableStyle(); - void DefaultParaStyle(); - - void ReadCharStyle(); - - String ReadBinHex(char& odd) const; - -private: - const char *rtf_begin; - const char *rtf; - - TOKEN token; - bool is_full; -// bool new_dest; - bool next_command; - WString text; - String command; - int command_arg; - - struct Cell { - Cell() : end_dots(0), merge_first(false), merge(false) {} - RichTxt text; - RichCell::Format format; - int end_dots; - bool merge_first; - bool merge; - }; - - struct Face : Moveable { - int face; - byte charset; - }; - - struct TableState { - TableState() : textcol(0), stylecol(0) { cells.Add(); } - - RichTable::Format tableformat; - Vector< Array > cells; - int textcol; - int stylecol; - }; - - struct State { - String dest; - RichPara::Format format; - RichPara::CharFormat charformat; - RichCell::Format cellformat; - Rect rowmargin; - Rect rowmarginunits; - Rect cellmarginunits; - int uc_value; - int left_margin; - int right_margin; - int first_indent; - bool in_table; - int itap; - bool nestprop; - bool new_dest; - byte charset; - }; - - Array stack; - Array table_stack; - State state; - RichPara::CharFormat plain_format; - RichPara::Format pard_format; - RichCell::Format std_cell_format; - byte plain_charset; - byte default_charset; - int default_font; - Alignment tab_align; - byte tab_fill; - Vector face_table; - Vector color_table; - int paper_width; - int left_margin; - int right_margin; - - RichText output; - RichPara para; -}; - -RichText ParseRTF(const char *rtf) { return RTFParser(rtf).Run(); } - -RTFParser::RTFParser(const char *rtf) -: rtf_begin(rtf) -, rtf(rtf) -{ -#ifdef _DEBUG - SaveFile(ConfigFile("rtfparser.rtf"), rtf); - LOG(rtf); -#endif - is_full = false; - next_command = false; - default_font = 0; - plain_charset = default_charset = state.charset = CHARSET_WIN1250; - state.uc_value = 1; - state.new_dest = false; - plain_format.Face(Font::ARIAL).Height(100); - std_cell_format.align = ALIGN_TOP; - std_cell_format.margin = Rect(25, 25, 25, 25); - DefaultParaStyle(); - state.charformat = plain_format; - tab_align = ALIGN_LEFT; - tab_fill = 0; - paper_width = 5100; - left_margin = right_margin = 750; -} - -RichText RTFParser::Run() -{ - if(!PassGroup() || !PassCmd("rtf") || command_arg != 1 && !IsNull(command_arg)) - return output; - while(Token() != T_EOF) - ReadItem(); - Flush(false, 1); - FlushTable(0); - return output; -} - -void RTFParser::FlushTable(int level) -{ - while(table_stack.GetCount() > level) { - TableState& child = table_stack.Top(); - while(!child.cells.IsEmpty() && child.cells.Top().IsEmpty()) - child.cells.Drop(); - if(child.cells.IsEmpty()) { - table_stack.Drop(); - continue; - } - Index dot_index; - int pos = child.tableformat.lm; - dot_index.Add(pos); - for(int r = 0; r < child.cells.GetCount(); r++) { - Array& rw = child.cells[r]; - int pos = 0; - for(int c = 0; c < rw.GetCount(); c++) - dot_index.FindAdd(rw[c].end_dots = pos = max(pos + 100, rw[c].end_dots)); - } - Vector dot_order = dot_index.PickKeys(); - Sort(dot_order); - RichTable table; - if(table_stack.GetCount() == 1) - child.tableformat.rm = max(paper_width - left_margin - right_margin - dot_order.Top(), 0); -// child.tableformat.before = state.format.before; -// child.tableformat.after = state.format.after; - table.SetFormat(child.tableformat); - for(int c = 1; c < dot_order.GetCount(); c++) - table.AddColumn(dot_order[c] - dot_order[c - 1]); - dot_index = dot_order; - for(int r = 0; r < child.cells.GetCount(); r++) { - Array& rw = child.cells[r]; - int pos = child.tableformat.lm; - for(int c = 0; c < rw.GetCount(); c++) { - Cell& cell = rw[c]; - if(cell.merge) - continue; - int vspan = 0; - if(cell.merge_first) { - for(int m = r + 1; m < child.cells.GetCount(); m++) { - const Array& mrw = child.cells[m]; - int mc = mrw.GetCount(); - while(--mc >= 0 && mrw[mc].end_dots > cell.end_dots) - ; - if(mc >= 0 && mrw[mc].end_dots == cell.end_dots && mrw[mc].merge) - vspan++; - else - break; - } - } - int nbegin = dot_index.Find(pos); - int hspan = dot_index.Find(pos = cell.end_dots) - nbegin - 1; - hspan = max(hspan, 0); - vspan = max(vspan, 0); -// ASSERT(hspan >= 0 && vspan >= 0); - if(hspan || vspan) - table.SetSpan(r, nbegin, vspan, hspan); - table.SetFormat(r, nbegin, cell.format); - cell.text.Normalize(); - table.SetPick(r, nbegin, cell.text); - } - } - table.Normalize(); - table_stack.Drop(); - if(table_stack.IsEmpty()) - output.CatPick(table); - else { - TableState& par = table_stack.Top(); - par.cells.Top().At(par.textcol).text.CatPick(table); - } - } -} - -void RTFParser::Flush(bool force, int itap) -{ - if(!para.part.IsEmpty() || force) { - int fi = state.first_indent, li = state.left_margin, ri = state.right_margin; - if(state.format.bullet != RichPara::BULLET_NONE) { - li += fi; - fi = -fi; - } - state.format.indent = minmax(fi, 0, MAX_DOTS); - state.format.lm = minmax(li, 0, MAX_DOTS); - state.format.rm = minmax(ri, 0, MAX_DOTS); - para.format = state.format; - if(state.in_table) { - FlushTable(itap); - OpenTable(itap); - TableState& ts = table_stack[itap - 1]; - ts.cells.Top().At(ts.textcol).text.Cat(para, output.GetStyles()); - } - else { - FlushTable(0); - output.Cat(para); - } - para.part.Clear(); - } - else - FlushTable(itap); -} - -RTFParser::TOKEN RTFParser::Fetch() -{ - is_full = true; - text = WString(); - if(next_command) - { - next_command = false; - return token = T_COMMAND; - } - - text = Null; - command = Null; - command_arg = Null; - - int skip = 0; - while(*rtf && *rtf != '{' && *rtf != '}') - { - int c = 0, nskip = max(skip - 1, 0); - if((byte)*rtf < ' ') - rtf++; - else if(*rtf != '\\') - c = ToUnicode(*rtf++, state.charset); - else - switch(rtf++, *rtf++) - { - case 0: { - rtf--; - break; - } - - case '{': - case '}': - case '\\': { - c = rtf[-1]; - break; - } - - case '~': { - c = 160; - break; - } - - case '|': - case '-': - case '_': - case ':': { - command = String(rtf - 1, 1); - if(text.IsEmpty()) - return token = T_COMMAND; - next_command = true; - return token = T_TEXT; - } - - case '\'': { - int c1 = ctoi(*rtf); - if(c1 < 16) { - int c2 = ctoi(*++rtf); - if(c2 < 16) { - c1 = c1 * 16 + c2; - rtf++; - } - c = ToUnicode(c1, state.charset); - } - break; - } - - default: { - if(IsAlpha(*--rtf) || *rtf == '*' && rtf[1] == '\\' && IsAlpha(rtf[2])) { - if(*rtf == '*') { - rtf += 2; - state.new_dest = true; - } - const char *b = rtf; - while(IsAlpha(*++rtf)) - ; - command = String(b, rtf); - if(IsDigit(*rtf) || *rtf == '-') - command_arg = strtol(rtf, (char **)&rtf, 10); - if(*rtf == ' ') - rtf++; - if(command == "uc") - state.uc_value = command_arg; - else if(command == "u") { - c = command_arg; - nskip = state.uc_value; - } - else { // command - quit reading text - if(text.IsEmpty()) - return token = T_COMMAND; - next_command = true; - return token = T_TEXT; - } - } - break; - } - } - if(c && !skip) - text.Cat(c); - skip = nskip; - } - - if(!text.IsEmpty()) - return token = T_TEXT; - - if(*rtf == '{') { - stack.Add(state); - rtf++; - return token = T_GROUP; - } - - if(*rtf == '}') { - if(!stack.IsEmpty()) { - state = stack.Top(); - stack.Drop(); - } - rtf++; - return token = T_END_GROUP; - } - - return token = T_EOF; -} - -bool RTFParser::PassEndGroup(int level) -{ - if(Token() == T_EOF) - return true; - if(token != T_END_GROUP) - return false; - is_full = false; - return Level() < level; -} - -void RTFParser::Skip() -{ - bool is_group = (token == T_GROUP || token == T_COMMAND && state.new_dest); - is_full = false; - if(is_group) - SkipGroup(); -} - -void RTFParser::SkipGroup(int level) -{ - while(!PassEndGroup(level)) - is_full = false; -} - -void RTFParser::ReadItem() -{ - const char *p = rtf; - if(token == T_COMMAND) - ReadCommand(); - else if(token == T_TEXT) - ReadText(); - if(rtf == p && is_full) { - is_full = false; - if(token == T_COMMAND && state.new_dest) - SkipGroup(); - } -} - -void RTFParser::ReadItemGroup(int level) -{ - while(!PassEndGroup(level)) - ReadItem(); -} - -void RTFParser::ReadText() -{ - if(!IsNull(text)) - ReadText(text); -} - -void RTFParser::ReadText(const WString& text) -{ - if(!IsNull(state.dest)) - return; - LLOG("Output text: <" << FromUnicode(text, state.charset) << ">, " << state.charformat); - para.Cat(text, state.charformat); -} - -void RTFParser::ReadCommand() -{ - if(Token() == T_COMMAND) ReadHeader(); - if(Token() == T_COMMAND) ReadMisc(); - if(Token() == T_COMMAND) ReadParaStyle(); - if(Token() == T_COMMAND) ReadTableStyle(); - if(Token() == T_COMMAND) ReadCharStyle(); -} - -void RTFParser::ReadHeader() -{ - if(PassCmd("deff")) - default_font = command_arg; - else if(PassQ("fonttbl")) { - state.dest = command; - ReadFaceTable(); - } - else if(PassQ("colortbl")) { - state.dest = command; - ReadColorTable(); - } - else if(PassQ("stylesheet") || PassQ("list") || PassQ("listoverride") || PassQ("info")) { - state.dest = command; - SkipGroup(); - } - else if(Token() == T_COMMAND) - ReadCharSet(); -} - -void RTFParser::ReadCharSet() -{ - if(PassQ("ansi")) {} - else if(PassQ("mac")) {} - else if(PassQ("pc")) {} - else if(PassQ("pca")) {} - else if(PassQ("ansicpg")) { - static const struct { - int ansicpg; - byte charset; - } - charsets[] = - { - { 1250, CHARSET_WIN1250 }, - { 1251, CHARSET_WIN1251 }, - { 1252, CHARSET_WIN1252 }, - { 1253, CHARSET_WIN1253 }, - { 1254, CHARSET_WIN1254 }, - { 1255, CHARSET_WIN1255 }, - { 1256, CHARSET_WIN1256 }, - { 1257, CHARSET_WIN1257 }, - }; - for(int c = 0; c < __countof(charsets); c++) - if(charsets[c].ansicpg == command_arg) { - default_charset = state.charset = charsets[c].charset; - break; - } - } -} - -void RTFParser::ReadFaceTable() -{ - int fx = 0; - while(!PassEndGroup()) { - if(!PassGroup()) { - Skip(); - continue; - } - Face n; - n.face = Font::ARIAL; - n.charset = default_charset; - while(!PassEndGroup()) { - if(PassCmd("f")) - fx = command_arg; - else if(PassCmd("fnil")) - ; - else if(PassCmd("froman")) - n.face = Font::ROMAN; - else if(PassCmd("fswiss")) - n.face = Font::ARIAL; - else if(PassCmd("fmodern")) - n.face = Font::COURIER; - else if(PassCmd("ftech")) -#ifdef PLATFORM_WIN32 - n.face = Font::SYMBOL; -#else - n.face = Font::ARIAL; -#endif - else if(PassCmd("fcharset")) { - switch(command_arg) { - case 0: n.charset = CHARSET_WIN1252; break; // ANSI - case 1: n.charset = default_charset; break; // Default - case 2: n.charset = CHARSET_WIN1252; break; // Symbol - case 3: break; // Invalid - case 77: break; // Mac - case 128: break; // Shift Jis - case 129: break; // Hangul - case 130: break; // Johab - case 134: break; // GB2312 - case 136: break; // Big5 - case 161: n.charset = CHARSET_WIN1253; break; // Greek - case 162: n.charset = CHARSET_WIN1254; break; // Turkish - case 163: break; // Vietnamese - case 177: n.charset = CHARSET_WIN1255; break; // Hebrew - case 178: break; // Arabic - case 179: break; // Arabic Traditional - case 180: break; // Arabic user - case 181: break; // Hebrew user - case 186: break; // Baltic - case 204: n.charset = CHARSET_WIN1251; break; // Russian - case 222: break; // Thai - case 238: n.charset = CHARSET_WIN1250; break; // Eastern European - case 254: break; // PC 437 - case 255: n.charset = CHARSET_WIN1252; break; // OEM - } - } -/* else if(PassText()) { - String s = FromUnicode(text, charset); - if(!s.IsEmpty() && *s.Last() == ';') - s.Trim(s.GetLength() - 1); - if(!s.IsEmpty()) - f = Font::FindFaceNameIndex(s); - } - else if(PassGroup()) { - int level = Level(); - if(PassCmd("falt") && PassText() && f < 0) - f = Font::FindFaceNameIndex(FromUnicode(text, charset)); - SkipGroup(level); - }*/ //Cxl 2005-11-29 - "Arial CE" makes mess here! - else - Skip(); - } - if(fx >= 0 && fx < MAX_FONTS) { -// if(f < 0) // Cxl 2005-11-29 - if(default_font == fx) { - plain_format.Face(n.face); - plain_charset = n.charset; - } - Face dflt; - dflt.face = Font::ARIAL; - dflt.charset = default_charset; - face_table.At(fx++, dflt) = n; - } - } -} - -void RTFParser::ReadColorTable() -{ - int r = Null, g = Null, b = Null; - for(; !PassEndGroup(); Skip()) - if(PassCmd("red")) - r = command_arg; - else if(PassCmd("green")) - g = command_arg; - else if(PassCmd("blue")) - b = command_arg; - else if(PassText()) - { - Color c = Null; - if(!IsNull(r) || !IsNull(g) || !IsNull(b)) - c = Color(Nvl(r, 0), Nvl(g, 0), Nvl(b, 0)); - color_table.Add(c); - } -} - -void RTFParser::ReadMisc() -{ - if(PassQ("field")) - ReadField(); - else if(PassQ("pict")) - ReadPict(); - else if(PassQ("shpinst")) - ReadShape(); - else if(PassQ("endash")) - ReadChar(0x2013); - else if(PassQ("emdash")) - ReadChar(0x2014); - else if(PassQ("tab")) - ReadText(WString(9, 1)); - else if(PassQ("enspace")) - ReadText(WString(" ")); // todo - else if(PassQ("emspace")) - ReadText(WString(" ")); // todo - else if(PassQ("bullet")) - ReadChar(0x2022); - else if(PassQ("lquote")) - ReadChar(0x2018); - else if(PassQ("rquote")) - ReadChar(0x2019); - else if(PassQ("ldblquote")) - ReadChar(0x201C); - else if(PassQ("rdblquote")) - ReadChar(0x201D); -} - -void RTFParser::ReadField() -{ - bool ign_rslt = false; - int level = Level(); - while(!PassEndGroup(level)) - if(PassGroup() && Level() == level + 1) { - if(PassCmd("fldinst")) { - WString source; - for(; !PassEndGroup(); Skip()) - if(PassText()) - source.Cat(text); - if(ReadField(FromUnicode(source, state.charset))) - ign_rslt = true; - continue; - } - else if(PassCmd("fldrslt")) { - if(!ign_rslt) - ReadItemGroup(); - } - } - else - Skip(); -} - -bool RTFParser::ReadField(const char *p) -{ - Index symdef; - while(*p) - if((byte)*p <= ' ') - p++; - else if(*p == '\"') - symdef.Add(FromCString(p, &p)); - else { - const char *b = p; - while(*++p && *p != ' ') - ; - symdef.Add(String(b, p)); - } - if(symdef.IsEmpty()) - return false; - if(symdef[0] == "SYMBOL" && symdef.GetCount() >= 2 && IsDigit(*symdef[1])) { - int code = atoi(symdef[1]); - int face = -1; - int height = 0; - int f = symdef.Find("\\f"); - if(f >= 0 && f + 1 < symdef.GetCount()) - face = Font::FindFaceNameIndex(symdef[f + 1]); - f = symdef.Find("\\s"); - if(f >= 0 && f + 1 < symdef.GetCount()) - height = PointDots(fround(2 * atof(symdef[f + 1]))) >> 1; - if(face < 0) -#ifdef PLATFORM_WIN32 - face = Font::SYMBOL; -#else - face = Font::ARIAL; -#endif - if(height <= 0 || height >= MAX_DOT_HEIGHT) - height = state.charformat.GetHeight(); - if(code >= 0 && code < 255) { - state.charformat.Face(face).Height(height); - ReadText(WString(ToUnicode(code, state.charset), 1)); - return true; - } - } - return false; -} - -void RTFParser::DefaultParaStyle() -{ - state.format = pard_format; - state.first_indent = state.left_margin = state.right_margin = 0; - state.cellformat = std_cell_format; - state.in_table = false; - state.itap = 1; - state.nestprop = false; - state.rowmargin = Rect(25, 25, 25, 25); - state.cellmarginunits = state.rowmarginunits = Rect(0, 0, 0, 0); - state.charset = plain_charset; -} - -void RTFParser::ReadParaStyle() -{ - if(PassQ("par")) - Flush(true, state.itap); - else if(PassQ("cell")) { - Flush(false, 1); - if(!table_stack.IsEmpty()) - table_stack[0].textcol++; - } - else if(PassQ("nestcell")) { - Flush(false, state.itap); - if(state.itap <= table_stack.GetCount()) - table_stack[state.itap - 1].textcol++; - } - else if(PassQ("pard")) - DefaultParaStyle(); - else if(PassQ("pntext")) - SkipGroup(); - else if(PassQ("pn")) { - SkipGroup(); - state.format.bullet = RichPara::BULLET_ROUND; - } - else if(PassQ("pagebb")) - state.format.newpage = (command_arg != 0); - else if(PassQ("ql")) - state.format.align = ALIGN_LEFT; - else if(PassQ("qc")) - state.format.align = ALIGN_CENTER; - else if(PassQ("qr")) - state.format.align = ALIGN_RIGHT; - else if(PassQ("qj")) - state.format.align = ALIGN_JUSTIFY; - else if(PassQ("fi")) - state.first_indent = TwipDotsLim(command_arg); - else if(PassQ("li")) - state.left_margin = TwipDotsLim(command_arg); - else if(PassQ("ri")) - state.right_margin = TwipDotsLim(command_arg); - else if(PassQ("sb")) - state.format.before = TwipDotsLim(command_arg); - else if(PassQ("sa")) - state.format.after = TwipDotsLim(command_arg); - else if(PassQ("widctlpar")) - state.format.orphan = true; - else if(PassQ("nowidctlpar")) - state.format.orphan = false; - else if(PassQ("tql")) - tab_align = ALIGN_LEFT; - else if(PassQ("tqc")) - tab_align = ALIGN_CENTER; - else if(PassQ("tqr")) - tab_align = ALIGN_RIGHT; - else if(PassQ("tqdec")) - tab_align = ALIGN_RIGHT; // todo - else if(PassQ("tldot")) - tab_fill = 0; - else if(PassQ("tlhyph")) - tab_fill = 0; - else if(PassQ("tlul")) - tab_fill = 0; - else if(PassQ("tlth")) - tab_fill = 0; - else if(PassQ("tleq")) - tab_fill = 0; - else if(PassQ("tx") || PassQ("tb")) { // todo: bar tab ? - int pos = TwipDotSize(command_arg); - RichPara::Tab& tab = state.format.tab.Add(); - tab.align = tab_align; - tab.fillchar = tab_fill; - tab.pos = pos; - state.format.SortTabs(); - } - else if(PassQ("intbl")) - state.in_table = true; - else if(PassQ("itap")) { - state.itap = minmax(command_arg, 1, 10); - if(table_stack.GetCount() < state.itap) - OpenTable(state.itap); - } -} - -void RTFParser::ReadCharStyle() -{ - if(PassQ("plain")) { - state.charformat = plain_format; - state.charset = plain_charset; - } - else if(PassQ("b")) - state.charformat.Bold(command_arg != 0); - else if(PassQ("i")) - state.charformat.Italic(command_arg != 0); - else if(PassQ("ul") || PassQ("uld") || PassQ("uldb") - || PassQ("uldash") || PassQ("uldashd") || PassQ("uldashdd") - || PassQ("ulth") || PassQ("ulw") || PassQ("ulwave")) - state.charformat.Underline(); - else if(PassQ("ulnone")) - state.charformat.Underline(false); - else if(PassQ("strike") || PassQ("strikedl")) - state.charformat.Strikeout(command_arg != 0); - else if(PassQ("caps") || PassQ("scaps")) - state.charformat.capitals = (command_arg != 0); - else if(PassQ("super") || PassQ("up")) - state.charformat.sscript = 1; - else if(PassQ("sub") || PassQ("dn")) - state.charformat.sscript = 2; - else if(PassQ("nosupersub")) - state.charformat.sscript = 0; - else if(PassQ("f") && command_arg >= 0 && command_arg < face_table.GetCount()) { - LLOG("font = " << command_arg << ", face = " << face_table[command_arg].face - << ", charset = " << face_table[command_arg].charset); - state.charformat.Face(face_table[command_arg].face); - state.charset = face_table[command_arg].charset; - } - else if(PassQ("fs")) - state.charformat.Height(PointDotHeight(command_arg)); - else if(PassQ("cf") && command_arg >= 0 && command_arg < color_table.GetCount()) - state.charformat.ink = Nvl(color_table[command_arg], Black); - else if(PassQ("cb") && command_arg >= 0 && command_arg < color_table.GetCount()) - state.charformat.paper = color_table[command_arg]; - else if(PassQ("lang")) - {} // state.language = ... -} - -void RTFParser::ReadShape() -{ - int level = Level(); - while(!PassEndGroup(level)) - if(PassCmd("shppict")) { - state.new_dest = false; - ReadItemGroup(); - } - else - is_full = false; -} - -void RTFParser::ReadPict() -{ - Size log_size(1, 1), out_size(1, 1), scaling(100, 100); - Rect crop(0, 0, 0, 0); - enum BLIPTYPE { UNK_BLIP, EMF_BLIP, PNG_BLIP, JPEG_BLIP, WMF_BLIP, DIB_BLIP }; - BLIPTYPE blip_type = UNK_BLIP; -#ifdef PLATFORM_WIN32 -#ifndef PLATFORM_WINCE - int wmf_mode = MM_ANISOTROPIC; -#endif -#endif - String blip_data; - char odd = 0; - while(!PassEndGroup()) - if(PassText()) - blip_data.Cat(ReadBinHex(odd)); - else if(Token() == T_COMMAND) { - if(PassQ("picw")) log_size.cx = minmax(command_arg, 0, 30000); - else if(PassQ("pich")) log_size.cy = minmax(command_arg, 0, 30000); - else if(PassQ("picwgoal")) out_size.cx = TwipDotSize(command_arg); - else if(PassQ("pichgoal")) out_size.cy = TwipDotSize(command_arg); - else if(PassQ("picscalex")) scaling.cx = minmax(command_arg, 1, 1000); - else if(PassQ("picscaley")) scaling.cy = minmax(command_arg, 1, 1000); - else if(PassQ("piccropl")) crop.left = TwipDotSize(command_arg); - else if(PassQ("piccropt")) crop.top = TwipDotSize(command_arg); - else if(PassQ("piccropr")) crop.right = TwipDotSize(command_arg); - else if(PassQ("piccropb")) crop.bottom = TwipDotSize(command_arg); - else if(PassQ("emfblip")) blip_type = EMF_BLIP; - else if(PassQ("pngblip")) blip_type = PNG_BLIP; - else if(PassQ("jpegblip")) blip_type = JPEG_BLIP; -#ifdef PLATFORM_WIN32 -#ifndef PLATFORM_WINCE - else if(PassQ("wmetafile")) { blip_type = WMF_BLIP; wmf_mode = command_arg; } -#endif -#endif - else if(PassQ("dibitmap")) blip_type = DIB_BLIP; - else Skip(); - } - else - Skip(); - Size final_size = minmax(iscale(out_size, scaling, Size(100, 100)), Size(1, 1), Size(30000, 30000)); - Size drawing_size; - DrawingDraw dd; - RichObject object; -#ifdef PLATFORM_WIN32 -#ifndef PLATFORM_WINCE - if(blip_type == EMF_BLIP || blip_type == WMF_BLIP) { - log_size = min(log_size, GetFitSize(log_size, final_size)); - dd.Create(drawing_size = log_size); - WinMetaFile wmf; - if(blip_type == EMF_BLIP) - wmf = WinMetaFile(SetEnhMetaFileBits(blip_data.GetLength(), blip_data)); - else { - METAFILEPICT mfp; - Zero(mfp); - mfp.mm = wmf_mode; - mfp.xExt = log_size.cx; - mfp.yExt = log_size.cy; - wmf = WinMetaFile(SetWinMetaFileBits(blip_data.GetLength(), blip_data, ScreenHDC(), &mfp)); - } - wmf.Paint(dd, log_size); - object = CreateDrawingObject(dd, out_size, final_size); - } - else -#endif -#endif - if(blip_type == DIB_BLIP || blip_type == PNG_BLIP || blip_type == JPEG_BLIP) { - //FIXIMAGE - Image image = StreamRaster::LoadStringAny(blip_data); - object = CreatePNGObject(image, out_size, final_size); - } - if(object) { - LLOG("object (" << object.GetTypeName() << ", " << object.Write().GetLength() << " B), pixel size " - << object.GetPixelSize() << ", final size " << object.GetSize()); - para.Cat(object, state.charformat); - } -} - -String RTFParser::ReadBinHex(char& odd) const -{ - int t = odd; - byte v = ctoi(odd); - String out; - for(const wchar *s = text.Begin(); *s; s++) { - byte w = (*s >= '0' && *s <= '9' ? *s - '0' - : *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 - : *s >= 'a' && *s <= 'f' ? *s - 'a' + 10 - : 255); - if(w < 16) - if(v >= 16) - { - t = *s; - v = w; - } - else - { - out.Cat(16 * v + w); - v = 255; - } - } - odd = (v < 16 ? t : 0); - return out; -} - -void RTFParser::OpenTable(int level) -{ - if(table_stack.GetCount() < level) { - TableState& ts = table_stack.At(level - 1); - ts.stylecol = 0; - state.cellformat = std_cell_format; - } -} - -void RTFParser::ReadTableStyle() -{ - if(PassQ("nesttableprops")) { - state.nestprop = true; - return; - } - if(PassQ("nonesttables")) { - SkipGroup(); - return; - } - int itap = (state.nestprop ? state.itap : 1); - if(PassQ("trowd")) { - OpenTable(itap); - table_stack[itap - 1].stylecol = 0; - return; - } - if(PassQ("row") && table_stack.GetCount() >= 1) { - TableState& ts0 = table_stack[0]; - ts0.textcol = ts0.stylecol = 0; - ts0.cells.Add(); - return; - } - if(PassQ("nestrow") && table_stack.GetCount() >= state.itap) { - TableState& ts = table_stack[state.itap - 1]; - ts.textcol = ts.stylecol = 0; - ts.cells.Add(); - return; - } - if(itap > table_stack.GetCount()) - return; - TableState& ts = table_stack[itap - 1]; - if(PassQ("trgaph")) {} - else if(PassQ("trql")) {} - else if(PassQ("trqr")) {} - else if(PassQ("trqc")) {} - else if(PassQ("trleft")) { - ts.tableformat.lm = TwipDotsLim(command_arg); - } - else if(PassQ("trbrdrl")) {} - else if(PassQ("trbrdrt")) {} - else if(PassQ("trbrdrr")) {} - else if(PassQ("trbrdrb")) {} - else if(PassQ("trbrdrv")) {} - else if(PassQ("trftsWidth")) {} - else if(PassQ("trautofit")) {} - else if(PassQ("trpaddl")) - state.rowmargin.left = TwipDotsLim(command_arg); - else if(PassQ("trpaddt")) - state.rowmargin.top = TwipDotsLim(command_arg); - else if(PassQ("trpaddr")) - state.rowmargin.right = TwipDotsLim(command_arg); - else if(PassQ("trpaddb")) - state.rowmargin.bottom = TwipDotsLim(command_arg); - else if(PassQ("trpaddfl")) - state.rowmarginunits.left = command_arg; - else if(PassQ("trpaddft")) - state.rowmarginunits.top = command_arg; - else if(PassQ("trpaddfr")) - state.rowmarginunits.right = command_arg; - else if(PassQ("trpaddfb")) - state.rowmarginunits.bottom = command_arg; - else if(PassQ("clpadl")) - state.cellformat.margin.left = TwipDotsLim(command_arg); - else if(PassQ("clpadt")) - state.cellformat.margin.top = TwipDotsLim(command_arg); - else if(PassQ("clpadr")) - state.cellformat.margin.right = TwipDotsLim(command_arg); - else if(PassQ("clpadb")) - state.cellformat.margin.bottom = TwipDotsLim(command_arg); - else if(PassQ("clpadfl")) - state.cellmarginunits.left = command_arg; - else if(PassQ("clpadft")) - state.cellmarginunits.top = command_arg; - else if(PassQ("clpadfr")) - state.cellmarginunits.right = command_arg; - else if(PassQ("clpadfb")) - state.cellmarginunits.bottom = command_arg; - else if(PassQ("clvertalt")) {} - else if(PassQ("clbrdrl")) {} - else if(PassQ("clbrdrt")) {} - else if(PassQ("clbrdrr")) {} - else if(PassQ("clbrdrb")) {} - else if(PassQ("cltxlrtb")) {} - else if(PassQ("clcbpat")) { - if(command_arg >= 0 && command_arg < color_table.GetCount()) - state.cellformat.color = color_table[command_arg]; - } - else if(PassQ("clvmrg")) - ts.cells.Top().At(ts.stylecol).merge = true; - else if(PassQ("clvmgf")) - ts.cells.Top().At(ts.stylecol).merge_first = true; - else if(PassQ("clftsWidth")) {} - else if(PassQ("clwWidth")) {} - else if(PassQ("cellx")) { - Cell& newcell = ts.cells.Top().At(ts.stylecol++); - newcell.end_dots = TwipDotsLim(command_arg); - newcell.format = state.cellformat; - if(state.cellmarginunits.left == 0) newcell.format.margin.left = state.rowmargin.left; - if(state.cellmarginunits.top == 0) newcell.format.margin.top = state.rowmargin.top; - if(state.cellmarginunits.right == 0) newcell.format.margin.right = state.rowmargin.right; - if(state.cellmarginunits.bottom == 0) newcell.format.margin.bottom = state.rowmargin.bottom; - state.cellformat = std_cell_format; - } - else if(PassQ("clvertalt")) - state.cellformat.align = ALIGN_TOP; - else if(PassQ("clvertalc")) - state.cellformat.align = ALIGN_CENTER; - else if(PassQ("clvertalb")) - state.cellformat.align = ALIGN_BOTTOM; -} - -END_UPP_NAMESPACE +#include "CtrlCore.h" + +NAMESPACE_UPP + +#define LLOG(x) LOG(x) + +static int TwipDotsLim(int twips) { return minmax(TwipDots(twips), 0, MAX_DOTS); } + +static String FromCString(const char *p, const char **endptr = NULL) +{ + if(endptr) { + const char *e = p; + if(*e == '\"') + e++; + while(*e && *e != '\"') + if(*e++ == '\\' && *e) + e++; + if(*e == '\"') + e++; + *endptr = e; + } + + try { + CParser parser(p); + return parser.ReadOneString(); + } + catch(Exc e) { + return Null; + } +} + +class RTFParser +{ +public: + RTFParser(const char *rtf); + + RichText Run(); + +private: + enum TOKEN { T_EOF, T_TEXT, T_COMMAND, T_GROUP, T_END_GROUP }; + + void Flush(bool force, int itap); + void OpenTable(int level); + void FlushTable(int level); + TOKEN Fetch(); + void Skip(); + TOKEN Token() { if(!is_full) Fetch(); return token; } + bool PassIf(bool c) { is_full &= !c; return c; } + bool PassText() { return PassIf(Token() == T_TEXT); } + bool PassGroup() { return PassIf(Token() == T_GROUP); } + bool PassEndGroup() { return PassIf(Token() == T_END_GROUP || token == T_EOF); } + bool PassEndGroup(int level); + bool PassCmd(const char *cmd) { return PassIf(Token() == T_COMMAND && command == cmd); } + bool PassQ(const char *cmd) { return PassIf(command == cmd); } + + void SkipGroup() { SkipGroup(stack.GetCount()); } + void SkipGroup(int level); + int Level() const { return stack.GetCount(); } + + void ReadItem(); + void ReadItemGroup(int level); + void ReadItemGroup() { ReadItemGroup(Level()); } + void ReadText(); + void ReadText(const WString& text); + void ReadChar(word ch) { ReadText(WString(ch, 1)); } + void ReadCommand(); + + void ReadHeader(); + void ReadFaceTable(); + void ReadColorTable(); + void ReadCharSet(); + + void ReadMisc(); + void ReadField(); + bool ReadField(const char *def); + void ReadPict(); + void ReadShape(); + + void ReadParaStyle(); + void ReadTableStyle(); + void DefaultParaStyle(); + + void ReadCharStyle(); + + String ReadBinHex(char& odd) const; + +private: + const char *rtf_begin; + const char *rtf; + + TOKEN token; + bool is_full; +// bool new_dest; + bool next_command; + WString text; + String command; + int command_arg; + + struct Cell { + Cell() : end_dots(0), merge_first(false), merge(false) {} + RichTxt text; + RichCell::Format format; + int end_dots; + bool merge_first; + bool merge; + }; + + struct Face : Moveable { + int face; + byte charset; + }; + + struct TableState { + TableState() : textcol(0), stylecol(0) { cells.Add(); } + + RichTable::Format tableformat; + Vector< Array > cells; + int textcol; + int stylecol; + }; + + struct State { + String dest; + RichPara::Format format; + RichPara::CharFormat charformat; + RichCell::Format cellformat; + Rect rowmargin; + Rect rowmarginunits; + Rect cellmarginunits; + int uc_value; + int left_margin; + int right_margin; + int first_indent; + bool in_table; + int itap; + bool nestprop; + bool new_dest; + byte charset; + }; + + Array stack; + Array table_stack; + State state; + RichPara::CharFormat plain_format; + RichPara::Format pard_format; + RichCell::Format std_cell_format; + byte plain_charset; + byte default_charset; + int default_font; + Alignment tab_align; + byte tab_fill; + Vector face_table; + Vector color_table; + int paper_width; + int left_margin; + int right_margin; + + RichText output; + RichPara para; +}; + +RichText ParseRTF(const char *rtf) { return RTFParser(rtf).Run(); } + +RTFParser::RTFParser(const char *rtf) +: rtf_begin(rtf) +, rtf(rtf) +{ +#ifdef _DEBUG + SaveFile(ConfigFile("rtfparser.rtf"), rtf); + LOG(rtf); +#endif + is_full = false; + next_command = false; + default_font = 0; + plain_charset = default_charset = state.charset = CHARSET_WIN1250; + state.uc_value = 1; + state.new_dest = false; + plain_format.Face(Font::ARIAL).Height(100); + std_cell_format.align = ALIGN_TOP; + std_cell_format.margin = Rect(25, 25, 25, 25); + DefaultParaStyle(); + state.charformat = plain_format; + tab_align = ALIGN_LEFT; + tab_fill = 0; + paper_width = 5100; + left_margin = right_margin = 750; +} + +RichText RTFParser::Run() +{ + if(!PassGroup() || !PassCmd("rtf") || command_arg != 1 && !IsNull(command_arg)) + return output; + while(Token() != T_EOF) + ReadItem(); + Flush(false, 1); + FlushTable(0); + return output; +} + +void RTFParser::FlushTable(int level) +{ + while(table_stack.GetCount() > level) { + TableState& child = table_stack.Top(); + while(!child.cells.IsEmpty() && child.cells.Top().IsEmpty()) + child.cells.Drop(); + if(child.cells.IsEmpty()) { + table_stack.Drop(); + continue; + } + Index dot_index; + int pos = child.tableformat.lm; + dot_index.Add(pos); + for(int r = 0; r < child.cells.GetCount(); r++) { + Array& rw = child.cells[r]; + int pos = 0; + for(int c = 0; c < rw.GetCount(); c++) + dot_index.FindAdd(rw[c].end_dots = pos = max(pos + 100, rw[c].end_dots)); + } + Vector dot_order = dot_index.PickKeys(); + Sort(dot_order); + RichTable table; + if(table_stack.GetCount() == 1) + child.tableformat.rm = max(paper_width - left_margin - right_margin - dot_order.Top(), 0); +// child.tableformat.before = state.format.before; +// child.tableformat.after = state.format.after; + table.SetFormat(child.tableformat); + for(int c = 1; c < dot_order.GetCount(); c++) + table.AddColumn(dot_order[c] - dot_order[c - 1]); + dot_index = dot_order; + for(int r = 0; r < child.cells.GetCount(); r++) { + Array& rw = child.cells[r]; + int pos = child.tableformat.lm; + for(int c = 0; c < rw.GetCount(); c++) { + Cell& cell = rw[c]; + if(cell.merge) + continue; + int vspan = 0; + if(cell.merge_first) { + for(int m = r + 1; m < child.cells.GetCount(); m++) { + const Array& mrw = child.cells[m]; + int mc = mrw.GetCount(); + while(--mc >= 0 && mrw[mc].end_dots > cell.end_dots) + ; + if(mc >= 0 && mrw[mc].end_dots == cell.end_dots && mrw[mc].merge) + vspan++; + else + break; + } + } + int nbegin = dot_index.Find(pos); + int hspan = dot_index.Find(pos = cell.end_dots) - nbegin - 1; + hspan = max(hspan, 0); + vspan = max(vspan, 0); +// ASSERT(hspan >= 0 && vspan >= 0); + if(hspan || vspan) + table.SetSpan(r, nbegin, vspan, hspan); + table.SetFormat(r, nbegin, cell.format); + cell.text.Normalize(); + table.SetPick(r, nbegin, cell.text); + } + } + table.Normalize(); + table_stack.Drop(); + if(table_stack.IsEmpty()) + output.CatPick(table); + else { + TableState& par = table_stack.Top(); + par.cells.Top().At(par.textcol).text.CatPick(table); + } + } +} + +void RTFParser::Flush(bool force, int itap) +{ + if(!para.part.IsEmpty() || force) { + int fi = state.first_indent, li = state.left_margin, ri = state.right_margin; + if(state.format.bullet != RichPara::BULLET_NONE) { + li += fi; + fi = -fi; + } + state.format.indent = minmax(fi, 0, MAX_DOTS); + state.format.lm = minmax(li, 0, MAX_DOTS); + state.format.rm = minmax(ri, 0, MAX_DOTS); + para.format = state.format; + if(state.in_table) { + FlushTable(itap); + OpenTable(itap); + TableState& ts = table_stack[itap - 1]; + ts.cells.Top().At(ts.textcol).text.Cat(para, output.GetStyles()); + } + else { + FlushTable(0); + output.Cat(para); + } + para.part.Clear(); + } + else + FlushTable(itap); +} + +RTFParser::TOKEN RTFParser::Fetch() +{ + is_full = true; + text = WString(); + if(next_command) + { + next_command = false; + return token = T_COMMAND; + } + + text = Null; + command = Null; + command_arg = Null; + + int skip = 0; + while(*rtf && *rtf != '{' && *rtf != '}') + { + int c = 0, nskip = max(skip - 1, 0); + if((byte)*rtf < ' ') + rtf++; + else if(*rtf != '\\') + c = ToUnicode(*rtf++, state.charset); + else + switch(rtf++, *rtf++) + { + case 0: { + rtf--; + break; + } + + case '{': + case '}': + case '\\': { + c = rtf[-1]; + break; + } + + case '~': { + c = 160; + break; + } + + case '|': + case '-': + case '_': + case ':': { + command = String(rtf - 1, 1); + if(text.IsEmpty()) + return token = T_COMMAND; + next_command = true; + return token = T_TEXT; + } + + case '\'': { + int c1 = ctoi(*rtf); + if(c1 < 16) { + int c2 = ctoi(*++rtf); + if(c2 < 16) { + c1 = c1 * 16 + c2; + rtf++; + } + c = ToUnicode(c1, state.charset); + } + break; + } + + default: { + if(IsAlpha(*--rtf) || *rtf == '*' && rtf[1] == '\\' && IsAlpha(rtf[2])) { + if(*rtf == '*') { + rtf += 2; + state.new_dest = true; + } + const char *b = rtf; + while(IsAlpha(*++rtf)) + ; + command = String(b, rtf); + if(IsDigit(*rtf) || *rtf == '-') + command_arg = strtol(rtf, (char **)&rtf, 10); + if(*rtf == ' ') + rtf++; + if(command == "uc") + state.uc_value = command_arg; + else if(command == "u") { + c = command_arg; + nskip = state.uc_value; + } + else { // command - quit reading text + if(text.IsEmpty()) + return token = T_COMMAND; + next_command = true; + return token = T_TEXT; + } + } + break; + } + } + if(c && !skip) + text.Cat(c); + skip = nskip; + } + + if(!text.IsEmpty()) + return token = T_TEXT; + + if(*rtf == '{') { + stack.Add(state); + rtf++; + return token = T_GROUP; + } + + if(*rtf == '}') { + if(!stack.IsEmpty()) { + state = stack.Top(); + stack.Drop(); + } + rtf++; + return token = T_END_GROUP; + } + + return token = T_EOF; +} + +bool RTFParser::PassEndGroup(int level) +{ + if(Token() == T_EOF) + return true; + if(token != T_END_GROUP) + return false; + is_full = false; + return Level() < level; +} + +void RTFParser::Skip() +{ + bool is_group = (token == T_GROUP || token == T_COMMAND && state.new_dest); + is_full = false; + if(is_group) + SkipGroup(); +} + +void RTFParser::SkipGroup(int level) +{ + while(!PassEndGroup(level)) + is_full = false; +} + +void RTFParser::ReadItem() +{ + const char *p = rtf; + if(token == T_COMMAND) + ReadCommand(); + else if(token == T_TEXT) + ReadText(); + if(rtf == p && is_full) { + is_full = false; + if(token == T_COMMAND && state.new_dest) + SkipGroup(); + } +} + +void RTFParser::ReadItemGroup(int level) +{ + while(!PassEndGroup(level)) + ReadItem(); +} + +void RTFParser::ReadText() +{ + if(!IsNull(text)) + ReadText(text); +} + +void RTFParser::ReadText(const WString& text) +{ + if(!IsNull(state.dest)) + return; + LLOG("Output text: <" << FromUnicode(text, state.charset) << ">, " << state.charformat); + para.Cat(text, state.charformat); +} + +void RTFParser::ReadCommand() +{ + if(Token() == T_COMMAND) ReadHeader(); + if(Token() == T_COMMAND) ReadMisc(); + if(Token() == T_COMMAND) ReadParaStyle(); + if(Token() == T_COMMAND) ReadTableStyle(); + if(Token() == T_COMMAND) ReadCharStyle(); +} + +void RTFParser::ReadHeader() +{ + if(PassCmd("deff")) + default_font = command_arg; + else if(PassQ("fonttbl")) { + state.dest = command; + ReadFaceTable(); + } + else if(PassQ("colortbl")) { + state.dest = command; + ReadColorTable(); + } + else if(PassQ("stylesheet") || PassQ("list") || PassQ("listoverride") || PassQ("info")) { + state.dest = command; + SkipGroup(); + } + else if(Token() == T_COMMAND) + ReadCharSet(); +} + +void RTFParser::ReadCharSet() +{ + if(PassQ("ansi")) {} + else if(PassQ("mac")) {} + else if(PassQ("pc")) {} + else if(PassQ("pca")) {} + else if(PassQ("ansicpg")) { + static const struct { + int ansicpg; + byte charset; + } + charsets[] = + { + { 1250, CHARSET_WIN1250 }, + { 1251, CHARSET_WIN1251 }, + { 1252, CHARSET_WIN1252 }, + { 1253, CHARSET_WIN1253 }, + { 1254, CHARSET_WIN1254 }, + { 1255, CHARSET_WIN1255 }, + { 1256, CHARSET_WIN1256 }, + { 1257, CHARSET_WIN1257 }, + }; + for(int c = 0; c < __countof(charsets); c++) + if(charsets[c].ansicpg == command_arg) { + default_charset = state.charset = charsets[c].charset; + break; + } + } +} + +void RTFParser::ReadFaceTable() +{ + int fx = 0; + while(!PassEndGroup()) { + if(!PassGroup()) { + Skip(); + continue; + } + Face n; + n.face = Font::ARIAL; + n.charset = default_charset; + while(!PassEndGroup()) { + if(PassCmd("f")) + fx = command_arg; + else if(PassCmd("fnil")) + ; + else if(PassCmd("froman")) + n.face = Font::ROMAN; + else if(PassCmd("fswiss")) + n.face = Font::ARIAL; + else if(PassCmd("fmodern")) + n.face = Font::COURIER; + else if(PassCmd("ftech")) +#ifdef PLATFORM_WIN32 + n.face = Font::SYMBOL; +#else + n.face = Font::ARIAL; +#endif + else if(PassCmd("fcharset")) { + switch(command_arg) { + case 0: n.charset = CHARSET_WIN1252; break; // ANSI + case 1: n.charset = default_charset; break; // Default + case 2: n.charset = CHARSET_WIN1252; break; // Symbol + case 3: break; // Invalid + case 77: break; // Mac + case 128: break; // Shift Jis + case 129: break; // Hangul + case 130: break; // Johab + case 134: break; // GB2312 + case 136: break; // Big5 + case 161: n.charset = CHARSET_WIN1253; break; // Greek + case 162: n.charset = CHARSET_WIN1254; break; // Turkish + case 163: break; // Vietnamese + case 177: n.charset = CHARSET_WIN1255; break; // Hebrew + case 178: break; // Arabic + case 179: break; // Arabic Traditional + case 180: break; // Arabic user + case 181: break; // Hebrew user + case 186: break; // Baltic + case 204: n.charset = CHARSET_WIN1251; break; // Russian + case 222: break; // Thai + case 238: n.charset = CHARSET_WIN1250; break; // Eastern European + case 254: break; // PC 437 + case 255: n.charset = CHARSET_WIN1252; break; // OEM + } + } +/* else if(PassText()) { + String s = FromUnicode(text, charset); + if(!s.IsEmpty() && *s.Last() == ';') + s.Trim(s.GetLength() - 1); + if(!s.IsEmpty()) + f = Font::FindFaceNameIndex(s); + } + else if(PassGroup()) { + int level = Level(); + if(PassCmd("falt") && PassText() && f < 0) + f = Font::FindFaceNameIndex(FromUnicode(text, charset)); + SkipGroup(level); + }*/ //Cxl 2005-11-29 - "Arial CE" makes mess here! + else + Skip(); + } + if(fx >= 0 && fx < MAX_FONTS) { +// if(f < 0) // Cxl 2005-11-29 + if(default_font == fx) { + plain_format.Face(n.face); + plain_charset = n.charset; + } + Face dflt; + dflt.face = Font::ARIAL; + dflt.charset = default_charset; + face_table.At(fx++, dflt) = n; + } + } +} + +void RTFParser::ReadColorTable() +{ + int r = Null, g = Null, b = Null; + for(; !PassEndGroup(); Skip()) + if(PassCmd("red")) + r = command_arg; + else if(PassCmd("green")) + g = command_arg; + else if(PassCmd("blue")) + b = command_arg; + else if(PassText()) + { + Color c = Null; + if(!IsNull(r) || !IsNull(g) || !IsNull(b)) + c = Color(Nvl(r, 0), Nvl(g, 0), Nvl(b, 0)); + color_table.Add(c); + } +} + +void RTFParser::ReadMisc() +{ + if(PassQ("field")) + ReadField(); + else if(PassQ("pict")) + ReadPict(); + else if(PassQ("shpinst")) + ReadShape(); + else if(PassQ("endash")) + ReadChar(0x2013); + else if(PassQ("emdash")) + ReadChar(0x2014); + else if(PassQ("tab")) + ReadText(WString(9, 1)); + else if(PassQ("enspace")) + ReadText(WString(" ")); // todo + else if(PassQ("emspace")) + ReadText(WString(" ")); // todo + else if(PassQ("bullet")) + ReadChar(0x2022); + else if(PassQ("lquote")) + ReadChar(0x2018); + else if(PassQ("rquote")) + ReadChar(0x2019); + else if(PassQ("ldblquote")) + ReadChar(0x201C); + else if(PassQ("rdblquote")) + ReadChar(0x201D); +} + +void RTFParser::ReadField() +{ + bool ign_rslt = false; + int level = Level(); + while(!PassEndGroup(level)) + if(PassGroup() && Level() == level + 1) { + if(PassCmd("fldinst")) { + WString source; + for(; !PassEndGroup(); Skip()) + if(PassText()) + source.Cat(text); + if(ReadField(FromUnicode(source, state.charset))) + ign_rslt = true; + continue; + } + else if(PassCmd("fldrslt")) { + if(!ign_rslt) + ReadItemGroup(); + } + } + else + Skip(); +} + +bool RTFParser::ReadField(const char *p) +{ + Index symdef; + while(*p) + if((byte)*p <= ' ') + p++; + else if(*p == '\"') + symdef.Add(FromCString(p, &p)); + else { + const char *b = p; + while(*++p && *p != ' ') + ; + symdef.Add(String(b, p)); + } + if(symdef.IsEmpty()) + return false; + if(symdef[0] == "SYMBOL" && symdef.GetCount() >= 2 && IsDigit(*symdef[1])) { + int code = atoi(symdef[1]); + int face = -1; + int height = 0; + int f = symdef.Find("\\f"); + if(f >= 0 && f + 1 < symdef.GetCount()) + face = Font::FindFaceNameIndex(symdef[f + 1]); + f = symdef.Find("\\s"); + if(f >= 0 && f + 1 < symdef.GetCount()) + height = PointDots(fround(2 * atof(symdef[f + 1]))) >> 1; + if(face < 0) +#ifdef PLATFORM_WIN32 + face = Font::SYMBOL; +#else + face = Font::ARIAL; +#endif + if(height <= 0 || height >= MAX_DOT_HEIGHT) + height = state.charformat.GetHeight(); + if(code >= 0 && code < 255) { + state.charformat.Face(face).Height(height); + ReadText(WString(ToUnicode(code, state.charset), 1)); + return true; + } + } + return false; +} + +void RTFParser::DefaultParaStyle() +{ + state.format = pard_format; + state.first_indent = state.left_margin = state.right_margin = 0; + state.cellformat = std_cell_format; + state.in_table = false; + state.itap = 1; + state.nestprop = false; + state.rowmargin = Rect(25, 25, 25, 25); + state.cellmarginunits = state.rowmarginunits = Rect(0, 0, 0, 0); + state.charset = plain_charset; +} + +void RTFParser::ReadParaStyle() +{ + if(PassQ("par")) + Flush(true, state.itap); + else if(PassQ("cell")) { + Flush(false, 1); + if(!table_stack.IsEmpty()) + table_stack[0].textcol++; + } + else if(PassQ("nestcell")) { + Flush(false, state.itap); + if(state.itap <= table_stack.GetCount()) + table_stack[state.itap - 1].textcol++; + } + else if(PassQ("pard")) + DefaultParaStyle(); + else if(PassQ("pntext")) + SkipGroup(); + else if(PassQ("pn")) { + SkipGroup(); + state.format.bullet = RichPara::BULLET_ROUND; + } + else if(PassQ("pagebb")) + state.format.newpage = (command_arg != 0); + else if(PassQ("ql")) + state.format.align = ALIGN_LEFT; + else if(PassQ("qc")) + state.format.align = ALIGN_CENTER; + else if(PassQ("qr")) + state.format.align = ALIGN_RIGHT; + else if(PassQ("qj")) + state.format.align = ALIGN_JUSTIFY; + else if(PassQ("fi")) + state.first_indent = TwipDotsLim(command_arg); + else if(PassQ("li")) + state.left_margin = TwipDotsLim(command_arg); + else if(PassQ("ri")) + state.right_margin = TwipDotsLim(command_arg); + else if(PassQ("sb")) + state.format.before = TwipDotsLim(command_arg); + else if(PassQ("sa")) + state.format.after = TwipDotsLim(command_arg); + else if(PassQ("widctlpar")) + state.format.orphan = true; + else if(PassQ("nowidctlpar")) + state.format.orphan = false; + else if(PassQ("tql")) + tab_align = ALIGN_LEFT; + else if(PassQ("tqc")) + tab_align = ALIGN_CENTER; + else if(PassQ("tqr")) + tab_align = ALIGN_RIGHT; + else if(PassQ("tqdec")) + tab_align = ALIGN_RIGHT; // todo + else if(PassQ("tldot")) + tab_fill = 0; + else if(PassQ("tlhyph")) + tab_fill = 0; + else if(PassQ("tlul")) + tab_fill = 0; + else if(PassQ("tlth")) + tab_fill = 0; + else if(PassQ("tleq")) + tab_fill = 0; + else if(PassQ("tx") || PassQ("tb")) { // todo: bar tab ? + int pos = TwipDotSize(command_arg); + RichPara::Tab& tab = state.format.tab.Add(); + tab.align = tab_align; + tab.fillchar = tab_fill; + tab.pos = pos; + state.format.SortTabs(); + } + else if(PassQ("intbl")) + state.in_table = true; + else if(PassQ("itap")) { + state.itap = minmax(command_arg, 1, 10); + if(table_stack.GetCount() < state.itap) + OpenTable(state.itap); + } +} + +void RTFParser::ReadCharStyle() +{ + if(PassQ("plain")) { + state.charformat = plain_format; + state.charset = plain_charset; + } + else if(PassQ("b")) + state.charformat.Bold(command_arg != 0); + else if(PassQ("i")) + state.charformat.Italic(command_arg != 0); + else if(PassQ("ul") || PassQ("uld") || PassQ("uldb") + || PassQ("uldash") || PassQ("uldashd") || PassQ("uldashdd") + || PassQ("ulth") || PassQ("ulw") || PassQ("ulwave")) + state.charformat.Underline(); + else if(PassQ("ulnone")) + state.charformat.Underline(false); + else if(PassQ("strike") || PassQ("strikedl")) + state.charformat.Strikeout(command_arg != 0); + else if(PassQ("caps") || PassQ("scaps")) + state.charformat.capitals = (command_arg != 0); + else if(PassQ("super") || PassQ("up")) + state.charformat.sscript = 1; + else if(PassQ("sub") || PassQ("dn")) + state.charformat.sscript = 2; + else if(PassQ("nosupersub")) + state.charformat.sscript = 0; + else if(PassQ("f") && command_arg >= 0 && command_arg < face_table.GetCount()) { + LLOG("font = " << command_arg << ", face = " << face_table[command_arg].face + << ", charset = " << face_table[command_arg].charset); + state.charformat.Face(face_table[command_arg].face); + state.charset = face_table[command_arg].charset; + } + else if(PassQ("fs")) + state.charformat.Height(PointDotHeight(command_arg)); + else if(PassQ("cf") && command_arg >= 0 && command_arg < color_table.GetCount()) + state.charformat.ink = Nvl(color_table[command_arg], Black); + else if(PassQ("cb") && command_arg >= 0 && command_arg < color_table.GetCount()) + state.charformat.paper = color_table[command_arg]; + else if(PassQ("lang")) + {} // state.language = ... +} + +void RTFParser::ReadShape() +{ + int level = Level(); + while(!PassEndGroup(level)) + if(PassCmd("shppict")) { + state.new_dest = false; + ReadItemGroup(); + } + else + is_full = false; +} + +void RTFParser::ReadPict() +{ + Size log_size(1, 1), out_size(1, 1), scaling(100, 100); + Rect crop(0, 0, 0, 0); + enum BLIPTYPE { UNK_BLIP, EMF_BLIP, PNG_BLIP, JPEG_BLIP, WMF_BLIP, DIB_BLIP }; + BLIPTYPE blip_type = UNK_BLIP; +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + int wmf_mode = MM_ANISOTROPIC; +#endif +#endif + String blip_data; + char odd = 0; + while(!PassEndGroup()) + if(PassText()) + blip_data.Cat(ReadBinHex(odd)); + else if(Token() == T_COMMAND) { + if(PassQ("picw")) log_size.cx = minmax(command_arg, 0, 30000); + else if(PassQ("pich")) log_size.cy = minmax(command_arg, 0, 30000); + else if(PassQ("picwgoal")) out_size.cx = TwipDotSize(command_arg); + else if(PassQ("pichgoal")) out_size.cy = TwipDotSize(command_arg); + else if(PassQ("picscalex")) scaling.cx = minmax(command_arg, 1, 1000); + else if(PassQ("picscaley")) scaling.cy = minmax(command_arg, 1, 1000); + else if(PassQ("piccropl")) crop.left = TwipDotSize(command_arg); + else if(PassQ("piccropt")) crop.top = TwipDotSize(command_arg); + else if(PassQ("piccropr")) crop.right = TwipDotSize(command_arg); + else if(PassQ("piccropb")) crop.bottom = TwipDotSize(command_arg); + else if(PassQ("emfblip")) blip_type = EMF_BLIP; + else if(PassQ("pngblip")) blip_type = PNG_BLIP; + else if(PassQ("jpegblip")) blip_type = JPEG_BLIP; +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + else if(PassQ("wmetafile")) { blip_type = WMF_BLIP; wmf_mode = command_arg; } +#endif +#endif + else if(PassQ("dibitmap")) blip_type = DIB_BLIP; + else Skip(); + } + else + Skip(); + Size final_size = minmax(iscale(out_size, scaling, Size(100, 100)), Size(1, 1), Size(30000, 30000)); + Size drawing_size; + DrawingDraw dd; + RichObject object; +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + if(blip_type == EMF_BLIP || blip_type == WMF_BLIP) { + log_size = min(log_size, GetFitSize(log_size, final_size)); + dd.Create(drawing_size = log_size); + WinMetaFile wmf; + if(blip_type == EMF_BLIP) + wmf = WinMetaFile(SetEnhMetaFileBits(blip_data.GetLength(), blip_data)); + else { + METAFILEPICT mfp; + Zero(mfp); + mfp.mm = wmf_mode; + mfp.xExt = log_size.cx; + mfp.yExt = log_size.cy; + wmf = WinMetaFile(SetWinMetaFileBits(blip_data.GetLength(), blip_data, ScreenHDC(), &mfp)); + } + wmf.Paint(dd, log_size); + object = CreateDrawingObject(dd, out_size, final_size); + } + else +#endif +#endif + if(blip_type == DIB_BLIP || blip_type == PNG_BLIP || blip_type == JPEG_BLIP) { + //FIXIMAGE + Image image = StreamRaster::LoadStringAny(blip_data); + object = CreatePNGObject(image, out_size, final_size); + } + if(object) { + LLOG("object (" << object.GetTypeName() << ", " << object.Write().GetLength() << " B), pixel size " + << object.GetPixelSize() << ", final size " << object.GetSize()); + para.Cat(object, state.charformat); + } +} + +String RTFParser::ReadBinHex(char& odd) const +{ + int t = odd; + byte v = ctoi(odd); + String out; + for(const wchar *s = text.Begin(); *s; s++) { + byte w = (*s >= '0' && *s <= '9' ? *s - '0' + : *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 + : *s >= 'a' && *s <= 'f' ? *s - 'a' + 10 + : 255); + if(w < 16) + if(v >= 16) + { + t = *s; + v = w; + } + else + { + out.Cat(16 * v + w); + v = 255; + } + } + odd = (v < 16 ? t : 0); + return out; +} + +void RTFParser::OpenTable(int level) +{ + if(table_stack.GetCount() < level) { + TableState& ts = table_stack.At(level - 1); + ts.stylecol = 0; + state.cellformat = std_cell_format; + } +} + +void RTFParser::ReadTableStyle() +{ + if(PassQ("nesttableprops")) { + state.nestprop = true; + return; + } + if(PassQ("nonesttables")) { + SkipGroup(); + return; + } + int itap = (state.nestprop ? state.itap : 1); + if(PassQ("trowd")) { + OpenTable(itap); + table_stack[itap - 1].stylecol = 0; + return; + } + if(PassQ("row") && table_stack.GetCount() >= 1) { + TableState& ts0 = table_stack[0]; + ts0.textcol = ts0.stylecol = 0; + ts0.cells.Add(); + return; + } + if(PassQ("nestrow") && table_stack.GetCount() >= state.itap) { + TableState& ts = table_stack[state.itap - 1]; + ts.textcol = ts.stylecol = 0; + ts.cells.Add(); + return; + } + if(itap > table_stack.GetCount()) + return; + TableState& ts = table_stack[itap - 1]; + if(PassQ("trgaph")) {} + else if(PassQ("trql")) {} + else if(PassQ("trqr")) {} + else if(PassQ("trqc")) {} + else if(PassQ("trleft")) { + ts.tableformat.lm = TwipDotsLim(command_arg); + } + else if(PassQ("trbrdrl")) {} + else if(PassQ("trbrdrt")) {} + else if(PassQ("trbrdrr")) {} + else if(PassQ("trbrdrb")) {} + else if(PassQ("trbrdrv")) {} + else if(PassQ("trftsWidth")) {} + else if(PassQ("trautofit")) {} + else if(PassQ("trpaddl")) + state.rowmargin.left = TwipDotsLim(command_arg); + else if(PassQ("trpaddt")) + state.rowmargin.top = TwipDotsLim(command_arg); + else if(PassQ("trpaddr")) + state.rowmargin.right = TwipDotsLim(command_arg); + else if(PassQ("trpaddb")) + state.rowmargin.bottom = TwipDotsLim(command_arg); + else if(PassQ("trpaddfl")) + state.rowmarginunits.left = command_arg; + else if(PassQ("trpaddft")) + state.rowmarginunits.top = command_arg; + else if(PassQ("trpaddfr")) + state.rowmarginunits.right = command_arg; + else if(PassQ("trpaddfb")) + state.rowmarginunits.bottom = command_arg; + else if(PassQ("clpadl")) + state.cellformat.margin.left = TwipDotsLim(command_arg); + else if(PassQ("clpadt")) + state.cellformat.margin.top = TwipDotsLim(command_arg); + else if(PassQ("clpadr")) + state.cellformat.margin.right = TwipDotsLim(command_arg); + else if(PassQ("clpadb")) + state.cellformat.margin.bottom = TwipDotsLim(command_arg); + else if(PassQ("clpadfl")) + state.cellmarginunits.left = command_arg; + else if(PassQ("clpadft")) + state.cellmarginunits.top = command_arg; + else if(PassQ("clpadfr")) + state.cellmarginunits.right = command_arg; + else if(PassQ("clpadfb")) + state.cellmarginunits.bottom = command_arg; + else if(PassQ("clvertalt")) {} + else if(PassQ("clbrdrl")) {} + else if(PassQ("clbrdrt")) {} + else if(PassQ("clbrdrr")) {} + else if(PassQ("clbrdrb")) {} + else if(PassQ("cltxlrtb")) {} + else if(PassQ("clcbpat")) { + if(command_arg >= 0 && command_arg < color_table.GetCount()) + state.cellformat.color = color_table[command_arg]; + } + else if(PassQ("clvmrg")) + ts.cells.Top().At(ts.stylecol).merge = true; + else if(PassQ("clvmgf")) + ts.cells.Top().At(ts.stylecol).merge_first = true; + else if(PassQ("clftsWidth")) {} + else if(PassQ("clwWidth")) {} + else if(PassQ("cellx")) { + Cell& newcell = ts.cells.Top().At(ts.stylecol++); + newcell.end_dots = TwipDotsLim(command_arg); + newcell.format = state.cellformat; + if(state.cellmarginunits.left == 0) newcell.format.margin.left = state.rowmargin.left; + if(state.cellmarginunits.top == 0) newcell.format.margin.top = state.rowmargin.top; + if(state.cellmarginunits.right == 0) newcell.format.margin.right = state.rowmargin.right; + if(state.cellmarginunits.bottom == 0) newcell.format.margin.bottom = state.rowmargin.bottom; + state.cellformat = std_cell_format; + } + else if(PassQ("clvertalt")) + state.cellformat.align = ALIGN_TOP; + else if(PassQ("clvertalc")) + state.cellformat.align = ALIGN_CENTER; + else if(PassQ("clvertalb")) + state.cellformat.align = ALIGN_BOTTOM; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/CtrlCore/SystemDraw.cpp b/uppsrc/CtrlCore/SystemDraw.cpp index 8cd0d6d4f..7f6fd20db 100644 --- a/uppsrc/CtrlCore/SystemDraw.cpp +++ b/uppsrc/CtrlCore/SystemDraw.cpp @@ -1,59 +1,83 @@ -#include "SystemDraw.h" - -NAMESPACE_UPP - -#define LTIMING(x) - -void SystemDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) -{ - GuiLock __; - LTIMING("DrawImageOp"); - bool tonative = !IsNative(); - if(tonative) { - BeginNative(); - Native(x, y); - Native(cx, cy); - } - Size sz = Size(cx, cy); - if((cx > 2000 || cy > 1500) && IsNull(color) && IsPrinter()) { - int yy = 0; - ImageRaster ir(img); - RescaleImage rm; - rm.Create(Size(cx, cy), ir, src); - while(yy < cy) { - int ccy = min(cy - yy, 16); - ImageBuffer ib(cx, ccy); - for(int q = 0; q < ccy; q++) - rm.Get(ib[q]); - DrawImageBandRLE(*this, x, y + yy, ib, 16); - yy += ccy; - } - } - else - if(src.GetSize() == sz) - img.PaintImage(*this, x, y, src, color); - else { - Image h = Rescale(img, Size(cx, cy), src); - h.PaintImage(*this, x, y, h.GetSize(), color); - } - if(tonative) - EndNative(); -} - - -Draw& ImageDraw::Alpha() -{ - if(!has_alpha) { - alpha.DrawRect(size, GrayColor(0)); - has_alpha = true; - } - return alpha; -} - -ImageBuffer::ImageBuffer(ImageDraw& iw) -{ - Image m = iw; - Set(m); -} - -END_UPP_NAMESPACE +#include "SystemDraw.h" + +NAMESPACE_UPP + +#define LTIMING(x) + +void SystemDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + GuiLock __; + LTIMING("DrawImageOp"); + bool tonative = !IsNative(); + if(tonative) { + BeginNative(); + Native(x, y); + Native(cx, cy); + } + Size sz = Size(cx, cy); + if((cx > 2000 || cy > 1500) && IsNull(color) && IsPrinter()) { + int yy = 0; + ImageRaster ir(img); + RescaleImage rm; + rm.Create(Size(cx, cy), ir, src); + while(yy < cy) { + int ccy = min(cy - yy, 16); + ImageBuffer ib(cx, ccy); + for(int q = 0; q < ccy; q++) + rm.Get(ib[q]); + DrawImageBandRLE(*this, x, y + yy, ib, 16); + yy += ccy; + } + } + else + if(src.GetSize() == sz) + img.PaintImage(*this, x, y, src, color); + else { + Image h = Rescale(img, Size(cx, cy), src); + h.PaintImage(*this, x, y, h.GetSize(), color); + } + if(tonative) + EndNative(); +} + + +Draw& ImageDraw::Alpha() +{ + if(!has_alpha) { + alpha.DrawRect(size, GrayColor(0)); + has_alpha = true; + } + return alpha; +} + +ImageBuffer::ImageBuffer(ImageDraw& iw) +{ + Image m = iw; + Set(m); +} + +void ImageAnyDrawSystem(Draw *(*f)(Size sz), Image (*e)(Draw *w)); + +static Draw *sCD(Size sz) +{ + return new ImageDraw(sz); +} + +static Image sED(Draw *w) +{ + ImageDraw *ip = dynamic_cast(w); + return ip ? (Image)(*ip) : Image(); +} + +void InstallSystemImage() +{ + Image::Data::InitSystemImage(&Image::Data::SysInitImp, &Image::Data::SysReleaseImp, + &Image::Data::GetResCountImp, &Image::Data::PaintImp); +} + +INITBLOCK { + ImageAnyDrawSystem(sCD, sED); + InstallSystemImage(); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/CtrlCore/init b/uppsrc/CtrlCore/init index 6ee00ffd7..257bf025f 100644 --- a/uppsrc/CtrlCore/init +++ b/uppsrc/CtrlCore/init @@ -2,7 +2,8 @@ #define _CtrlCore_icpp_init_stub #include "Draw/init" #include "plugin\bmp/init" -#define BLITZ_INDEX__ F50C6488AA9AC98A955BA0CD0115A83C1 +#include "RichText/init" +#define BLITZ_INDEX__ F6E9203F1134FEED56F48EBA40A86EC94 #include "CtrlCore.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/CtrlLib/CtrlLib.h b/uppsrc/CtrlLib/CtrlLib.h index e4ff7c1d2..76371fc4f 100644 --- a/uppsrc/CtrlLib/CtrlLib.h +++ b/uppsrc/CtrlLib/CtrlLib.h @@ -2,7 +2,6 @@ #define CTRLLIB_H #include -#include NAMESPACE_UPP diff --git a/uppsrc/CtrlLib/CtrlLib.upp b/uppsrc/CtrlLib/CtrlLib.upp index 34a930b4b..3fe6fa200 100644 --- a/uppsrc/CtrlLib/CtrlLib.upp +++ b/uppsrc/CtrlLib/CtrlLib.upp @@ -4,8 +4,7 @@ acceptflags NOGTK; uses - CtrlCore, - RichText; + CtrlCore; uses(POSIX | LINUX | FREEBSD) PdfDraw; diff --git a/uppsrc/CtrlLib/init b/uppsrc/CtrlLib/init index fa03e1461..8d7d9f9c7 100644 --- a/uppsrc/CtrlLib/init +++ b/uppsrc/CtrlLib/init @@ -1,9 +1,8 @@ #ifndef _CtrlLib_icpp_init_stub #define _CtrlLib_icpp_init_stub #include "CtrlCore/init" -#include "RichText/init" #include "PdfDraw/init" -#define BLITZ_INDEX__ F57B71893CA53B1803608C307020EC5D8 +#define BLITZ_INDEX__ F0B03D5D3AD4DE5D8FCD3A246E4FAC29A #include "CtrlLib.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index 9fb64e7b5..0d07de9e5 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -757,6 +757,52 @@ public: virtual void DrawPaintingOp(const Rect& target, const Painting& w); }; +class ImageAnyDraw : public Draw { + Draw *draw; + + void Init(Size sz); + +public: + virtual dword GetInfo() const; + virtual Size GetPageSize() const; + virtual void BeginOp(); + virtual void EndOp(); + virtual void OffsetOp(Point p); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual bool IsPaintingOp(const Rect& r) const; + virtual Rect GetPaintRect() const; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx); + virtual void DrawDrawingOp(const Rect& target, const Drawing& w); + virtual void DrawPaintingOp(const Rect& target, const Painting& w); + +public: + operator Image() const; + + ImageAnyDraw(Size sz); + ImageAnyDraw(int cx, int cy); + + ~ImageAnyDraw(); +}; + void AddNotEmpty(Vector& result, int left, int right, int top, int bottom); bool Subtract(const Rect& r, const Rect& sub, Vector& result); bool Subtract(const Vector& rr, const Rect& sub, Vector& result); diff --git a/uppsrc/Draw/Draw.upp b/uppsrc/Draw/Draw.upp index 944aa92b7..058572629 100644 --- a/uppsrc/Draw/Draw.upp +++ b/uppsrc/Draw/Draw.upp @@ -6,23 +6,15 @@ acceptflags uses Core; -library((LINUX | BSD) & !NOGTK) "gtk-x11-2.0 gdk-x11-2.0 atk-1.0 gdk_pixbuf-2.0 m pangocairo-1.0 fontconfig Xext Xrender Xinerama Xi Xrandr Xcursor Xfixes pango-1.0 cairo X11 gobject-2.0 gmodule-2.0 glib-2.0"; - library(WIN32 !MSC8ARM) "user32 gdi32"; -library(LINUX) X11; - library(LINUX) dl; -library(LINUX !XLFD) Xft; +library(BSD !XLFD) "fontconfig freetype expat"; -library(BSD) "X11 Xau Xdmcp"; +library(LINUX !XLFD) "fontconfig expat"; -library(BSD !XLFD) "Xft fontconfig Xrender freetype expat"; - -library(LINUX !XLFD !SHARED) "fontconfig Xrender freetype expat"; - -library(OSX11) "X11 Xft fontconfig Xrender freetype expat"; +library(OSX11) "fontconfig freetype expat"; library(FREEBSD) xcb; @@ -38,6 +30,7 @@ file DrawText.cpp, DrawData.cpp, Drawing.cpp, + ImageAnyDraw.cpp, DrawUtil.cpp, DrawTextUtil.cpp, Display.h, diff --git a/uppsrc/Draw/Image.cpp b/uppsrc/Draw/Image.cpp index f6068efec..6885a0dd2 100644 --- a/uppsrc/Draw/Image.cpp +++ b/uppsrc/Draw/Image.cpp @@ -1,687 +1,730 @@ -#include "Draw.h" - -NAMESPACE_UPP - -#define LTIMING(x) // RTIMING(x) - -int ImageBuffer::ScanKind() const -{ - bool a255 = false; - bool a0 = false; - const RGBA *s = pixels; - const RGBA *e = s + GetLength(); - while(s < e) { - if(s->a == 0) - a0 = true; - else - if(s->a == 255) - a255 = true; - else - return IMAGE_ALPHA; - s++; - } - return a255 ? a0 ? IMAGE_MASK : IMAGE_OPAQUE : IMAGE_EMPTY; -} - -void ImageBuffer::Create(int cx, int cy) -{ - ASSERT(cx >= 0 && cy >= 0); - size.cx = cx; - size.cy = cy; - pixels.Alloc(GetLength()); -#ifdef _DEBUG - RGBA *s = pixels; - RGBA *e = pixels + GetLength(); - byte a = 0; - while(s < e) { - s->a = a; - a = ~a; - s->r = 255; - s->g = s->b = 0; - s++; - } -#endif - kind = IMAGE_UNKNOWN; - spot2 = hotspot = Point(0, 0); - dots = Size(0, 0); -} - -void ImageBuffer::DeepCopy(const ImageBuffer& img) -{ - Create(img.GetSize()); - SetHotSpot(img.GetHotSpot()); - Set2ndSpot(img.Get2ndSpot()); - SetDots(img.GetDots()); - memcpy(pixels, img.pixels, GetLength() * sizeof(RGBA)); -} - -void ImageBuffer::Set(Image& img) -{ - if(img.data) - if(img.data->refcount == 1) { - size = img.GetSize(); - kind = IMAGE_UNKNOWN; - hotspot = img.GetHotSpot(); - spot2 = img.Get2ndSpot(); - dots = img.GetDots(); - pixels = img.data->buffer.pixels; - img.Clear(); - } - else { - DeepCopy(img.data->buffer); - kind = IMAGE_UNKNOWN; - img.Clear(); - } - else - Create(0, 0); -} - - -void ImageBuffer::operator=(Image& img) -{ - Clear(); - Set(img); -} - -void ImageBuffer::operator=(ImageBuffer& img) -{ - Clear(); - Image m = img; - Set(m); -} - -ImageBuffer::ImageBuffer(Image& img) -{ - Set(img); -} - -ImageBuffer::ImageBuffer(ImageBuffer& b) -{ - kind = b.kind; - size = b.size; - dots = b.dots; - pixels = b.pixels; - hotspot = b.hotspot; - spot2 = b.spot2; -} - -void Image::Set(ImageBuffer& b) -{ - if(b.GetWidth() == 0 || b.GetHeight() == 0) - data = NULL; - else - data = new Data(b); -} - -void Image::Clear() -{ - if(data) - data->Release(); - data = NULL; -} - -Image& Image::operator=(ImageBuffer& img) -{ - if(data) - data->Release(); - Set(img); - return *this; -} - -Image& Image::operator=(const Image& img) -{ - Data *d = data; - data = img.data; - if(data) - data->Retain(); - if(d) - d->Release(); - return *this; -} - -const RGBA* Image::operator~() const -{ - return data ? ~data->buffer : NULL; -} - -Image::operator const RGBA*() const -{ - return data ? ~data->buffer : NULL; -} - -const RGBA* Image::operator[](int i) const -{ - ASSERT(data); - return data->buffer[i]; -} - -Size Image::GetSize() const -{ - return data ? data->buffer.GetSize() : Size(0, 0); -} - -int Image::GetLength() const -{ - return data ? data->buffer.GetLength() : 0; -} - -Point Image::GetHotSpot() const -{ - return data ? data->buffer.GetHotSpot() : Point(0, 0); -} - -Point Image::Get2ndSpot() const -{ - return data ? data->buffer.Get2ndSpot() : Point(0, 0); -} - -Size Image::GetDots() const -{ - return data ? data->buffer.GetDots() : Size(0, 0); -} - -int Image::GetKindNoScan() const -{ - return data ? data->buffer.GetKind() : IMAGE_EMPTY; -} - -int Image::Data::GetKind() -{ - int k = buffer.GetKind(); - if(k != IMAGE_UNKNOWN) - return k; - k = buffer.ScanKind(); - buffer.SetKind(k); - return k; -} - -int Image::GetKind() const -{ - return data ? data->GetKind() : IMAGE_EMPTY; -} - -void Image::PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const -{ - if(data) - data->Paint(w, x, y, src, c); -} - -void Image::Serialize(Stream& s) -{ - int version = 0; - s / version; - Size sz = GetSize(); - Point p = GetHotSpot(); - Size dots = GetDots(); - s % sz % p % dots; - int len = sz.cx * sz.cy; - if(s.IsLoading()) - if(len) { - ImageBuffer b(sz); - if(!s.GetAll(~b, len * sizeof(RGBA))) - s.SetError(); - b.SetDots(dots); - b.SetHotSpot(p); - *this = b; - } - else - Clear(); - else - s.Put(~*this, len * sizeof(RGBA)); -} - -INITBLOCK { - RichValue::Register(); -} - -bool Image::operator==(const Image& img) const -{ - if(GetLength() != img.GetLength()) - return false; - return memcmp(~*this, ~img, GetLength() * sizeof(RGBA)) == 0; -} - -bool Image::operator!=(const Image& img) const -{ - return !operator==(img); -} - -dword Image::GetHashValue() const -{ - return memhash(~*this, GetLength() * sizeof(RGBA)); -} - -Image::Image(const Image& img) -{ - data = img.data; - if(data) - data->Retain(); -} - -Image::Image(Image (*fn)()) -{ - data = NULL; - *this = (*fn)(); -} - -Image::Image(const Value& src) -{ - data = NULL; - if(!IsNull(src)) - *this = RawValue::Extract(src); -} - -Image::Image(ImageBuffer& b) -{ - Set(b); -} - -Image::~Image() -{ - if(data) - data->Release(); -} - -Image::Image(const Init& init) -{ - ASSERT(init.info[0] >= 1); - Size sz; - sz.cx = Peek32le(init.info + 1); - sz.cy = Peek32le(init.info + 5); - ImageBuffer b(sz); - int i = 0; - while(i < init.scan_count) { - UnpackRLE(b[i], (const byte *)init.scans[i], sz.cx); - i++; - } - while(i < sz.cy) - memset(b[i++], 0, sizeof(RGBA) * sz.cx); - b.SetHotSpot(Point(Peek32le(init.info + 9), Peek32le(init.info + 13))); - Set(b); -} - -String Image::ToString() const -{ - return String("Image ").Cat() << GetSize(); -} - -Link Image::Data::ResData[1]; -int Image::Data::ResCount; - -Image::Data::Data(ImageBuffer& b) -: buffer(b) -{ - paintcount = 0; - paintonly = false; - refcount = 1; - INTERLOCKED { - static int64 gserial; - serial = ++gserial; - } - SysInit(); -} - -Image::Data::~Data() -{ - DrawLock __; - SysRelease(); - Unlink(); -} - -void Image::Data::PaintOnlyShrink() -{ - if(paintonly) { - LTIMING("PaintOnlyShrink"); - DrawLock __; - DropPixels___(buffer); - ResCount -= GetResCount(); - Unlink(); - } -} - -static void sMultiply(ImageBuffer& b, int (*op)(RGBA *t, const RGBA *s, int len)) -{ - if(b.GetKind() != IMAGE_OPAQUE && b.GetKind() != IMAGE_EMPTY) - (*op)(~b, ~b, b.GetLength()); -} - -void Premultiply(ImageBuffer& b) -{ - sMultiply(b, Premultiply); -} - -void Unmultiply(ImageBuffer& b) -{ - sMultiply(b, Unmultiply); -} - -static Image sMultiply(const Image& img, int (*op)(RGBA *t, const RGBA *s, int len)) -{ - int k = img.GetKind(); - if(k == IMAGE_OPAQUE || k == IMAGE_EMPTY) - return img; - ImageBuffer ib(img.GetSize()); - ib.SetHotSpot(img.GetHotSpot()); - ib.Set2ndSpot(img.Get2ndSpot()); - ib.SetKind(Premultiply(~ib, ~img, ib.GetLength())); - return ib; -} - -Image Premultiply(const Image& img) -{ - return sMultiply(img, Premultiply); -} - -Image Unmultiply(const Image& img) -{ - return sMultiply(img, Unmultiply); -} - -void SetPaintOnly___(Image& m) -{ - if(m.data && m.data->refcount == 1) - m.data->paintonly = true; -} - -void Iml::Init(int n) -{ - for(int i = 0; i < n; i++) - map.Add(name[i]); -} - -void Iml::Reset() -{ - int n = map.GetCount(); - map.Clear(); - Init(n); -} - -void Iml::Set(int i, const Image& img) -{ - map[i].image = img; - map[i].loaded = true; -} - -static StaticCriticalSection sImgImlLock; - -Image Iml::Get(int i) -{ - IImage& m = map[i]; - if(!m.loaded) { - INTERLOCKED_(sImgImlLock) { - if(data.GetCount()) { - int ii = 0; - for(;;) { - const Data& d = data[ii]; - if(i < d.count) { - static const char *cached_data; - static Vector cached; - if(cached_data != d.data) { - cached_data = d.data; - cached = UnpackImlData(String(d.data, d.len)); - if(premultiply) - for(int i = 0; i < cached.GetCount(); i++) - cached[i] = Premultiply(cached[i]); - } - m.image = cached[i]; - break; - } - i -= d.count; - ii++; - } - } - else - m.image = Premultiply(Image(img_init[i])); - } - m.loaded = true; - } - return m.image; -} - -#ifdef _DEBUG -int Iml::GetBinSize() const -{ - int size = 0; - for(int i = 0; i < map.GetCount(); i++) { - const Image::Init& init = img_init[i]; - size += (int)strlen(name[i]) + 1 + 24; - for(int q = 0; q < init.scan_count; q++) - size += (int)strlen(init.scans[q]); - } - return size; -} -#endif - -Iml::Iml(const Image::Init *img_init, const char **name, int n) -: img_init(img_init), - name(name) -{ -#ifdef flagCHECKINIT - RLOG("Constructing iml " << *name); -#endif - premultiply = true; - Init(n); -} - -void Iml::AddData(const byte *_data, int len, int count) -{ - Data& d = data.Add(); - d.data = (const char *)_data; - d.len = len; - d.count = count; - data.Shrink(); -} - -static StaticCriticalSection sImgMapLock; - -static VectorMap& sImgMap() -{ - static VectorMap x; - return x; -} - -void Register(const char *imageclass, Iml& list) -{ -#ifdef flagCHECKINIT - RLOG("Registering iml " << imageclass); -#endif - INTERLOCKED_(sImgMapLock) - sImgMap().GetAdd(imageclass) = &list; -} - -int GetImlCount() -{ - int q; - INTERLOCKED_(sImgMapLock) - q = sImgMap().GetCount(); - return q; -} - -Iml& GetIml(int i) -{ - return *sImgMap()[i]; -} - -void Iml::Enter() -{ - sImgMapLock.Enter(); -} - -void Iml::Leave() -{ - sImgMapLock.Leave(); -} - -String GetImlName(int i) -{ - String x; - INTERLOCKED_(sImgMapLock) - x = sImgMap().GetKey(i); - return x; -} - -int FindIml(const char *name) -{ - int q; - INTERLOCKED_(sImgMapLock) - q = sImgMap().Find(name); - return q; -} - -Image GetImlImage(const char *name) -{ - Image m; - const char *w = strchr(name, ':'); - if(w) { - int q = FindIml(String(name, w)); - if(q >= 0) { - INTERLOCKED_(sImgMapLock) { - Iml& iml = *sImgMap()[q]; - while(*w == ':') - w++; - q = iml.Find(w); - if(q >= 0) - m = iml.Get(q); - } - } - } - return m; -} - -void SetImlImage(const char *name, const Image& m) -{ - const char *w = strchr(name, ':'); - if(w) { - int q = FindIml(String(name, w)); - if(q >= 0) { - INTERLOCKED_(sImgMapLock) { - Iml& iml = *sImgMap()[q]; - while(*w == ':') - w++; - q = iml.Find(w); - if(q >= 0) - iml.Set(q, m); - } - } - } -} - -String StoreImageAsString(const Image& img) -{ - if(img.GetKind() == IMAGE_EMPTY) - return Null; - int type = img.GetKind() == IMAGE_OPAQUE ? 3 : 4; - StringStream ss; - ss.Put(type); - Size sz = img.GetSize(); - ss.Put16le(sz.cx); - ss.Put16le(sz.cy); - Point p = img.GetHotSpot(); - ss.Put16le(p.x); - ss.Put16le(p.y); - Size dots = img.GetDots(); - ss.Put16le(dots.cx); - ss.Put16le(dots.cy); - const RGBA *s = img; - const RGBA *e = s + img.GetLength(); - Buffer b(type * img.GetLength()); - byte *t = b; - if(type == 3) - while(s < e) { - *t++ = s->r; - *t++ = s->g; - *t++ = s->b; - s++; - } - else - while(s < e) { - *t++ = s->r; - *t++ = s->g; - *t++ = s->b; - *t++ = s->a; - s++; - } - MemReadStream m(b, type * img.GetLength()); - ZCompress(ss, m); - return ss; -} - -Image LoadImageFromString(const String& src) -{ - if(src.GetLength() < 13) - return Null; - StringStream ss(src); - int type = ss.Get(); - Size sz; - sz.cx = ss.Get16le(); - sz.cy = ss.Get16le(); - if(sz.cx < 0 || sz.cy < 0) - return Null; - Point p; - p.x = ss.Get16le(); - p.y = ss.Get16le(); - if(p.x < 0 || p.y < 0) - return Null; - Size dots; - dots.cx = ss.Get16le(); - dots.cy = ss.Get16le(); - if(dots.cx < 0 || dots.cy < 0) - return Null; - StringStream out; - ZDecompress(out, ss); - String data = out; - if(data.GetLength() != type * sz.cx * sz.cy) - return Image(); - ImageBuffer ib(sz); - ib.SetHotSpot(p); - ib.SetDots(dots); - RGBA *t = ib; - const RGBA *e = t + ib.GetLength(); - const byte *s = data; - if(type == 3) - while(t < e) { - t->r = *s++; - t->g = *s++; - t->b = *s++; - t->a = 255; - t++; - } - else - if(type == 4) - while(t < e) { - t->r = *s++; - t->g = *s++; - t->b = *s++; - t->a = *s++; - t++; - } - else - return Image(); - return ib; -} - -Size GetImageStringSize(const String& src) -{ - if(src.GetLength() < 13) - return Size(0, 0); - StringStream ss(src); - ss.Get(); - Size sz; - sz.cx = ss.Get16le(); - sz.cy = ss.Get16le(); - return sz; -} - -Size GetImageStringDots(const String& src) -{ - if(src.GetLength() < 13) - return Size(0, 0); - StringStream ss(src); - ss.SeekCur(9); - Size sz; - sz.cx = ss.Get16le(); - sz.cy = ss.Get16le(); - return sz; -} - -END_UPP_NAMESPACE +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +int ImageBuffer::ScanKind() const +{ + bool a255 = false; + bool a0 = false; + const RGBA *s = pixels; + const RGBA *e = s + GetLength(); + while(s < e) { + if(s->a == 0) + a0 = true; + else + if(s->a == 255) + a255 = true; + else + return IMAGE_ALPHA; + s++; + } + return a255 ? a0 ? IMAGE_MASK : IMAGE_OPAQUE : IMAGE_EMPTY; +} + +void ImageBuffer::Create(int cx, int cy) +{ + ASSERT(cx >= 0 && cy >= 0); + size.cx = cx; + size.cy = cy; + pixels.Alloc(GetLength()); +#ifdef _DEBUG + RGBA *s = pixels; + RGBA *e = pixels + GetLength(); + byte a = 0; + while(s < e) { + s->a = a; + a = ~a; + s->r = 255; + s->g = s->b = 0; + s++; + } +#endif + kind = IMAGE_UNKNOWN; + spot2 = hotspot = Point(0, 0); + dots = Size(0, 0); +} + +void ImageBuffer::DeepCopy(const ImageBuffer& img) +{ + Create(img.GetSize()); + SetHotSpot(img.GetHotSpot()); + Set2ndSpot(img.Get2ndSpot()); + SetDots(img.GetDots()); + memcpy(pixels, img.pixels, GetLength() * sizeof(RGBA)); +} + +void ImageBuffer::Set(Image& img) +{ + if(img.data) + if(img.data->refcount == 1) { + size = img.GetSize(); + kind = IMAGE_UNKNOWN; + hotspot = img.GetHotSpot(); + spot2 = img.Get2ndSpot(); + dots = img.GetDots(); + pixels = img.data->buffer.pixels; + img.Clear(); + } + else { + DeepCopy(img.data->buffer); + kind = IMAGE_UNKNOWN; + img.Clear(); + } + else + Create(0, 0); +} + + +void ImageBuffer::operator=(Image& img) +{ + Clear(); + Set(img); +} + +void ImageBuffer::operator=(ImageBuffer& img) +{ + Clear(); + Image m = img; + Set(m); +} + +ImageBuffer::ImageBuffer(Image& img) +{ + Set(img); +} + +ImageBuffer::ImageBuffer(ImageBuffer& b) +{ + kind = b.kind; + size = b.size; + dots = b.dots; + pixels = b.pixels; + hotspot = b.hotspot; + spot2 = b.spot2; +} + +void (Image::Data::*Image::Data::sSysInit)(); +void (Image::Data::*Image::Data::sSysRelease)(); +int (Image::Data::*Image::Data::sGetResCount)() const; +void (Image::Data::*Image::Data::sPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c); + +void Image::Data::InitSystemImage( + void (Image::Data::*fSysInit)(), + void (Image::Data::*fSysRelease)(), + int (Image::Data::*fGetResCount)() const, + void (Image::Data::*fPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c) +) +{ + Image::Data::sSysInit = fSysInit; + Image::Data::sSysRelease = fSysRelease; + Image::Data::sGetResCount = fGetResCount; + Image::Data::sPaint = fPaint; +} + +void Image::Data::SysInit() +{ + if(sSysInit) + (this->*sSysInit)(); +} + +void Image::Data::SysRelease() +{ + if(sSysRelease) + (this->*sSysRelease)(); +} + +int Image::Data::GetResCount() const +{ + if(sGetResCount) + return (this->*sGetResCount)(); + return 0; +} + +void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c) +{ + if(sPaint) + (this->*sPaint)(w, x, y, src, c); +} + +void Image::Set(ImageBuffer& b) +{ + if(b.GetWidth() == 0 || b.GetHeight() == 0) + data = NULL; + else + data = new Data(b); +} + +void Image::Clear() +{ + if(data) + data->Release(); + data = NULL; +} + +Image& Image::operator=(ImageBuffer& img) +{ + if(data) + data->Release(); + Set(img); + return *this; +} + +Image& Image::operator=(const Image& img) +{ + Data *d = data; + data = img.data; + if(data) + data->Retain(); + if(d) + d->Release(); + return *this; +} + +const RGBA* Image::operator~() const +{ + return data ? ~data->buffer : NULL; +} + +Image::operator const RGBA*() const +{ + return data ? ~data->buffer : NULL; +} + +const RGBA* Image::operator[](int i) const +{ + ASSERT(data); + return data->buffer[i]; +} + +Size Image::GetSize() const +{ + return data ? data->buffer.GetSize() : Size(0, 0); +} + +int Image::GetLength() const +{ + return data ? data->buffer.GetLength() : 0; +} + +Point Image::GetHotSpot() const +{ + return data ? data->buffer.GetHotSpot() : Point(0, 0); +} + +Point Image::Get2ndSpot() const +{ + return data ? data->buffer.Get2ndSpot() : Point(0, 0); +} + +Size Image::GetDots() const +{ + return data ? data->buffer.GetDots() : Size(0, 0); +} + +int Image::GetKindNoScan() const +{ + return data ? data->buffer.GetKind() : IMAGE_EMPTY; +} + +int Image::Data::GetKind() +{ + int k = buffer.GetKind(); + if(k != IMAGE_UNKNOWN) + return k; + k = buffer.ScanKind(); + buffer.SetKind(k); + return k; +} + +int Image::GetKind() const +{ + return data ? data->GetKind() : IMAGE_EMPTY; +} + +void Image::PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const +{ + if(data) + data->Paint(w, x, y, src, c); +} + +void Image::Serialize(Stream& s) +{ + int version = 0; + s / version; + Size sz = GetSize(); + Point p = GetHotSpot(); + Size dots = GetDots(); + s % sz % p % dots; + int len = sz.cx * sz.cy; + if(s.IsLoading()) + if(len) { + ImageBuffer b(sz); + if(!s.GetAll(~b, len * sizeof(RGBA))) + s.SetError(); + b.SetDots(dots); + b.SetHotSpot(p); + *this = b; + } + else + Clear(); + else + s.Put(~*this, len * sizeof(RGBA)); +} + +INITBLOCK { + RichValue::Register(); +} + +bool Image::operator==(const Image& img) const +{ + if(GetLength() != img.GetLength()) + return false; + return memcmp(~*this, ~img, GetLength() * sizeof(RGBA)) == 0; +} + +bool Image::operator!=(const Image& img) const +{ + return !operator==(img); +} + +dword Image::GetHashValue() const +{ + return memhash(~*this, GetLength() * sizeof(RGBA)); +} + +Image::Image(const Image& img) +{ + data = img.data; + if(data) + data->Retain(); +} + +Image::Image(Image (*fn)()) +{ + data = NULL; + *this = (*fn)(); +} + +Image::Image(const Value& src) +{ + data = NULL; + if(!IsNull(src)) + *this = RawValue::Extract(src); +} + +Image::Image(ImageBuffer& b) +{ + Set(b); +} + +Image::~Image() +{ + if(data) + data->Release(); +} + +Image::Image(const Init& init) +{ + ASSERT(init.info[0] >= 1); + Size sz; + sz.cx = Peek32le(init.info + 1); + sz.cy = Peek32le(init.info + 5); + ImageBuffer b(sz); + int i = 0; + while(i < init.scan_count) { + UnpackRLE(b[i], (const byte *)init.scans[i], sz.cx); + i++; + } + while(i < sz.cy) + memset(b[i++], 0, sizeof(RGBA) * sz.cx); + b.SetHotSpot(Point(Peek32le(init.info + 9), Peek32le(init.info + 13))); + Set(b); +} + +String Image::ToString() const +{ + return String("Image ").Cat() << GetSize(); +} + +Link Image::Data::ResData[1]; +int Image::Data::ResCount; + +Image::Data::Data(ImageBuffer& b) +: buffer(b) +{ + paintcount = 0; + paintonly = false; + refcount = 1; + INTERLOCKED { + static int64 gserial; + serial = ++gserial; + } + SysInit(); +} + +Image::Data::~Data() +{ + DrawLock __; + SysRelease(); + Unlink(); +} + +void Image::Data::PaintOnlyShrink() +{ + if(paintonly) { + LTIMING("PaintOnlyShrink"); + DrawLock __; + DropPixels___(buffer); + ResCount -= GetResCount(); + Unlink(); + } +} + +static void sMultiply(ImageBuffer& b, int (*op)(RGBA *t, const RGBA *s, int len)) +{ + if(b.GetKind() != IMAGE_OPAQUE && b.GetKind() != IMAGE_EMPTY) + (*op)(~b, ~b, b.GetLength()); +} + +void Premultiply(ImageBuffer& b) +{ + sMultiply(b, Premultiply); +} + +void Unmultiply(ImageBuffer& b) +{ + sMultiply(b, Unmultiply); +} + +static Image sMultiply(const Image& img, int (*op)(RGBA *t, const RGBA *s, int len)) +{ + int k = img.GetKind(); + if(k == IMAGE_OPAQUE || k == IMAGE_EMPTY) + return img; + ImageBuffer ib(img.GetSize()); + ib.SetHotSpot(img.GetHotSpot()); + ib.Set2ndSpot(img.Get2ndSpot()); + ib.SetKind(Premultiply(~ib, ~img, ib.GetLength())); + return ib; +} + +Image Premultiply(const Image& img) +{ + return sMultiply(img, Premultiply); +} + +Image Unmultiply(const Image& img) +{ + return sMultiply(img, Unmultiply); +} + +void SetPaintOnly___(Image& m) +{ + if(m.data && m.data->refcount == 1) + m.data->paintonly = true; +} + +void Iml::Init(int n) +{ + for(int i = 0; i < n; i++) + map.Add(name[i]); +} + +void Iml::Reset() +{ + int n = map.GetCount(); + map.Clear(); + Init(n); +} + +void Iml::Set(int i, const Image& img) +{ + map[i].image = img; + map[i].loaded = true; +} + +static StaticCriticalSection sImgImlLock; + +Image Iml::Get(int i) +{ + IImage& m = map[i]; + if(!m.loaded) { + INTERLOCKED_(sImgImlLock) { + if(data.GetCount()) { + int ii = 0; + for(;;) { + const Data& d = data[ii]; + if(i < d.count) { + static const char *cached_data; + static Vector cached; + if(cached_data != d.data) { + cached_data = d.data; + cached = UnpackImlData(String(d.data, d.len)); + if(premultiply) + for(int i = 0; i < cached.GetCount(); i++) + cached[i] = Premultiply(cached[i]); + } + m.image = cached[i]; + break; + } + i -= d.count; + ii++; + } + } + else + m.image = Premultiply(Image(img_init[i])); + } + m.loaded = true; + } + return m.image; +} + +#ifdef _DEBUG +int Iml::GetBinSize() const +{ + int size = 0; + for(int i = 0; i < map.GetCount(); i++) { + const Image::Init& init = img_init[i]; + size += (int)strlen(name[i]) + 1 + 24; + for(int q = 0; q < init.scan_count; q++) + size += (int)strlen(init.scans[q]); + } + return size; +} +#endif + +Iml::Iml(const Image::Init *img_init, const char **name, int n) +: img_init(img_init), + name(name) +{ +#ifdef flagCHECKINIT + RLOG("Constructing iml " << *name); +#endif + premultiply = true; + Init(n); +} + +void Iml::AddData(const byte *_data, int len, int count) +{ + Data& d = data.Add(); + d.data = (const char *)_data; + d.len = len; + d.count = count; + data.Shrink(); +} + +static StaticCriticalSection sImgMapLock; + +static VectorMap& sImgMap() +{ + static VectorMap x; + return x; +} + +void Register(const char *imageclass, Iml& list) +{ +#ifdef flagCHECKINIT + RLOG("Registering iml " << imageclass); +#endif + INTERLOCKED_(sImgMapLock) + sImgMap().GetAdd(imageclass) = &list; +} + +int GetImlCount() +{ + int q; + INTERLOCKED_(sImgMapLock) + q = sImgMap().GetCount(); + return q; +} + +Iml& GetIml(int i) +{ + return *sImgMap()[i]; +} + +void Iml::Enter() +{ + sImgMapLock.Enter(); +} + +void Iml::Leave() +{ + sImgMapLock.Leave(); +} + +String GetImlName(int i) +{ + String x; + INTERLOCKED_(sImgMapLock) + x = sImgMap().GetKey(i); + return x; +} + +int FindIml(const char *name) +{ + int q; + INTERLOCKED_(sImgMapLock) + q = sImgMap().Find(name); + return q; +} + +Image GetImlImage(const char *name) +{ + Image m; + const char *w = strchr(name, ':'); + if(w) { + int q = FindIml(String(name, w)); + if(q >= 0) { + INTERLOCKED_(sImgMapLock) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + m = iml.Get(q); + } + } + } + return m; +} + +void SetImlImage(const char *name, const Image& m) +{ + const char *w = strchr(name, ':'); + if(w) { + int q = FindIml(String(name, w)); + if(q >= 0) { + INTERLOCKED_(sImgMapLock) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + iml.Set(q, m); + } + } + } +} + +String StoreImageAsString(const Image& img) +{ + if(img.GetKind() == IMAGE_EMPTY) + return Null; + int type = img.GetKind() == IMAGE_OPAQUE ? 3 : 4; + StringStream ss; + ss.Put(type); + Size sz = img.GetSize(); + ss.Put16le(sz.cx); + ss.Put16le(sz.cy); + Point p = img.GetHotSpot(); + ss.Put16le(p.x); + ss.Put16le(p.y); + Size dots = img.GetDots(); + ss.Put16le(dots.cx); + ss.Put16le(dots.cy); + const RGBA *s = img; + const RGBA *e = s + img.GetLength(); + Buffer b(type * img.GetLength()); + byte *t = b; + if(type == 3) + while(s < e) { + *t++ = s->r; + *t++ = s->g; + *t++ = s->b; + s++; + } + else + while(s < e) { + *t++ = s->r; + *t++ = s->g; + *t++ = s->b; + *t++ = s->a; + s++; + } + MemReadStream m(b, type * img.GetLength()); + ZCompress(ss, m); + return ss; +} + +Image LoadImageFromString(const String& src) +{ + if(src.GetLength() < 13) + return Null; + StringStream ss(src); + int type = ss.Get(); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + if(sz.cx < 0 || sz.cy < 0) + return Null; + Point p; + p.x = ss.Get16le(); + p.y = ss.Get16le(); + if(p.x < 0 || p.y < 0) + return Null; + Size dots; + dots.cx = ss.Get16le(); + dots.cy = ss.Get16le(); + if(dots.cx < 0 || dots.cy < 0) + return Null; + StringStream out; + ZDecompress(out, ss); + String data = out; + if(data.GetLength() != type * sz.cx * sz.cy) + return Image(); + ImageBuffer ib(sz); + ib.SetHotSpot(p); + ib.SetDots(dots); + RGBA *t = ib; + const RGBA *e = t + ib.GetLength(); + const byte *s = data; + if(type == 3) + while(t < e) { + t->r = *s++; + t->g = *s++; + t->b = *s++; + t->a = 255; + t++; + } + else + if(type == 4) + while(t < e) { + t->r = *s++; + t->g = *s++; + t->b = *s++; + t->a = *s++; + t++; + } + else + return Image(); + return ib; +} + +Size GetImageStringSize(const String& src) +{ + if(src.GetLength() < 13) + return Size(0, 0); + StringStream ss(src); + ss.Get(); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + return sz; +} + +Size GetImageStringDots(const String& src) +{ + if(src.GetLength() < 13) + return Size(0, 0); + StringStream ss(src); + ss.SeekCur(9); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + return sz; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/Image.h b/uppsrc/Draw/Image.h index f1b3d023a..afe6f0d13 100644 --- a/uppsrc/Draw/Image.h +++ b/uppsrc/Draw/Image.h @@ -1,334 +1,354 @@ -#define NEWIMAGE - -enum ImageKind { - IMAGE_UNKNOWN, - IMAGE_EMPTY, - IMAGE_ALPHA, - IMAGE_MASK, - IMAGE_OPAQUE, -}; - -inline bool operator==(const RGBA& a, const RGBA& b) -{ - return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; -} - -inline bool operator!=(const RGBA& a, const RGBA& b) -{ - return !(a == b); -} - -inline RGBA RGBAZero() { RGBA c; c.r = c.g = c.b = c.a = 0; return c; } - -void Fill(RGBA *t, const RGBA& src, int n); -void FillColor(RGBA *t, const RGBA& src, int n); - -void Copy(RGBA *t, const RGBA *s, int n); - -int Premultiply(RGBA *t, const RGBA *s, int len); -int Unmultiply(RGBA *t, const RGBA *s, int len); - -void AlphaBlend(RGBA *t, const RGBA *s, int len); -void AlphaBlend(RGBA *t, const RGBA *s, int len, Color color); - -void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len, Color color); -void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len); - -void AlphaBlendStraight(RGBA *b, const RGBA *f, int len); -void AlphaBlendStraight(RGBA *b, const RGBA *f, int len, Color color); -void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len); -void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len, int alpha); - -int GetChMaskPos32(dword mask); -void AlphaBlendOverBgST(RGBA *b, RGBA bg, int len); - -const byte *UnpackRLE(RGBA *t, const byte *src, int len); -String PackRLE(const RGBA *s, int len); - -inline int Grayscale(int r, int g, int b) { return (77 * r + 151 * g + 28 * b) >> 8; } -inline int Grayscale(const RGBA& c) { return Grayscale(c.r, c.g, c.b); } -inline byte Saturate255(int x) { return byte(~(x >> 24) & (x | (-(x >> 8) >> 24)) & 0xff); } - -class Image; - -class ImageBuffer : NoCopy { - mutable int kind; - Size size; - Buffer pixels; - Point hotspot; - Point spot2; - Size dots; - - void Set(Image& img); - void DeepCopy(const ImageBuffer& img); - - RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)~pixels + i * size.cx; } - friend void DropPixels___(ImageBuffer& b) { b.pixels.Clear(); } - - friend class Image; - -public: - void SetKind(int k) { kind = k; } - int GetKind() const { return kind; } - int ScanKind() const; - int GetScanKind() const { return kind == IMAGE_UNKNOWN ? ScanKind() : kind; } - - void SetHotSpot(Point p) { hotspot = p; } - Point GetHotSpot() const { return hotspot; } - - void Set2ndSpot(Point p) { spot2 = p; } - Point Get2ndSpot() const { return spot2; } - - void SetDots(Size sz) { dots = sz; } - Size GetDots() const { return dots; } - - Size GetSize() const { return size; } - int GetWidth() const { return size.cx; } - int GetHeight() const { return size.cy; } - int GetLength() const { return size.cx * size.cy; } - - RGBA *operator[](int i) { return Line(i); } - const RGBA *operator[](int i) const { return Line(i); } - RGBA *operator~() { return pixels; } - operator RGBA*() { return pixels; } - const RGBA *operator~() const { return pixels; } - operator const RGBA*() const { return pixels; } - - void Create(int cx, int cy); - void Create(Size sz) { Create(sz.cx, sz.cy); } - bool IsEmpty() const { return (size.cx | size.cy) == 0; } - void Clear() { Create(0, 0); } - - void operator=(Image& img); - void operator=(ImageBuffer& img); - - ImageBuffer() { Create(0, 0); } - ImageBuffer(int cx, int cy) { Create(cx, cy); } - ImageBuffer(Size sz) { Create(sz.cx, sz.cy); } - ImageBuffer(Image& img); - ImageBuffer(ImageBuffer& b); -// BW, defined in CtrlCore: - ImageBuffer(ImageDraw& iw); -}; - -void Premultiply(ImageBuffer& b); -void Unmultiply(ImageBuffer& b); - -void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels); - -class Image : public AssignValueTypeNo< Image, 150, Moveable > { -private: - struct Data : Link { - Atomic refcount; - int64 serial; - int paintcount; - - static Link ResData[1]; - static int ResCount; - - void Retain() { AtomicInc(refcount); } - void Release() { if(AtomicDec(refcount) == 0) delete this; } - - struct SystemData; - - void *system_buffer[6]; - SystemData& Sys() const; - int GetResCount() const; - -#ifdef PLATFORM_WIN32 - void CreateHBMP(HDC dc, const RGBA *data); -#endif - - ImageBuffer buffer; - bool paintonly; - - void SysInit(); - void SysRelease(); - int GetKind(); - void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c); - void PaintOnlyShrink(); - - Data(ImageBuffer& b); - ~Data(); - }; - - Data *data; - - static Link ResData[1]; - static int ResCount; - - void Set(ImageBuffer& b); - - friend class ImageBuffer; - friend struct Data; - - friend class SystemDraw; - - void PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const; - - friend void SetPaintOnly___(Image& m); - friend void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp); - -#ifdef PLATFORM_WIN32 -#ifndef PLATFORM_WINCE - void SetCursorCheat(LPCSTR id); - LPCSTR GetCursorCheat() const; - friend Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor); - friend HICON IconWin32(const Image& img, bool cursor); -#endif -#endif - -#ifdef PLATFORM_X11 - void SetCursorCheat(int id); - int GetCursorCheat() const; - friend void *X11Cursor(const Image&); - friend Image sX11Cursor__(int c); -#endif - -public: - const RGBA* operator~() const; - operator const RGBA*() const; - const RGBA* operator[](int i) const; - - Size GetSize() const; - int GetWidth() const { return GetSize().cx; } - int GetHeight() const { return GetSize().cy; } - int GetLength() const; - Point GetHotSpot() const; - Point Get2ndSpot() const; - Size GetDots() const; - int GetKindNoScan() const; - int GetKind() const; - - int64 GetSerialId() const { return data ? data->serial : 0; } - bool IsSame(const Image& img) const { return GetSerialId() == img.GetSerialId(); } - - bool operator==(const Image& img) const; - bool operator!=(const Image& img) const; - dword GetHashValue() const; - String ToString() const; - - void Serialize(Stream& s); - void Clear(); - - Image& operator=(const Image& img); - Image& operator=(ImageBuffer& img); - - bool IsNullInstance() const { Size sz = GetSize(); return (sz.cx|sz.cy) == 0; } - - bool IsEmpty() const { return IsNullInstance(); } - operator Value() const { return RichValue(*this); } - - Image() { data = NULL; } - Image(const Nuller&) { data = NULL; } - Image(const Value& src); - Image(const Image& img); - Image(Image (*fn)()); - Image(ImageBuffer& b); - ~Image(); - - - static Image Arrow(); - static Image Wait(); - static Image IBeam(); - static Image No(); - static Image SizeAll(); - static Image SizeHorz(); - static Image SizeVert(); - static Image SizeTopLeft(); - static Image SizeTop(); - static Image SizeTopRight(); - static Image SizeLeft(); - static Image SizeRight(); - static Image SizeBottomLeft(); - static Image SizeBottom(); - static Image SizeBottomRight(); - static Image Cross(); - static Image Hand(); - - // IML support ("private"), deprecated - legacy .iml - struct Init { - const char *const *scans; - int16 scan_count; - char info[24]; - }; - explicit Image(const Init& init); -}; - -Image Premultiply(const Image& img); -Image Unmultiply(const Image& img); - -Vector UnpackImlData(const void *ptr, int len); -Vector UnpackImlData(const String& d); - -class Iml { - struct IImage : Moveable { - bool loaded; - Image image; - - IImage() { loaded = false; } - }; - struct Data : Moveable { - const char *data; - int len, count; - }; - Vector data; - VectorMap map; - const Image::Init *img_init; - const char **name; - bool premultiply; - - void Init(int n); - -public: - void Enter(); - void Leave(); - void Reset(); - int GetCount() const { return map.GetCount(); } - String GetId(int i) { return map.GetKey(i); } - Image Get(int i); - int Find(const String& s) const { return map.Find(s); } - void Set(int i, const Image& img); - void Premultiplied() { premultiply = false; } - -#ifdef _DEBUG - int GetBinSize() const; -#endif - - Iml(const Image::Init *img_init, const char **name, int n);//Deprecated - legacy .iml - void AddData(const byte *data, int len, int count); -}; - -void Register(const char *imageclass, Iml& iml); - -int GetImlCount(); -String GetImlName(int i); -Iml& GetIml(int i); -int FindIml(const char *name); -Image GetImlImage(const char *name); -void SetImlImage(const char *name, const Image& m); - -String StoreImageAsString(const Image& img); -Image LoadImageFromString(const String& s); -Size GetImageStringSize(const String& src); -Size GetImageStringDots(const String& src); - -#include "Raster.h" -#include "ImageOp.h" - -#ifdef PLATFORM_WIN32 -#ifndef PLATFORM_WINCE - -Image Win32Icon(LPCSTR id, int iconsize = 0); -Image Win32Icon(int id, int iconsize = 0); -Image Win32Cursor(LPCSTR id); -Image Win32Cursor(int id); -HICON IconWin32(const Image& img, bool cursor = false); -Image Win32DllIcon(const char *dll, int ii, bool large); - -#endif -#endif - -#ifdef PLATFORM_X11 -void *X11Cursor(const Image& img); -#endif +#define NEWIMAGE + +enum ImageKind { + IMAGE_UNKNOWN, + IMAGE_EMPTY, + IMAGE_ALPHA, + IMAGE_MASK, + IMAGE_OPAQUE, +}; + +inline bool operator==(const RGBA& a, const RGBA& b) +{ + return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; +} + +inline bool operator!=(const RGBA& a, const RGBA& b) +{ + return !(a == b); +} + +inline RGBA RGBAZero() { RGBA c; c.r = c.g = c.b = c.a = 0; return c; } + +void Fill(RGBA *t, const RGBA& src, int n); +void FillColor(RGBA *t, const RGBA& src, int n); + +void Copy(RGBA *t, const RGBA *s, int n); + +int Premultiply(RGBA *t, const RGBA *s, int len); +int Unmultiply(RGBA *t, const RGBA *s, int len); + +void AlphaBlend(RGBA *t, const RGBA *s, int len); +void AlphaBlend(RGBA *t, const RGBA *s, int len, Color color); + +void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len, Color color); +void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len); + +void AlphaBlendStraight(RGBA *b, const RGBA *f, int len); +void AlphaBlendStraight(RGBA *b, const RGBA *f, int len, Color color); +void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len); +void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len, int alpha); + +int GetChMaskPos32(dword mask); +void AlphaBlendOverBgST(RGBA *b, RGBA bg, int len); + +const byte *UnpackRLE(RGBA *t, const byte *src, int len); +String PackRLE(const RGBA *s, int len); + +inline int Grayscale(int r, int g, int b) { return (77 * r + 151 * g + 28 * b) >> 8; } +inline int Grayscale(const RGBA& c) { return Grayscale(c.r, c.g, c.b); } +inline byte Saturate255(int x) { return byte(~(x >> 24) & (x | (-(x >> 8) >> 24)) & 0xff); } + +class Image; + +class ImageBuffer : NoCopy { + mutable int kind; + Size size; + Buffer pixels; + Point hotspot; + Point spot2; + Size dots; + + void Set(Image& img); + void DeepCopy(const ImageBuffer& img); + + RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)~pixels + i * size.cx; } + friend void DropPixels___(ImageBuffer& b) { b.pixels.Clear(); } + + friend class Image; + +public: + void SetKind(int k) { kind = k; } + int GetKind() const { return kind; } + int ScanKind() const; + int GetScanKind() const { return kind == IMAGE_UNKNOWN ? ScanKind() : kind; } + + void SetHotSpot(Point p) { hotspot = p; } + Point GetHotSpot() const { return hotspot; } + + void Set2ndSpot(Point p) { spot2 = p; } + Point Get2ndSpot() const { return spot2; } + + void SetDots(Size sz) { dots = sz; } + Size GetDots() const { return dots; } + + Size GetSize() const { return size; } + int GetWidth() const { return size.cx; } + int GetHeight() const { return size.cy; } + int GetLength() const { return size.cx * size.cy; } + + RGBA *operator[](int i) { return Line(i); } + const RGBA *operator[](int i) const { return Line(i); } + RGBA *operator~() { return pixels; } + operator RGBA*() { return pixels; } + const RGBA *operator~() const { return pixels; } + operator const RGBA*() const { return pixels; } + + void Create(int cx, int cy); + void Create(Size sz) { Create(sz.cx, sz.cy); } + bool IsEmpty() const { return (size.cx | size.cy) == 0; } + void Clear() { Create(0, 0); } + + void operator=(Image& img); + void operator=(ImageBuffer& img); + + ImageBuffer() { Create(0, 0); } + ImageBuffer(int cx, int cy) { Create(cx, cy); } + ImageBuffer(Size sz) { Create(sz.cx, sz.cy); } + ImageBuffer(Image& img); + ImageBuffer(ImageBuffer& b); +// BW, defined in CtrlCore: + ImageBuffer(ImageDraw& iw); +}; + +void Premultiply(ImageBuffer& b); +void Unmultiply(ImageBuffer& b); + +void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels); + +class Image : public AssignValueTypeNo< Image, 150, Moveable > { +private: + struct Data : Link { + Atomic refcount; + int64 serial; + int paintcount; + + static Link ResData[1]; + static int ResCount; + + void Retain() { AtomicInc(refcount); } + void Release() { if(AtomicDec(refcount) == 0) delete this; } + + struct SystemData; + + void *system_buffer[6]; + SystemData& Sys() const; + +#ifdef PLATFORM_WIN32 + void CreateHBMP(HDC dc, const RGBA *data); +#endif + + ImageBuffer buffer; + bool paintonly; + + void SysInitImp(); + void SysReleaseImp(); + int GetResCountImp() const; + void PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c); + + void SysInit(); + void SysRelease(); + int GetResCount() const; + void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c); + + int GetKind(); + void PaintOnlyShrink(); + + Data(ImageBuffer& b); + ~Data(); + + static void (Image::Data::*sSysInit)(); + static void (Image::Data::*sSysRelease)(); + static int (Image::Data::*sGetResCount)() const; + static void (Image::Data::*sPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c); + + friend void InstallSystemImage(); + static void InitSystemImage( + void (Image::Data::*fSysInit)(), + void (Image::Data::*fSysRelease)(), + int (Image::Data::*fGetResCount)() const, + void (Image::Data::*fPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c) + ); + }; + + Data *data; + + static Link ResData[1]; + static int ResCount; + + void Set(ImageBuffer& b); + + friend class ImageBuffer; + friend struct Data; + + friend class SystemDraw; + + void PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const; + + friend void SetPaintOnly___(Image& m); + friend void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp); + friend void InstallSystemImage(); + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + void SetCursorCheat(LPCSTR id); + LPCSTR GetCursorCheat() const; + friend Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor); + friend HICON IconWin32(const Image& img, bool cursor); +#endif +#endif + +#ifdef PLATFORM_X11 + void SetCursorCheat(int id); + int GetCursorCheat() const; + friend void *X11Cursor(const Image&); + friend Image sX11Cursor__(int c); +#endif + +public: + const RGBA* operator~() const; + operator const RGBA*() const; + const RGBA* operator[](int i) const; + + Size GetSize() const; + int GetWidth() const { return GetSize().cx; } + int GetHeight() const { return GetSize().cy; } + int GetLength() const; + Point GetHotSpot() const; + Point Get2ndSpot() const; + Size GetDots() const; + int GetKindNoScan() const; + int GetKind() const; + + int64 GetSerialId() const { return data ? data->serial : 0; } + bool IsSame(const Image& img) const { return GetSerialId() == img.GetSerialId(); } + + bool operator==(const Image& img) const; + bool operator!=(const Image& img) const; + dword GetHashValue() const; + String ToString() const; + + void Serialize(Stream& s); + void Clear(); + + Image& operator=(const Image& img); + Image& operator=(ImageBuffer& img); + + bool IsNullInstance() const { Size sz = GetSize(); return (sz.cx|sz.cy) == 0; } + + bool IsEmpty() const { return IsNullInstance(); } + operator Value() const { return RichValue(*this); } + + Image() { data = NULL; } + Image(const Nuller&) { data = NULL; } + Image(const Value& src); + Image(const Image& img); + Image(Image (*fn)()); + Image(ImageBuffer& b); + ~Image(); + + + static Image Arrow(); + static Image Wait(); + static Image IBeam(); + static Image No(); + static Image SizeAll(); + static Image SizeHorz(); + static Image SizeVert(); + static Image SizeTopLeft(); + static Image SizeTop(); + static Image SizeTopRight(); + static Image SizeLeft(); + static Image SizeRight(); + static Image SizeBottomLeft(); + static Image SizeBottom(); + static Image SizeBottomRight(); + static Image Cross(); + static Image Hand(); + + // IML support ("private"), deprecated - legacy .iml + struct Init { + const char *const *scans; + int16 scan_count; + char info[24]; + }; + explicit Image(const Init& init); +}; + +Image Premultiply(const Image& img); +Image Unmultiply(const Image& img); + +Vector UnpackImlData(const void *ptr, int len); +Vector UnpackImlData(const String& d); + +class Iml { + struct IImage : Moveable { + bool loaded; + Image image; + + IImage() { loaded = false; } + }; + struct Data : Moveable { + const char *data; + int len, count; + }; + Vector data; + VectorMap map; + const Image::Init *img_init; + const char **name; + bool premultiply; + + void Init(int n); + +public: + void Enter(); + void Leave(); + void Reset(); + int GetCount() const { return map.GetCount(); } + String GetId(int i) { return map.GetKey(i); } + Image Get(int i); + int Find(const String& s) const { return map.Find(s); } + void Set(int i, const Image& img); + void Premultiplied() { premultiply = false; } + +#ifdef _DEBUG + int GetBinSize() const; +#endif + + Iml(const Image::Init *img_init, const char **name, int n);//Deprecated - legacy .iml + void AddData(const byte *data, int len, int count); +}; + +void Register(const char *imageclass, Iml& iml); + +int GetImlCount(); +String GetImlName(int i); +Iml& GetIml(int i); +int FindIml(const char *name); +Image GetImlImage(const char *name); +void SetImlImage(const char *name, const Image& m); + +String StoreImageAsString(const Image& img); +Image LoadImageFromString(const String& s); +Size GetImageStringSize(const String& src); +Size GetImageStringDots(const String& src); + +#include "Raster.h" +#include "ImageOp.h" + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + +Image Win32Icon(LPCSTR id, int iconsize = 0); +Image Win32Icon(int id, int iconsize = 0); +Image Win32Cursor(LPCSTR id); +Image Win32Cursor(int id); +HICON IconWin32(const Image& img, bool cursor = false); +Image Win32DllIcon(const char *dll, int ii, bool large); + +#endif +#endif + +#ifdef PLATFORM_X11 +void *X11Cursor(const Image& img); +#endif diff --git a/uppsrc/Draw/ImageAnyDraw.cpp b/uppsrc/Draw/ImageAnyDraw.cpp new file mode 100644 index 000000000..60a118119 --- /dev/null +++ b/uppsrc/Draw/ImageAnyDraw.cpp @@ -0,0 +1,164 @@ +#include "Draw.h" + +NAMESPACE_UPP + +dword ImageAnyDraw::GetInfo() const +{ + return draw->GetInfo(); +} + +Size ImageAnyDraw::GetPageSize() const +{ + return draw->GetPageSize(); +} + +void ImageAnyDraw::BeginOp() +{ + return draw->BeginOp(); +} + +void ImageAnyDraw::EndOp() +{ + return draw->EndOp(); +} + +void ImageAnyDraw::OffsetOp(Point p) +{ + return draw->OffsetOp(p); +} + +bool ImageAnyDraw::ClipOp(const Rect& r) +{ + return draw->ClipOp(r); +} + +bool ImageAnyDraw::ClipoffOp(const Rect& r) +{ + return draw->ClipoffOp(r); +} + +bool ImageAnyDraw::ExcludeClipOp(const Rect& r) +{ + return draw->ExcludeClipOp(r); +} + +bool ImageAnyDraw::IntersectClipOp(const Rect& r) +{ + return draw->IntersectClipOp(r); +} + +bool ImageAnyDraw::IsPaintingOp(const Rect& r) const +{ + return draw->IsPaintingOp(r); +} + +Rect ImageAnyDraw::GetPaintRect() const +{ + return draw->GetPaintRect(); +} + +void ImageAnyDraw::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + draw->DrawRectOp(x, y, cx, cy, color); +} + +void ImageAnyDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + draw->DrawImageOp(x, y, cx, cy, img, src, color); +} + +void ImageAnyDraw::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) +{ + draw->DrawDataOp(x, y, cx, cy, data, id); +} + +void ImageAnyDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + draw->DrawLineOp(x1, y1, x2, y2, width, color); +} + +void ImageAnyDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, int width, + Color color, Color doxor) +{ + draw->DrawPolyPolylineOp(vertices, vertex_count, counts, count_count, width, color, doxor); +} + +void ImageAnyDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + draw->DrawPolyPolyPolygonOp(vertices, vertex_count, subpolygon_counts, scc, + disjunct_polygon_counts, dpcc, color, width, outline, + pattern, doxor); +} + +void ImageAnyDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ + draw->DrawArcOp(rc, start, end, width, color); +} + +void ImageAnyDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ + draw->DrawEllipseOp(r, color, pen, pencolor); +} + +void ImageAnyDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx) +{ + draw->DrawTextOp(x, y, angle, text, font, ink, n, dx); +} + +void ImageAnyDraw::DrawDrawingOp(const Rect& target, const Drawing& w) +{ + draw->DrawDrawingOp(target, w); +} + +void ImageAnyDraw::DrawPaintingOp(const Rect& target, const Painting& w) +{ + draw->DrawPaintingOp(target, w); +} + +Draw *(*sCreateImageDraw)(Size sz); +Image (*sExtractImageDraw)(Draw *w); + +void ImageAnyDrawPainter(Draw *(*f)(Size sz), Image (*e)(Draw *w)) +{ + sCreateImageDraw = f; + sExtractImageDraw = e; +} + +void ImageAnyDrawSystem(Draw *(*f)(Size sz), Image (*e)(Draw *w)) +{ + if(!sCreateImageDraw) { + sCreateImageDraw = f; + sExtractImageDraw = e; + } +} + +void ImageAnyDraw::Init(Size sz) +{ + ASSERT(sCreateImageDraw); + draw = (*sCreateImageDraw)(sz); + ASSERT(draw); +} + +ImageAnyDraw::operator Image() const +{ + return (*sExtractImageDraw)(draw); +} + +ImageAnyDraw::ImageAnyDraw(Size sz) +{ + Init(sz); +} + +ImageAnyDraw::ImageAnyDraw(int cx, int cy) +{ + Init(Size(cx, cy)); +} + +ImageAnyDraw::~ImageAnyDraw() +{ + delete draw; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Painter/DrawOp.cpp b/uppsrc/Painter/DrawOp.cpp index 3d363e4bc..269ca20cb 100644 --- a/uppsrc/Painter/DrawOp.cpp +++ b/uppsrc/Painter/DrawOp.cpp @@ -135,4 +135,21 @@ void Painter::DrawPaintingOp(const Rect& target, const Painting& p) End(); } +void ImageAnyDrawPainter(Draw *(*f)(Size sz), Image (*e)(Draw *w)); + +static Draw *sCP(Size sz) +{ + return new ImagePainter(sz); +} + +static Image sEP(Draw *w) +{ + ImagePainter *ip = dynamic_cast(w); + return ip ? (Image)(*ip) : Image(); +} + +INITBLOCK { + ImageAnyDrawPainter(sCP, sEP); +} + END_UPP_NAMESPACE diff --git a/uppsrc/Painter/FontX11.cpp b/uppsrc/Painter/FontX11.cpp index 6ba77b2de..5ac89feda 100644 --- a/uppsrc/Painter/FontX11.cpp +++ b/uppsrc/Painter/FontX11.cpp @@ -17,15 +17,12 @@ #include "Painter.h" -#ifdef PLATFORM_X11 +#ifdef PLATFORM_POSIX #include #include -#endif NAMESPACE_UPP -#ifdef PLATFORM_X11 - FT_Face FTFace(Font fnt, String *rpath); static inline double ft_dbl(int p) @@ -38,7 +35,6 @@ bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double y FT_Vector v_last; FT_Vector v_control; FT_Vector v_start; - double x1, y1, x2, y2, x3, y3; FT_Vector* point; FT_Vector* limit; char* tags; @@ -154,6 +150,7 @@ void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt) sw.EvenOdd(true); } -#endif END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/Painter/Painter.upp b/uppsrc/Painter/Painter.upp index b384ee688..9215d78a7 100644 --- a/uppsrc/Painter/Painter.upp +++ b/uppsrc/Painter/Painter.upp @@ -1,8 +1,7 @@ description "2D software rendering with PDF/SVG strength\377"; uses - Core, - CtrlLib; + Core; file Painter.h, diff --git a/uppsrc/RichText/Object.cpp b/uppsrc/RichText/Object.cpp index 032a7a000..1b235e2f0 100644 --- a/uppsrc/RichText/Object.cpp +++ b/uppsrc/RichText/Object.cpp @@ -112,7 +112,7 @@ Image RichObjectType::ToImage(const Value& data, Size sz) const Image RichObjectType::ToImage(const Value& data, Size sz, void *context) const { - ImageDraw iw(sz); + ImageAnyDraw iw(sz); iw.DrawRect(sz, SColorPaper()); Paint(data, iw, sz, context); return iw; @@ -176,7 +176,7 @@ Image RichObject::ToImage(Size sz, void *context) const if(type) return type->ToImage(data, sz, context); else { - ImageDraw w(sz); + ImageAnyDraw w(sz); Paint(w, sz, context); return w; } diff --git a/uppsrc/RichText/RichImage.icpp b/uppsrc/RichText/RichImage.icpp index 18c8616bc..9b4738bcc 100644 --- a/uppsrc/RichText/RichImage.icpp +++ b/uppsrc/RichText/RichImage.icpp @@ -24,24 +24,46 @@ String RichImage::GetTypeName(const Value& v) const return "image"; } +static String (*sGetImageClip)(const Image& img, const String& fmt); +static bool (*sAcceptImage)(PasteClip& clip); +static Image (*sGetImage)(PasteClip& clip); +static const char *(*sClipFmtsImage)(); + +void InitRichImage(String (*fGetImageClip)(const Image& img, const String& fmt), + bool (*fAcceptImage)(PasteClip& clip), + Image (*fGetImage)(PasteClip& clip), + const char *(*fClipFmtsImage)()) +{ + sGetImageClip = fGetImageClip; + sAcceptImage = fAcceptImage; + sGetImage = fGetImage; + sClipFmtsImage = fClipFmtsImage; +} + bool RichImage::Accept(PasteClip& clip) { - return AcceptImage(clip); + return sAcceptImage? sAcceptImage(clip) : false; } Value RichImage::Read(PasteClip& clip) { - return StoreImageAsString(GetImage(clip)); + if(sGetImage) + return StoreImageAsString(sGetImage(clip)); + return Null; } String RichImage::GetClipFmts() const { - return ClipFmtsImage(); + if(sClipFmtsImage) + return sClipFmtsImage(); + return Null; } String RichImage::GetClip(const Value& data, const String& fmt) const { - return GetImageClip(LoadImageFromString(data), fmt); + if(sGetImageClip) + return sGetImageClip(LoadImageFromString(data), fmt); + return Null; } Size RichImage::GetPixelSize(const Value& data) const @@ -141,7 +163,7 @@ void RichPNG::Paint(const Value& data, Draw& w, Size sz) const Image RichPNG::ToImage(const Value& data, Size sz, void *) const { if(IsString(data)) { - ImageDraw iw(sz); + ImageAnyDraw iw(sz); Paint(data, iw, sz); return iw; } diff --git a/uppsrc/RichText/RichText.h b/uppsrc/RichText/RichText.h index 60812d01f..8c0f1ae26 100644 --- a/uppsrc/RichText/RichText.h +++ b/uppsrc/RichText/RichText.h @@ -1,11 +1,13 @@ #ifndef RICHTEXT_H #define RICHTEXT_H -#include +#include #include NAMESPACE_UPP +class PasteClip; + struct Zoom { int m, d; @@ -426,11 +428,7 @@ inline int PointDots(int pts) { return (pts * 25 + 3 * ROUNDOFF + 1) / 3 - inline int TwipDotSize(int twp) { return IsNull(twp) ? 0 : minmax(TwipDots(twp), 0, MAX_DOTS); } inline int PointDotHeight(int p) { return (minmax(Nvl(p, 0), 0, MAX_POINT_HEIGHT) * 25 + 5) / 6; } -void EncodeRTF(Stream& stream, const RichText& richtext, byte charset); -String EncodeRTF(const RichText& richtext, byte charset); -String EncodeRTF(const RichText& richtext); -RichText ParseRTF(const char *rtf); - +void SetRichTextStdScreenZoom(int m, int d); Zoom GetRichTextStdScreenZoom(); const Display& QTFDisplay(); diff --git a/uppsrc/RichText/RichText.upp b/uppsrc/RichText/RichText.upp index 751b0865a..6f0e56662 100644 --- a/uppsrc/RichText/RichText.upp +++ b/uppsrc/RichText/RichText.upp @@ -1,8 +1,8 @@ description "Rich-text data structures and painting, including RTF and HTML export/import\3770,0,128"; uses - CtrlCore, - plugin\png; + plugin\png, + Draw; file RichText.h, @@ -29,9 +29,7 @@ file TextTable.cpp, EncodeQtf.cpp optimize_speed, ParseQtf.cpp optimize_speed, - EncodeRTF.cpp optimize_speed, - ParseRTF.cpp optimize_speed, - EncodeHTML.cpp optimize_speed, + EncodeHTML.cpp, Util.cpp, RichText.iml, Info readonly separator, diff --git a/uppsrc/RichText/Util.cpp b/uppsrc/RichText/Util.cpp index b8d2f079f..cc845151b 100644 --- a/uppsrc/RichText/Util.cpp +++ b/uppsrc/RichText/Util.cpp @@ -21,9 +21,24 @@ void RichText::ApplyZoom(Zoom z) RefreshAll(); } +Zoom& sRichTextStdScreenZoom() +{ + static Zoom *zz; + ONCELOCK { + static Zoom z(96, 600); + zz = &z; + } + return *zz; +} + +void SetRichTextStdScreenZoom(int m, int d) +{ + sRichTextStdScreenZoom() = Zoom(m, d); +} + Zoom GetRichTextStdScreenZoom() { - return Zoom(Ctrl::HorzLayoutZoom(96), 600); + return sRichTextStdScreenZoom(); } struct QTFDisplayCls : Display { diff --git a/uppsrc/RichText/init b/uppsrc/RichText/init index 3fbdfca2e..18697050b 100644 --- a/uppsrc/RichText/init +++ b/uppsrc/RichText/init @@ -1,8 +1,8 @@ #ifndef _RichText_icpp_init_stub #define _RichText_icpp_init_stub -#include "CtrlCore/init" #include "plugin\png/init" -#define BLITZ_INDEX__ FD9BFF8A7459D77CDDE8AF2999BB1DAC7 +#include "Draw/init" +#define BLITZ_INDEX__ FDE63A693846F2AB9FD888AAECF47B819 #include "RichImage.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/ide/Browser/Item.cpp b/uppsrc/ide/Browser/Item.cpp index bc2b13a56..7761798a3 100644 --- a/uppsrc/ide/Browser/Item.cpp +++ b/uppsrc/ide/Browser/Item.cpp @@ -1,178 +1,178 @@ -#include "Browser.h" - -#define IMAGECLASS BrowserImg -#define IMAGEFILE -#include - -#define LLOG(x) // DLOG(x) - -bool IsCppKeyword(const String& id) -{ - static Index kw; - ONCELOCK { - const char **cppk = CppKeyword(); - for(int i = 0; cppk[i]; i++) - kw.Add(cppk[i]); - } - return kw.Find(id) >= 0; -} - -bool IsCppType(const String& id) -{ - static const char *t[] = { - "int", "long", "short", "void", "float", "double", "char", "signed", "unsigned", "bool", - "const", "mutable", "struct", "class", "union" - }; - static Index kt; - ONCELOCK { - for(int i = 0; i < __countof(t); i++) - kt.Add(t[i]); - } - return kt.Find(id) >= 0; -} - -int InScListIndext(const char *s, const char *list) -{ - int ii = 0; - for(;;) { - const char *q = s; - while(*list == ' ') list++; - for(;;) { - if(*q == '\0' && *list == '\0') return ii; - if(*q != *list) { - if(*q == '\0' && (*list == '<' || *list == ';' || *list == ',' || *list == '>')) - return ii; - if(*list == '\0') return -1; - break; - } - q++; - list++; - } - while(*list && *list != ';' && *list != '<' && *list != '>' && *list != ',') list++; - if(*list == '\0') return -1; - list++; - ii++; - } -} - -static String s_pick_("pick_"); - -static bool sOperatorTab[256]; - -INITBLOCK { - for(const char *s = "!+-*^/%~&|=[]:?."; *s; s++) - sOperatorTab[*s] = true; -} - -inline bool sOperator(byte c) -{ - return sOperatorTab[c]; -} - -Vector ParseItemNatural(const String& name, const CppItem& m, const char *s) -{ - LLOG("ParseItemNatural " << m.natural << ", pname: " << m.pname - << ", tname: " << m.tname << ", m.ctname: " << m.ctname); - Vector part; - bool param = false; - int pari = -1; - int par = 0; - while(*s) { - ItemTextPart& p = part.Add(); - p.pos = (int)(s - ~m.natural); - p.type = ITEM_TEXT; - p.pari = pari; - int n = 1; - if(*s >= '0' && *s <= '9') { - while(s[n] >= '0' && s[n] <= '9') - n++; - p.type = ITEM_NUMBER; - } - else - if(iscid(*s) || *s == ':') { - if(strncmp(s, name, name.GetLength()) == 0 && !iscid(s[name.GetLength()])) { - p.type = ITEM_NAME; - n = name.GetLength(); - param = true; - } - else { - String id; - n = 0; - while(IsAlNum(s[n]) || s[n] == '_' || s[n] == ':') - id.Cat(s[n++]); - if(IsCppType(id)) - p.type = ITEM_CPP_TYPE; - else - if(IsCppKeyword(id)) - p.type = ITEM_CPP; - else - if(InScList(id, m.pname)) - p.type = ITEM_PNAME; - else - if(id == s_pick_) { - p.type = ITEM_UPP; - } - else - if(InScList(id, m.tname) || InScList(id, m.ctname)) - p.type = ITEM_TNAME; - else - if(param) { - int ii = InScListIndext(id, m.ptype); - if(ii >= 0) - p.type = ITEM_PTYPE + ii; - } - else { - int ii = InScListIndext(id, m.type); - if(ii >= 0) - p.type = ITEM_TYPE + ii; - } - LLOG("id: " << id << ", type: " << p.type); - } - } - else - if(sOperator(*s)) { - while(sOperator(s[n])) - n++; - p.type = ITEM_CPP; - } - else { - p.type = ITEM_SIGN; - if(pari >= 0) { - if(*s == '(' || *s == '<') - par++; - if(*s == ')' || *s == '>') { - par--; - if(par < 0) { - p.pari = -1; - pari = -1; - param = false; - } - } - if(*s == ',' && par == 0) { - p.pari = -1; - pari++; - } - } - else - if(*s == '(' && param) { - pari = 0; - par = 0; - } - while(s[n] && !iscid(s[n])) - n++; - } - p.len = n; - s += n; - } - return part; -} - -Vector ParseItemNatural(const CppItemInfo& m, const char *s) -{ - return ParseItemNatural(m.name, m, s); -} - -Vector ParseItemNatural(const CppItemInfo& m) -{ - return ParseItemNatural(m, ~m.natural + m.at); -} +#include "Browser.h" + +#define IMAGECLASS BrowserImg +#define IMAGEFILE +#include + +#define LLOG(x) // DLOG(x) + +bool IsCppKeyword(const String& id) +{ + static Index kw; + ONCELOCK { + const char **cppk = CppKeyword(); + for(int i = 0; cppk[i]; i++) + kw.Add(cppk[i]); + } + return kw.Find(id) >= 0; +} + +bool IsCppType(const String& id) +{ + static const char *t[] = { + "int", "long", "short", "void", "float", "double", "char", "signed", "unsigned", "bool", + "const", "mutable", "struct", "class", "union" + }; + static Index kt; + ONCELOCK { + for(int i = 0; i < __countof(t); i++) + kt.Add(t[i]); + } + return kt.Find(id) >= 0; +} + +int InScListIndext(const char *s, const char *list) +{ + int ii = 0; + for(;;) { + const char *q = s; + while(*list == ' ') list++; + for(;;) { + if(*q == '\0' && *list == '\0') return ii; + if(*q != *list) { + if(*q == '\0' && (*list == '<' || *list == ';' || *list == ',' || *list == '>')) + return ii; + if(*list == '\0') return -1; + break; + } + q++; + list++; + } + while(*list && *list != ';' && *list != '<' && *list != '>' && *list != ',') list++; + if(*list == '\0') return -1; + list++; + ii++; + } +} + +static String s_pick_("pick_"); + +static bool sOperatorTab[256]; + +INITBLOCK { + for(const char *s = "!+-*^/%~&|=[]:?."; *s; s++) + sOperatorTab[(int)*s] = true; +} + +inline bool sOperator(byte c) +{ + return sOperatorTab[c]; +} + +Vector ParseItemNatural(const String& name, const CppItem& m, const char *s) +{ + LLOG("ParseItemNatural " << m.natural << ", pname: " << m.pname + << ", tname: " << m.tname << ", m.ctname: " << m.ctname); + Vector part; + bool param = false; + int pari = -1; + int par = 0; + while(*s) { + ItemTextPart& p = part.Add(); + p.pos = (int)(s - ~m.natural); + p.type = ITEM_TEXT; + p.pari = pari; + int n = 1; + if(*s >= '0' && *s <= '9') { + while(s[n] >= '0' && s[n] <= '9') + n++; + p.type = ITEM_NUMBER; + } + else + if(iscid(*s) || *s == ':') { + if(strncmp(s, name, name.GetLength()) == 0 && !iscid(s[name.GetLength()])) { + p.type = ITEM_NAME; + n = name.GetLength(); + param = true; + } + else { + String id; + n = 0; + while(IsAlNum(s[n]) || s[n] == '_' || s[n] == ':') + id.Cat(s[n++]); + if(IsCppType(id)) + p.type = ITEM_CPP_TYPE; + else + if(IsCppKeyword(id)) + p.type = ITEM_CPP; + else + if(InScList(id, m.pname)) + p.type = ITEM_PNAME; + else + if(id == s_pick_) { + p.type = ITEM_UPP; + } + else + if(InScList(id, m.tname) || InScList(id, m.ctname)) + p.type = ITEM_TNAME; + else + if(param) { + int ii = InScListIndext(id, m.ptype); + if(ii >= 0) + p.type = ITEM_PTYPE + ii; + } + else { + int ii = InScListIndext(id, m.type); + if(ii >= 0) + p.type = ITEM_TYPE + ii; + } + LLOG("id: " << id << ", type: " << p.type); + } + } + else + if(sOperator(*s)) { + while(sOperator(s[n])) + n++; + p.type = ITEM_CPP; + } + else { + p.type = ITEM_SIGN; + if(pari >= 0) { + if(*s == '(' || *s == '<') + par++; + if(*s == ')' || *s == '>') { + par--; + if(par < 0) { + p.pari = -1; + pari = -1; + param = false; + } + } + if(*s == ',' && par == 0) { + p.pari = -1; + pari++; + } + } + else + if(*s == '(' && param) { + pari = 0; + par = 0; + } + while(s[n] && !iscid(s[n])) + n++; + } + p.len = n; + s += n; + } + return part; +} + +Vector ParseItemNatural(const CppItemInfo& m, const char *s) +{ + return ParseItemNatural(m.name, m, s); +} + +Vector ParseItemNatural(const CppItemInfo& m) +{ + return ParseItemNatural(m, ~m.natural + m.at); +}