Link destionation includes rectangle on page.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3695 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer
2003-06-27 17:19:35 +00:00
parent 61594003dd
commit 2e07400817
5 changed files with 154 additions and 113 deletions
+109 -84
View File
@@ -37,53 +37,43 @@ THE SOFTWARE.
#include "Log.h" #include "Log.h"
#include "Report.h" #include "Report.h"
Link::Link(PDFWriter* writer, BString* utf8, BFont* font) Link::Link(PDFWriter* writer, BString* utf8)
: fWriter(writer) : fWriter(writer)
, fUtf8(utf8) , fUtf8(utf8)
, fFont(font)
, fPos(0)
, fContainsLink(false) , fContainsLink(false)
{ {
} }
bool
Link::BoundingBox(BRect* rect) {
return fWriter->fTextLine.BoundingBox(fStartPos, fEndPos+1, rect);
}
// create link from fStartPos to fEndPos and fStart to end // create link from fStartPos to fEndPos and fStart to end
void void
Link::CreateLink(BPoint end) Link::CreateLink()
{ {
if (fFont->Rotation() != 0.0) { static bool reported = false; // report warning once only
BRect bounds;
if (BoundingBox(&bounds)) {
CreateLink(bounds.left, bounds.bottom, bounds.right, bounds.top);
} else if (!reported) {
REPORT(kWarning, fWriter->fPage, "Warning: Can not create link for rotated font!"); REPORT(kWarning, fWriter->fPage, "Warning: Can not create link for rotated font!");
return; reported = true;
} }
// calculate rectangle for url
font_height height;
fFont->GetHeight(&height);
float llx, lly, urx, ury;
llx = fWriter->tx(fStart.x);
urx = fWriter->tx(end.x);
lly = fWriter->ty(fStart.y + height.descent);
ury = fWriter->ty(end.y - height.ascent);
CreateLink(llx, lly, urx, ury);
} }
void void
Link::NextChar(int cps, float x, float y, float w) Link::Do() {
{ int pos = 0;
if (fContainsLink) { do {
if (fPos == fStartPos) { DetectLink(pos);
fStart.Set(x, y); if (ContainsLink()) {
CreateLink();
pos = fEndPos;
} }
if (fPos == fEndPos) { } while (ContainsLink());
CreateLink(BPoint(x + w, y));
DetectLink(fPos + cps);
}
fPos += cps;
}
} }
// TODO: check this list and add more prefixes // TODO: check this list and add more prefixes
@@ -292,8 +282,8 @@ WebLink::CreateLink(float llx, float lly, float urx, float ury)
} }
WebLink::WebLink(PDFWriter* writer, BString* utf8, BFont* font) WebLink::WebLink(PDFWriter* writer, BString* utf8)
: Link(writer, utf8, font) : Link(writer, utf8)
{ {
} }
@@ -371,6 +361,78 @@ bool TextLine::Follows(TextSegment* segment) const {
return false; return false;
} }
bool TextLine::BoundingBox(int startPos, int endPos, BRect* bounds) {
const int32 n = fSegments.CountItems();
if (n == 0) return false;
// build the text in the line
BString line;
for (int32 i = 0; i < n; i ++) {
line << fSegments.ItemAt(i)->Text();
}
const char* c = line.String();
const char* pStart = &c[startPos];
const char* pEnd = &c[endPos];
for (int32 i = 0; i < n; i ++) {
TextSegment* seg = fSegments.ItemAt(i);
BPoint pos = seg->Start();
BFont* font = seg->Font();
const char* sc = seg->Text();
float escpSpace = seg->EscpSpace();
float escpNoSpace = seg->EscpNoSpace();
int32 spaces = seg->Spaces();
PDFSystem* system = seg->System();
while (*sc != 0) {
ASSERT(*sc == *c);
int s = fWriter->CodePointSize((char*)c);
float w = font->StringWidth(c, s);
if (c == pStart) {
bounds->left = bounds->right = system->tx(pos.x);
bounds->top = bounds->bottom = system->ty(pos.y);
}
if (pStart <= c && c < pEnd) {
font_height height;
font->GetHeight(&height);
float top = system->ty(pos.y - height.ascent);
float bottom = system->ty(pos.y + height.descent);
if (bounds->top < top) bounds->top = top;
if (bounds->bottom > bottom) bounds->bottom = bottom;
bounds->right = system->tx(pos.x+w);
}
if (spaces == 0) {
// position of next character
if (*(unsigned char*)c <= 0x20) { // should test if c is a white-space!
w += escpSpace;
} else {
w += escpNoSpace;
}
pos.x += w;
} else {
// skip over the prepended spaces
spaces --;
}
// next character
c += s; sc += s;
if (c >= pEnd) {
return true;
}
}
}
return false;
}
void TextLine::Flush() { void TextLine::Flush() {
const int32 n = fSegments.CountItems(); const int32 n = fSegments.CountItems();
@@ -387,65 +449,28 @@ void TextLine::Flush() {
if (!fWriter->MakesPDF()) { if (!fWriter->MakesPDF()) {
if (fWriter->fCreateXRefs) fWriter->RecordDests(c); if (fWriter->fCreateXRefs) fWriter->RecordDests(c);
} else { } else {
// XXX
TextSegment* s = fSegments.ItemAt(0);
BFont* f = s->Font();
// simple link handling for now // simple link handling for now
WebLink webLink(fWriter, &line, f); WebLink webLink(fWriter, &line);
if (fWriter->fCreateWebLinks) webLink.Init(); if (fWriter->fCreateWebLinks) webLink.Do();
// local links // local links
LocalLink localLink(fWriter->fXRefs, fWriter->fXRefDests, fWriter, &line, f, fWriter->fPage); LocalLink localLink(fWriter->fXRefs, fWriter->fXRefDests, fWriter, &line, fWriter->fPage);
if (fWriter->fCreateXRefs) localLink.Init(); if (fWriter->fCreateXRefs) localLink.Do();
// simple bookmark adding (XXX: s->Start() // simple bookmark adding
if (fWriter->fCreateBookmarks) { if (fWriter->fCreateBookmarks) {
BPoint start(s->System()->tx(s->Start().x), s->System()->ty(s->Start().y)); TextSegment* s = fSegments.ItemAt(0);
fWriter->fBookmark->AddBookmark(start, c, f); BFont* f = s->Font();
} PDFSystem* system = s->System();
BPoint start(system->tx(s->Start().x), system->ty(s->Start().y));
for (int32 i = 0; i < n; i ++) { font_height height;
f->GetHeight(&height);
TextSegment* seg = fSegments.ItemAt(i); float h = system->scale(height.ascent);
BPoint pos = seg->Start();
BFont* font = seg->Font(); fWriter->fBookmark->AddBookmark(start, h, c, f);
const char* sc = seg->Text();
float escpSpace = seg->EscpSpace();
float escpNoSpace = seg->EscpNoSpace();
int32 spaces = seg->Spaces();
while (*sc != 0) {
ASSERT(*sc == *c);
int s = fWriter->CodePointSize((char*)c);
float w = font->StringWidth(c, s);
if (fWriter->fCreateWebLinks) webLink.NextChar(s, pos.x, pos.y, w);
if (fWriter->fCreateXRefs) localLink.NextChar(s, pos.x, pos.y, w);
if (spaces == 0) {
// position of next character
if (*(unsigned char*)c <= 0x20) { // should test if c is a white-space!
w += escpSpace;
} else {
w += escpNoSpace;
}
pos.x += w;
} else {
// skip over the prepended spaces
spaces --;
}
// next character
c += s; sc += s;
}
} }
} }
fSegments.MakeEmpty(); fSegments.MakeEmpty();
} }
+12 -8
View File
@@ -37,26 +37,28 @@ THE SOFTWARE.
class PDFWriter; class PDFWriter;
class TextLine;
class Link { class Link {
protected: protected:
PDFWriter* fWriter; PDFWriter* fWriter;
BString* fUtf8; BString* fUtf8;
BFont* fFont;
int fPos; // into fUtf8
bool fContainsLink; bool fContainsLink;
int fStartPos, fEndPos; int fStartPos, fEndPos;
BPoint fStart;
virtual void DetectLink(int start) = 0; virtual void DetectLink(int start) = 0;
virtual void CreateLink(float llx, float lly, float urx, float ury) = 0; virtual void CreateLink(float llx, float lly, float urx, float ury) = 0;
void CreateLink(BPoint end); void CreateLink();
bool ContainsLink() const { return fContainsLink; }
private:
bool BoundingBox(BRect* rect);
public: public:
Link(PDFWriter* writer, BString* utf8, BFont* font); Link(PDFWriter* writer, BString* utf8);
void Init() { DetectLink(0); } void Do();
void NextChar(int cps, float x, float y, float w);
}; };
class WebLink : public Link { class WebLink : public Link {
@@ -82,7 +84,7 @@ class WebLink : public Link {
void DetectLink(int start); void DetectLink(int start);
public: public:
WebLink(PDFWriter* writer, BString* utf8, BFont* font); WebLink(PDFWriter* writer, BString* utf8);
}; };
class TextSegment { class TextSegment {
@@ -122,6 +124,8 @@ public:
void Add(TextSegment* segment); void Add(TextSegment* segment);
void Flush(); void Flush();
// startPos inclusive, endPos exclusive
bool BoundingBox(int startPos, int endPos, BRect* bounds);
}; };
@@ -321,7 +321,7 @@ PDFWriter::CodePointSize(const char* s)
void PDFWriter::RecordDests(const char* s) { void PDFWriter::RecordDests(const char* s) {
::RecordDests record(fXRefDests, fPage); ::RecordDests record(fXRefDests, &fTextLine, fPage);
fXRefs->Matches(s, &record, true); fXRefs->Matches(s, &record, true);
} }
@@ -214,7 +214,7 @@ Line comment starts with: '#'
Definition = Version {XRefDef}. Definition = Version {XRefDef}.
Version = "CrossReferences" "1.0". Version = "CrossReferences" "1.0".
XRefDef = Pattern {"," Pattern} "-" ">" Pattern {, Pattern} ".". XRefDef = Pattern {"," Pattern} "-" ">" Pattern {"," Pattern} ".".
Pattern = '"' string '"'. Pattern = '"' string '"'.
Example: Example:
@@ -301,9 +301,10 @@ bool XRefDefs::Read(const char* name) {
// Destination // Destination
Destination::Destination(const char* label, int32 page) Destination::Destination(const char* label, int32 page, BRect bounds)
: fLabel(label) : fLabel(label)
, fPage(page) , fPage(page)
, fBoundingBox(bounds)
{ {
} }
@@ -336,23 +337,24 @@ XRefDests::XRefDests(int32 n) {
} }
bool XRefDests::Add(XRefDef* def, const char* label, int32 page) { bool XRefDests::Add(XRefDef* def, const char* label, int32 page, BRect boundingBox) {
DestList* list = GetList(def); DestList* list = GetList(def);
ASSERT(list != NULL); ASSERT(list != NULL);
if (!list->Find(label)) { if (!list->Find(label)) {
list->AddItem(new Destination(label, page)); list->AddItem(new Destination(label, page, boundingBox));
return true; return true;
} }
return false; return false;
} }
bool XRefDests::Find(XRefDef* def, const char* label, int32* page) const { bool XRefDests::Find(XRefDef* def, const char* label, int32* page, BRect* boundingBox) const {
DestList* list = GetList(def); DestList* list = GetList(def);
ASSERT(list != NULL); ASSERT(list != NULL);
Destination* dest = list->Find(label); Destination* dest = list->Find(label);
if (dest) { if (dest) {
*page = dest->Page(); *page = dest->Page();
*boundingBox = dest->BoundingBox();
return true; return true;
} }
return false; return false;
@@ -361,13 +363,13 @@ bool XRefDests::Find(XRefDef* def, const char* label, int32* page) const {
// RecordDests // RecordDests
RecordDests::RecordDests(XRefDests* dests, int32 page) RecordDests::RecordDests(XRefDests* dests, TextLine* line, int32 page)
: fDests(dests) : fDests(dests)
, fLine(line)
, fPage(page) , fPage(page)
{ {
} }
bool RecordDests::Link(XRefDef* def, MatchResult* result) { bool RecordDests::Link(XRefDef* def, MatchResult* result) {
return true; return true;
} }
@@ -376,8 +378,11 @@ bool RecordDests::Link(XRefDef* def, MatchResult* result) {
bool RecordDests::Dest(XRefDef* def, MatchResult* result) { bool RecordDests::Dest(XRefDef* def, MatchResult* result) {
if (result->CountResults() >= 2) { if (result->CountResults() >= 2) {
BString s; BString s;
BRect b;
result->GetString(1, &s); result->GetString(1, &s);
fDests->Add(def, s.String(), fPage); if (fLine->BoundingBox(result->StartPos(1), result->EndPos(1), &b)) {
fDests->Add(def, s.String(), fPage, b);
}
} }
return true; return true;
} }
@@ -385,8 +390,8 @@ bool RecordDests::Dest(XRefDef* def, MatchResult* result) {
// LocalLink // LocalLink
LocalLink::LocalLink(XRefDefs* defs, XRefDests* dests, PDFWriter* writer, BString* utf8, BFont* font, int32 page) LocalLink::LocalLink(XRefDefs* defs, XRefDests* dests, PDFWriter* writer, BString* utf8, int32 page)
: ::Link(writer, utf8, font) : ::Link(writer, utf8)
, fDefs(defs) , fDefs(defs)
, fDests(dests) , fDests(dests)
, fLinkPage(page) , fLinkPage(page)
@@ -398,7 +403,7 @@ bool LocalLink::Link(XRefDef* def, MatchResult* result) {
if (result->CountResults() >= 2) { if (result->CountResults() >= 2) {
BString label; BString label;
result->GetString(1, &label); result->GetString(1, &label);
if (fDests->Find(def, label.String(), &fDestPage)) { if (fDests->Find(def, label.String(), &fDestPage, &fDestBounds)) {
result->Start(1); result->Start(1);
fContainsLink = true; fContainsLink = true;
fStartPos = result->Start(1) - fUtf8->String(); fStartPos = result->Start(1) - fUtf8->String();
@@ -428,9 +433,11 @@ void LocalLink::DetectLink(int start) {
void LocalLink::CreateLink(float llx, float lly, float urx, float ury) { void LocalLink::CreateLink(float llx, float lly, float urx, float ury) {
char optList[256];
if (fDestPage != fLinkPage) { if (fDestPage != fLinkPage) {
BString s(&fUtf8->String()[fStartPos], fEndPos-fStartPos+1); BString s(&fUtf8->String()[fStartPos], fEndPos-fStartPos+1);
REPORT(kInfo, fLinkPage, "Link '%s' to page %d", s.String(), fDestPage); REPORT(kInfo, fLinkPage, "Link '%s' to page %d", s.String(), fDestPage);
PDF_add_locallink(fWriter->fPdf, llx, lly, urx, ury, fDestPage, "retain"); sprintf(optList, "type=fixed left=%f top=%f", fDestBounds.left, fDestBounds.top);
PDF_add_locallink(fWriter->fPdf, llx, lly, urx, ury, fDestPage, optList);
} }
} }
@@ -168,11 +168,13 @@ class Destination {
private: private:
BString fLabel; BString fLabel;
int32 fPage; int32 fPage;
BRect fBoundingBox;
public: public:
Destination(const char* label, int32 page); Destination(const char* label, int32 page, BRect bounds);
const char* Label() const { return fLabel.String(); } const char* Label() const { return fLabel.String(); }
int32 Page() const { return fPage; } int32 Page() const { return fPage; }
BRect BoundingBox() const { return fBoundingBox; }
}; };
@@ -194,8 +196,8 @@ class XRefDests {
public: public:
XRefDests(int32 n); XRefDests(int32 n);
bool Add(XRefDef* def, const char* label, int32 page); bool Add(XRefDef* def, const char* label, int32 page, BRect boundingBox);
bool Find(XRefDef* def, const char* label, int32* page) const; bool Find(XRefDef* def, const char* label, int32* page, BRect* boundingBox) const;
}; };
@@ -203,10 +205,11 @@ public:
class RecordDests : public XMatchResult { class RecordDests : public XMatchResult {
XRefDests* fDests; XRefDests* fDests;
TextLine* fLine;
int32 fPage; int32 fPage;
public: public:
RecordDests(XRefDests* dests, int32 page); RecordDests(XRefDests* dests, TextLine* line, int32 page);
bool Link(XRefDef* def, MatchResult* result); bool Link(XRefDef* def, MatchResult* result);
bool Dest(XRefDef* def, MatchResult* result); bool Dest(XRefDef* def, MatchResult* result);
}; };
@@ -217,15 +220,17 @@ public:
class LocalLink : public Link, XMatchResult { class LocalLink : public Link, XMatchResult {
protected: protected:
XRefDefs* fDefs; XRefDefs* fDefs;
XRefDests* fDests; XRefDests* fDests;
int32 fLinkPage;
int32 fLinkPage, fDestPage; int32 fDestPage;
BRect fDestBounds;
void DetectLink(int start); void DetectLink(int start);
void CreateLink(float llx, float lly, float urx, float ury); void CreateLink(float llx, float lly, float urx, float ury);
public: public:
LocalLink(XRefDefs* defs, XRefDests* dests, PDFWriter* writer, BString* utf8, BFont* font, int32 page); LocalLink(XRefDefs* defs, XRefDests* dests, PDFWriter* writer, BString* utf8, int32 page);
bool Link(XRefDef* def, MatchResult* result); bool Link(XRefDef* def, MatchResult* result);
bool Dest(XRefDef* def, MatchResult* result); bool Dest(XRefDef* def, MatchResult* result);
}; };