From bdbbeca30e5737a6a4cee9899c5a0c356fd18ffd Mon Sep 17 00:00:00 2001 From: cxl Date: Fri, 11 Sep 2015 12:46:39 +0000 Subject: [PATCH] PdfDraw, RichText: PdfDraw and RichText->PDF export now support urls #1183 git-svn-id: svn://ultimatepp.org/upp/trunk@8915 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Draw/Draw.cpp | 2 + uppsrc/Draw/Draw.h | 4 ++ uppsrc/Draw/Drawing.cpp | 10 +++++ uppsrc/Draw/src.tpp/Draw$en-us.tpp | 7 +++ uppsrc/PdfDraw/PdfDraw.cpp | 71 +++++++++++++++++++++++------- uppsrc/PdfDraw/PdfDraw.h | 16 ++++++- uppsrc/RichText/ParaPaint.cpp | 6 ++- uppsrc/RichText/TxtPaint.cpp | 2 +- 8 files changed, 99 insertions(+), 19 deletions(-) diff --git a/uppsrc/Draw/Draw.cpp b/uppsrc/Draw/Draw.cpp index 389f5f0fb..1d975c39f 100644 --- a/uppsrc/Draw/Draw.cpp +++ b/uppsrc/Draw/Draw.cpp @@ -113,6 +113,8 @@ void Draw::EndNative() {} int Draw::GetCloffLevel() const { return 0; } +void Draw::Escape(const String& data) {} + // ------------------------------- void Draw::SysDrawImageOp(int x, int y, const Image& img, Color color) diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index 4d39ae649..c4e02d2a5 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -466,6 +466,8 @@ public: virtual void EndNative(); virtual int GetCloffLevel() const; + + virtual void Escape(const String& data); virtual ~Draw(); @@ -701,6 +703,8 @@ public: virtual void DrawDrawingOp(const Rect& target, const Drawing& w); virtual void DrawPaintingOp(const Rect& target, const Painting& w); + virtual void Escape(const String& data); + private: Size size; bool dots; diff --git a/uppsrc/Draw/Drawing.cpp b/uppsrc/Draw/Drawing.cpp index a6f57e55e..6c54c7c25 100644 --- a/uppsrc/Draw/Drawing.cpp +++ b/uppsrc/Draw/Drawing.cpp @@ -22,6 +22,7 @@ enum { DRAWING_DRAWPOLYPOLYPOLYGON = 17, DRAWING_DRAWDATA = 18, DRAWING_DRAWPAINTING = 19, + DRAWING_ESCAPE = 20, }; @@ -183,6 +184,12 @@ void DrawingDraw::DrawDataOp(int x, int y, int cx, int cy, const String& data, c val.Add(data); } +void DrawingDraw::Escape(const String& data) +{ + DrawingOp(DRAWING_ESCAPE); + val.Add(data); +} + void DrawingDraw::DrawDrawingOp(const Rect& target, const Drawing& w) { DrawingOp(DRAWING_DRAWDRAWING) % const_cast(target); @@ -452,6 +459,9 @@ void Draw::DrawDrawingOp(const Rect& target, const Drawing& w) { DrawData(ps(x, y, cx, cy), data, id); } break; + case DRAWING_ESCAPE: + Escape(w.val[vi++]); + break; case DRAWING_DRAWDRAWING: if(w.val.GetCount()) dw = w.val[vi++]; diff --git a/uppsrc/Draw/src.tpp/Draw$en-us.tpp b/uppsrc/Draw/src.tpp/Draw$en-us.tpp index 0c5f491e1..b81bdc548 100644 --- a/uppsrc/Draw/src.tpp/Draw$en-us.tpp +++ b/uppsrc/Draw/src.tpp/Draw$en-us.tpp @@ -347,6 +347,13 @@ mode.&] [s2;%% Returns the number of elements in clip`&offset stack. Mostly used for diagnostic purposes.&] [s3;%% &] +[s4; &] +[s5;:Upp`:`:Draw`:`:Escape`(const Upp`:`:String`&`): [@(0.0.255) virtual +void]_[* Escape]([@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 data])&] +[s2;%% Passes additional information to Draw target instance. For +example, PdfDraw understands `"url:http://link.html`" escapes to +define text hyperlinks. Frontend to EscapeOp.&] +[s3;%% &] [s4;%% &] [s5;:Draw`:`:GetPixelsPerInch`(`)const: [_^Size^ Size]_[* GetPixelsPerInch]()_[@(0.0.255) c onst]&] diff --git a/uppsrc/PdfDraw/PdfDraw.cpp b/uppsrc/PdfDraw/PdfDraw.cpp index 66c070d47..c922a656f 100644 --- a/uppsrc/PdfDraw/PdfDraw.cpp +++ b/uppsrc/PdfDraw/PdfDraw.cpp @@ -7,7 +7,7 @@ NAMESPACE_UPP #define LDUMP(x) // DUMP(x) #define LLOG(x) // DLOG(x) -#define PDF_COMPRESS +// #define PDF_COMPRESS dword PdfDraw::GetInfo() const { @@ -27,6 +27,7 @@ void PdfDraw::Init(int pagecx, int pagecy, int _margin, bool _pdfa) pgsz.cx = pagecx; pgsz.cy = pagecy; pgsz += margin; + current_offset = Point(0, 0); StartPage(); } @@ -135,8 +136,21 @@ void PdfDraw::EndPage() page.Clear(); } +void PdfDraw::PushOffset() +{ + offset_stack.Add(current_offset); +} + +void PdfDraw::PopOffset() +{ + ASSERT(offset_stack.GetCount()); + if(offset_stack.GetCount()) // be defensive + current_offset = offset_stack.Pop(); +} + void PdfDraw::BeginOp() { + PushOffset(); page << "q\n"; } @@ -148,6 +162,7 @@ void PdfDraw::EndOp() rgcolor = RGcolor = Null; linewidth = -1; page << "Q\n"; + PopOffset(); } void PdfDraw::OffsetOp(Point p) @@ -155,6 +170,8 @@ void PdfDraw::OffsetOp(Point p) page << "q "; if(p.x || p.y) page << "1 0 0 1 " << Pt(p.x) << ' ' << Pt(-p.y) << " cm\n"; + PushOffset(); + current_offset += p; } bool PdfDraw::ClipOp(const Rect& r) @@ -162,6 +179,7 @@ bool PdfDraw::ClipOp(const Rect& r) page << "q "; PutRect(r); page << "W* n\n"; + PushOffset(); return true; } @@ -172,6 +190,8 @@ bool PdfDraw::ClipoffOp(const Rect& r) page << "W* n\n"; if(r.left || r.top) page << "1 0 0 1 " << Pt(r.left) << ' ' << Pt(-r.top) << " cm\n"; + PushOffset(); + current_offset += r.TopLeft(); return true; } @@ -334,18 +354,19 @@ void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt, prev = next; } page << "ET\n"; + + if(q == 0 && url.GetCount()) { // For now, only 'zero angle' text can have links + UrlInfo& u = page_url.At(offset.GetCount()).Add(); + u.rect = RectC(x, y, posx, ff.GetCy()).Offseted(current_offset); + u.url = url; + } } -/* -// DrawRect(x + posx, y, 20, 20, Black()); _DBG_ - if(fnt.IsUnderline()) { - int w = max(2, ff.GetAscent() / 25); - int dy = ff.GetAscent() + min(ff.GetDescent() - w, 2 * w); - DrawLine(fround(x + sina * dy), - fround(y + cosa * dy), - fround(x + cosa * posx + sina * dy), - fround(y + cosa * dy - sina * posx), w, ink); - } -*/ +} + +void PdfDraw::Escape(const String& data) +{ + if(data.StartsWith("url:")) + url = data.Mid(4); } Image RenderGlyph(int cx, int x, Font font, int chr, int py, int pcy); @@ -652,7 +673,7 @@ String PdfDraw::Finish() for(int i = 0; i < patterns.GetCount(); i++) { uint64 pat = patterns[i]; StringBuffer ptk; - ptk << + ptk << "/Type /Pattern\n" "/PatternType 1\n" "/PaintType 2\n" @@ -924,10 +945,10 @@ String PdfDraw::Finish() out << ">>\n"; } if(!patternobj.IsEmpty()) { - out << + out << "/ColorSpace << /Cspat " << patcsobj << " 0 R >>\n" "/Pattern << "; - for(int i = 0; i < patterns.GetCount(); i++) + for(int i = 0; i < patterns.GetCount(); i++) out << "/Pat" << (i + 1) << ' ' << patternobj[i] << " 0 R "; out << ">>\n"; } @@ -936,6 +957,22 @@ String PdfDraw::Finish() } out << ">>\n"; EndObj(); + + Vector url_ann; + for(int pi = 0; pi < min(page_url.GetCount(), pagecount); pi++) { + const Array& url = page_url[pi]; + for(int i = 0; i < url.GetCount(); i++) { + const UrlInfo& u = url[i]; + url_ann.At(pi) << ' ' << BeginObj() << " 0 R"; + out << "<>\n>>\n"; + EndObj(); + } + } int pages = BeginObj(); out << "<< /Type /Pages\n" @@ -952,7 +989,9 @@ String PdfDraw::Finish() << "/Parent " << pages << " 0 R\n" << "/MediaBox [0 0 " << Pt(pgsz.cx) << ' ' << Pt(pgsz.cy) << "]\n" << "/Contents " << i + 1 << " 0 R\n" - << "/Resources " << resources << " 0 R \n"; + << "/Resources " << resources << " 0 R\n"; + if(i < url_ann.GetCount() && url_ann[i].GetCount()) + out << "/Annots[" << url_ann[i] << "]\n"; out << ">>\n"; EndObj(); } diff --git a/uppsrc/PdfDraw/PdfDraw.h b/uppsrc/PdfDraw/PdfDraw.h index fd984f08d..e77e16aee 100644 --- a/uppsrc/PdfDraw/PdfDraw.h +++ b/uppsrc/PdfDraw/PdfDraw.h @@ -258,6 +258,8 @@ public: virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx); + virtual void Escape(const String& data); + private: struct CharPos : Moveable { word fi, ci; }; @@ -266,12 +268,18 @@ private: bool sitalic; bool sbold; }; + + struct UrlInfo { + Rectf rect; + String url; + }; VectorMap outline_info; VectorMap > pdffont; VectorMap > fontchars; Index patterns; VectorMap< Tuple2, Image> images; + Array< Array > page_url; Vector offset; StringBuffer out; @@ -286,6 +294,9 @@ private: uint64 patternid; bool pdfa; bool empty; + String url; + Vector offset_stack; + Point current_offset; inline double Pt(double dot) { return 0.12 * dot; } @@ -304,6 +315,9 @@ private: void FlushText(int dx, int fi, int height, const String& txt); static String PdfColor(Color c); + void PushOffset(); + void PopOffset(); + OutlineInfo GetOutlineInfo(Font fnt); struct M22 { @@ -336,7 +350,7 @@ public: String Finish(); void Clear(); bool IsEmpty() const { return empty; } - + PdfDraw(int pagecx, int pagecy, bool pdfa = false) { Init(pagecx, pagecy, 0, pdfa); } PdfDraw(Size pgsz = Size(5100, 6600), bool pdfa = false) { Init(pgsz.cx, pgsz.cy, 0, pdfa); } }; diff --git a/uppsrc/RichText/ParaPaint.cpp b/uppsrc/RichText/ParaPaint.cpp index 4d30ab15c..2f146152d 100644 --- a/uppsrc/RichText/ParaPaint.cpp +++ b/uppsrc/RichText/ParaPaint.cpp @@ -76,6 +76,8 @@ void RichPara::Flush(Draw& draw, const PaintInfo& pi, wchar *text, } x = zx0; Vector< Tuple2 > bak; + if(f.link.GetCount()) + draw.Escape("url:" + f.link); for(int i = 0; i < len; i++) { int w = wd[pos + i]; Image img; @@ -113,6 +115,8 @@ void RichPara::Flush(Draw& draw, const PaintInfo& pi, wchar *text, text + pos, fnt, ink, len, wd + pos); for(int i = 0; i < bak.GetCount(); i++) text[bak[i].a] = bak[i].b; + if(f.link.GetCount()) + draw.Escape("url:"); } } @@ -168,7 +172,7 @@ void RichPara::DrawRuler(Draw& w, int x, int y, int cx, int cy, Color ink, int s case RULER_DOT: while(x < r) { w.DrawRect(x, y, min(r - x, segment), cy, ink); - x += 2 * segment; + x += 2 * segment; } break; default: diff --git a/uppsrc/RichText/TxtPaint.cpp b/uppsrc/RichText/TxtPaint.cpp index be306e7a2..bcdf02daa 100644 --- a/uppsrc/RichText/TxtPaint.cpp +++ b/uppsrc/RichText/TxtPaint.cpp @@ -95,7 +95,7 @@ PageY RichTxt::GetNextPageY(int parti, const RichContext& rc) const py.y += pp.cy; else for(int lni = 0; lni < pp.linecy.GetCount(); lni++) { - if(BreaksPage(py, pp, lni, rc.page)) { + if(BreaksPage(py, pp, lni, rc.page)) { py.y = rc.page.top; py.page++; }