ultimatepp/uppsrc/RichText/ParaType.cpp
mdelfede d2b54f7989 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

376 lines
8.2 KiB
C++

#include "RichText.h"
NAMESPACE_UPP
void RichPara::Smh(Lines& lines, HeightInfo *th, int cx) const
{
Line& l = lines.line.Top();
l.ascent = l.descent = l.external = 0;
const HeightInfo *he = th + l.pos + l.len;
for(const HeightInfo *h = th + l.pos; h < he; h++) {
if(h->ascent > l.ascent) l.ascent = h->ascent;
if(h->descent > l.descent) l.descent = h->descent;
if(h->external > l.external) l.external = h->external;
}
if(format.linespacing == LSP15) {
l.ascent = (3 * l.ascent) >> 1;
l.descent = (3 * l.descent) >> 1;
}
if(format.linespacing == LSP20) {
l.ascent = 2 * l.ascent;
l.descent = 2 * l.descent;
}
l.xpos = format.lm;
cx -= format.lm + format.rm;
l.xpos += lines.GetCount() == 1 ? lines.first_indent : lines.next_indent;
if(!l.withtabs)
switch(format.align) {
case ALIGN_RIGHT:
l.xpos += cx - l.cx;
break;
case ALIGN_CENTER:
l.xpos += (cx - l.cx) / 2;
break;
}
l.cx -= lines.GetCount() == 1 ? lines.first_indent : lines.next_indent;
}
RichPara::Tab RichPara::GetNextTab(int pos) const
{
int tabi = -1;
int dist = INT_MAX;
for(int i = 0; i < format.tab.GetCount(); i++) {
const Tab& tab = format.tab[i];
if(tab.pos > pos && tab.pos - pos < dist) {
tabi = i;
dist = tab.pos - pos;
}
}
if(format.bullet == BULLET_TEXT) {
int q = format.indent + format.lm;
if(q > pos && q - pos < dist) {
Tab tab;
tab.align = ALIGN_LEFT;
tab.pos = q;
return tab;
}
}
if(tabi < 0) {
Tab tab;
tab.pos = format.tabsize ? (pos + format.tabsize) / format.tabsize * format.tabsize : 0;
tab.align = ALIGN_LEFT;
return tab;
}
return format.tab[tabi];
}
struct RichPara::StorePart {
wchar *t;
int *w;
int *p;
const CharFormat **f;
HeightInfo *h;
int pos;
FontInfo pfi;
void Store(Lines& lines, const Part& p, int pinc);
};
void RichPara::StorePart::Store(Lines& lines, const Part& part, int pinc)
{
if(part.field && pinc) {
for(int i = 0; i < part.fieldpart.GetCount(); i++)
Store(lines, part.fieldpart[i], 0);
pos++;
}
else
if(part.object) {
*f++ = &part.format;
Size sz = part.object.GetSize();
*w++ = sz.cx;
h->ydelta = part.object.GetYDelta();
h->ascent = sz.cy - h->ydelta;
h->descent = max(h->ydelta, 0);
h->external = 0;
h->object = &part.object;
h++;
*t++ = 'x';
*p++ = pos;
pos += pinc;
}
else {
const wchar *s = part.text;
const wchar *lim = part.text.End();
Font fnt = part.format;
FontInfo fi = fnt.Info();
FontInfo wfi = fi;
if(part.format.sscript) {
fnt.Height(fnt.GetHeight() * 3 / 5);
wfi = fnt.Info();
}
if(part.format.capitals) {
CharFormat& cfmt = lines.hformat.Add();
cfmt = part.format;
cfmt.Height(cfmt.GetHeight() * 4 / 5);
FontInfo cfi = cfmt.Info();
FontInfo cwfi = cfi;
if(part.format.sscript) {
Font fnt = cfmt;
fnt.Height(fnt.GetHeight() * 3 / 5);
cwfi = fnt.Info();
}
while(s < lim) {
wchar c = *s++;
if(c == 9) {
*f++ = &part.format;
h->ascent = pfi.GetAscent();
h->descent = pfi.GetDescent();
h->external = pfi.GetExternal();
*w++ = 0;
}
else
if(IsLower(c)) {
*f++ = &cfmt;
c = ToUpper(c);
h->ascent = cfi.GetAscent();
h->descent = cfi.GetDescent();
h->external = cfi.GetExternal();
*w++ = c >= 32 ? cwfi[c] : 0;
}
else {
*f++ = &part.format;
h->ascent = fi.GetAscent();
h->descent = fi.GetDescent();
h->external = fi.GetExternal();
*w++ = c >= 32 ? wfi[c] : 0;
}
h->object = NULL;
*t++ = c;
*p++ = pos;
pos += pinc;
h++;
}
}
else {
while(s < lim) {
wchar c = *s++;
*f++ = &part.format;
if(c == 9) {
h->ascent = pfi.GetAscent();
h->descent = pfi.GetDescent();
h->external = pfi.GetExternal();
}
else {
h->ascent = fi.GetAscent();
h->descent = fi.GetDescent();
h->external = fi.GetExternal();
}
h->object = NULL;
*p++ = pos;
pos += pinc;
h++;
*w++ = c >= 32 ? wfi[c] : 0;
*t++ = c;
}
}
}
}
static int CountChars(const Array<RichPara::Part>& part)
{
int n = 0;
for(int i = 0; i < part.GetCount(); i++) {
const RichPara::Part& p = part[i];
if(p.field)
n += CountChars(p.fieldpart);
else
n += p.GetLength();
}
return n;
}
RichPara::Lines RichPara::FormatLines(int acx) const
{
int i;
Lines lines;
lines.cx = acx;
lines.len = GetLength();
lines.clen = CountChars(part);
lines.first_indent = lines.next_indent = format.indent;
if(format.bullet == BULLET_TEXT)
lines.first_indent = 0;
else
if(!format.bullet && !format.IsNumbered())
lines.next_indent = 0;
FontInfo pfi = format.Info();
if(lines.len == 0) {
Line& l = lines.line.Add();
l.pos = 0;
l.ppos = 0;
l.plen = 0;
l.len = 0;
l.cx = lines.first_indent;
l.withtabs = false;
HeightInfo dummy;
Smh(lines, &dummy, lines.cx);
l.ascent = pfi.GetAscent();
l.descent = pfi.GetDescent();
l.external = pfi.GetExternal();
return lines;
}
lines.text.Alloc(lines.clen);
lines.width.Alloc(lines.clen);
lines.pos.Alloc(lines.clen);
lines.format.Alloc(lines.clen);
lines.height.Alloc(lines.clen);
StorePart sp;
sp.t = lines.text;
sp.w = lines.width;
sp.p = lines.pos;
sp.f = lines.format;
sp.h = lines.height;
sp.pfi = pfi;
sp.pos = 0;
for(i = 0; i < part.GetCount(); i++)
sp.Store(lines, part[i], 1);
wchar *s = lines.text;
wchar *text = s;
wchar *end = lines.text + lines.clen;
wchar *space = NULL;
int *w = lines.width;
int cx = lines.first_indent;
int rcx = lines.cx - format.lm - format.rm;
bool withtabs = false;
int scx;
while(s < end) {
Tab t;
if(*s == ' ') {
space = s;
scx = cx;
}
else {
if(*s == '\t') {
t = GetNextTab(cx + format.lm);
space = NULL;
}
if(cx + *w > rcx && s > text || *s == '\t' && t.pos - format.lm >= rcx) {
Line& l = lines.line.Add();
l.withtabs = withtabs;
l.pos = (int)(text - lines.text);
if(space) {
l.len = (int)(space - text) + 1;
l.cx = scx;
text = s = space + 1;
}
else {
l.len = (int)(s - text);
l.cx = cx;
text = s;
}
Smh(lines, lines.height, lines.cx);
cx = lines.next_indent;
w = text - ~lines.text + lines.width;
space = NULL;
rcx = lines.cx - format.lm - format.rm;
withtabs = false;
t = GetNextTab(cx + format.lm);
}
}
if(*s == '\t') {
*s += t.fillchar;
if(t.align == ALIGN_LEFT) {
*w++ = t.pos - format.lm - cx;
cx = t.pos - format.lm;
}
else {
int tcx = 0;
int *tw = w + 1;
for(wchar *ts = s + 1; ts < end && *ts != '\t'; ts++)
tcx += *tw++;
int ww = t.pos - format.lm - cx - (t.align == ALIGN_RIGHT ? tcx : tcx / 2);
if(ww > 0) {
*w++ = ww;
cx += ww;
}
else
*w++ = 0;
}
withtabs = true;
}
else
cx += *w++;
s++;
}
Line& l = lines.line.Add();
l.withtabs = withtabs;
l.pos = (int)(text - lines.text);
l.len = (int)(s - text);
l.cx = cx;
Smh(lines, lines.height, lines.cx);
for(i = 0; i < lines.line.GetCount(); i++) {
Line& l = lines.line[i];
l.ppos = lines.pos[l.pos];
l.plen = (l.pos + l.len < lines.clen ? lines.pos[l.pos + l.len] : lines.len) - l.ppos;
}
return lines;
}
void RichPara::Lines::Justify(const RichPara::Format& format)
{
if(format.align != ALIGN_JUSTIFY) return;
for(int i = 0; i < line.GetCount() - 1; i++) {
const Line& li = line[i];
if(!li.withtabs && li.len) {
const wchar *s = ~text + li.pos;
const wchar *lim = s + li.len;
while(lim - 1 > s) {
if(*(lim - 1) != ' ') break;
lim--;
}
while(s < lim) {
if(*s != ' ' && *s != 160) break;
s++;
}
const wchar *beg = s;
int nspc = 0;
while(s < lim) {
if(*s == ' ' || *s == 160) nspc++;
s++;
}
s = beg;
if(nspc) {
int q = ((cx - format.lm - format.rm -
(i == 0 ? first_indent : next_indent) - li.cx) << 16)
/ nspc;
int *w = beg - ~text + width;
int prec = 0;
while(s < lim) {
if(*s == ' ' || *s == 160) {
*w += (prec + q) >> 16;
prec = (prec + q) & 0xffff;
}
w++;
s++;
}
}
}
}
}
int RichPara::Lines::BodyHeight()
{
int sum = 0;
for(int i = 0; i < line.GetCount(); i++)
sum += line[i].Sum();
return sum;
}
END_UPP_NAMESPACE