textformatter.cpp
来自「俄罗斯人开发的大名鼎鼎的Pocket Pc 阅读器haaliread的源代码,v」· C++ 代码 · 共 775 行 · 第 1/2 页
CPP
775 行
/*
* Copyright (c) 2001,2002,2003 Mike Matsnev. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Absolutely no warranty of function or purpose is made by the author
* Mike Matsnev.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: TextFormatter.cpp,v 1.66.2.6 2004/01/08 11:06:06 mike Exp $
*
*/
#include <afxwin.h>
#include <afxtempl.h>
#include "ptr.h"
#include "FDC.h"
#include "FilePos.h"
#include "TextFile.h"
#include "TextFormatter.h"
#include "TextViewNG.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#ifndef MAXINT
#define MAXINT 0x7fffffff
#endif
#define FBIG_ADD 4
#define FSMALL_ADD -1
TextFormatter::TextFormatter(TextFile *tf) :
m_tf(tf),
m_width(1),
m_height(1),
m_pages(1),
m_justified(false),
m_hyphenate(false),
m_hllen(0),
m_angle(0)
{
m_junk.flags=Line::first|Line::last;
}
void TextFormatter::GetTextExtent(CFDC& dc,Paragraph& line,int off,
int width,int& nch,int *dx,int& lh,int& lb)
{
const wchar_t *sp=line.str;
Attr *att=line.cflags+off;
int len=nch-off;
int xoff=0;
sp+=off;
nch=0;
while (len>0 && width>0) {
int i;
int n=0;
SIZE sz;
Attr curatt=att[0];
if (curatt.img) { // inline image
int idx=*sp;
Image img;
if (idx<line.links.size() &&
m_tf->GetImage(line.links[idx].target,dc.DC(),
width,m_height,m_angle,img))
{
int dh=img.height-lb;
if (dh>0) {
lh+=dh;
lb+=dh;
}
sz.cx=img.width;
*dx=xoff+img.width;
}
n=1;
++nch;
if (len==1)
break;
} else {
for (i=1;i<len && att[i].fontflags()==curatt.fontflags();++i);
dc.SelectFont(curatt.fsize,curatt.fontattr(),true);
int fh,fa;
dc.GetFontSize(fh,fa);
if (lh<fh) {
lh=fh;
lb=fa;
}
dc.GetTextExtent(sp,i,width,n,dx,sz);
if (n==0)
break;
for (int j=0;j<n;++j)
dx[j]+=xoff;
nch+=n;
if (i==len)
break;
}
xoff+=sz.cx;
width-=sz.cx;
dx+=n;
sp+=n;
att+=n;
len-=n;
}
}
void CopyAttr(Attr *dest,const Attr *src,DWORD len) {
while (len--)
(*dest++=*src++).hyphen=false;
}
static void AdjustIndent(int& width,int& indent,int li,int ri,int fi,int lpx) {
int pli=lpx*(li+fi)/25;
int pri=lpx*ri/25;
if (width-pli<50)
pli=width-50;
width-=pli;
indent+=pli;
width-=pri;
if (width<50)
width=50;
}
// split image into strips
int TextFormatter::WrapImage(CFDC& dc,Paragraph& pp,
FilePos& pos,LineArray& la,
int top,int maxh)
{
Image img;
#if 0
int curwidth=m_width;
int ispace=0;
AdjustIndent(curwidth,ispace,pp.lindent,pp.rindent,0,dc.GetLPX());
#else
int curwidth=m_total_width;
int ispace=-m_margin;
#endif
if (pp.links.size()<=0 ||
!m_tf->GetImage(pp.links[0].target,dc.DC(),curwidth,m_height,m_angle,img))
{ // image fetch failed, just skip the paragraph
pos.off+=pp.len;
return 0;
}
#if 0
if (top && img.height>maxh)
return -1;
#endif
// calc strips, min strip height is 16
int striph=(img.height+pp.str.size()-1)/pp.str.size();
if (striph<16)
striph=16;
if (striph>img.height)
striph=img.height;
// number of visible strips
int vstrips=(img.height+striph-1)/striph;
int topstrip=vstrips;
if (topstrip>pp.len)
topstrip=pp.len;
// all lines are the same
Line line(L" ",1,false);
line.attr[0].wa=0;
line.dx[0]=0;
line.ispace=ispace+(curwidth-img.width)/2;
line.href=pp.links[0].target;
line.pos=pos;
line.flags=Line::image;
line.height=striph;
line.base=curwidth;
line.imageheight=m_height;
// take care of the strip offset
int stripnum=pos.off;
int yoffset=stripnum*striph;
// add visible strips as lines
int toth=0;
// add visible strips
while (stripnum<topstrip) {
line.yoffset=yoffset;
line.pos=pos;
if (stripnum==vstrips-1) { // last line
// assign all unsused spaces here
int spcount=pp.len-pos.off;
line.attr=Buffer<Attr>(spcount);
line.str=Buffer<wchar_t>(spcount);
line.dx=Buffer<int>(spcount);
for (int i=0;i<spcount;++i) {
line.attr[i].wa=0;
line.str[i]=L' ';
line.dx[i]=0;
}
line.real_len=spcount;
// adjust line height
line.height=img.height-striph*stripnum;
}
if (toth+line.height>maxh)
break;
la.Add(line);
pos.off+=line.real_len;
++stripnum;
yoffset+=striph;
toth+=line.height;
}
// ok, return processed height
// if we didn't process anything, return a failure
return toth ? toth : -1;
}
// the formatter's core, wraps the line and justifies it if needed
int TextFormatter::WrapLine(CFDC& dc,Paragraph& pp,
FilePos& pos,LineArray& la,
int top,int maxh)
{
if (maxh<=0)
return 0;
// process images separately
if (pp.flags&Paragraph::image)
return WrapImage(dc,pp,pos,la,top,maxh);
if (pp.len==0 || (pp.len==1 && pp.str[0]==L' ')) {
dc.SelectFont(0,0);
int fh,fa;
dc.GetFontSize(fh,fa);
if (fh>maxh)
return -1;
Line l;
l.pos=pos;
l.flags=Line::first|Line::last|Line::defstyle;
l.height=fh;
l.base=fa;
la.Add(l);
pos.off=pp.len;
return l.height;
}
if (m_hyphenate)
pp.Hyphenate();
const wchar_t *str=pp.str;
int len=pp.len;
Buffer<int> dx(len+1);
int toth=0;
while (toth<maxh && pos.off<len) {
// 1. get text size
int nch=len;
int curwidth=m_width;
int ispace=0;
if (pos.off==0 && (pp.flags&(Paragraph::center|Paragraph::right))==0)
AdjustIndent(curwidth,ispace,pp.lindent,pp.rindent,pp.findent,dc.GetLPX());
else
AdjustIndent(curwidth,ispace,pp.lindent,pp.rindent,0,dc.GetLPX());
dx[0]=0;
int lh=1,lbase=1;
GetTextExtent(dc,pp,pos.off,curwidth,nch,dx+1,lh,lbase);
if (toth+lh>maxh)
return -1;
if (nch==0)
nch=1;
// 2. do word wrap
bool addhyp=false;
if (nch+pos.off<pp.str.size()) {
int i;
for (i=nch;i>0 && str[pos.off+i]!=L' ';--i) {
// wrap at existing dashes
if (i<nch && (str[pos.off+i]==L'-' || str[pos.off+i]==0x2013 ||
str[pos.off+i]==0x2014) && i<len-1 && (str[pos.off+i+1]==L' ' ||
iswalpha(str[pos.off+i+1])))
{
++i;
break;
}
// or at possible hyphenation points
if (m_hyphenate && pp.cflags[pos.off+i].hyphen &&
dx[i]+dc.GetHypWidth()<=curwidth) {
addhyp=true;
break;
}
}
if (i>0)
nch=i;
else
addhyp=false;
}
// insert it into line list
if (pos.off==0 && nch==pp.str.size()) { // got full line
Line l(str,len,false);
l.pos=pos;
l.flags=Line::first|Line::last;
l.ispace=ispace;
l.height=lh;
l.base=lbase;
if (dx[nch]<curwidth) {
if (pp.flags&Paragraph::center)
l.ispace+=(curwidth-dx[nch])/2;
else if (pp.flags&Paragraph::right)
l.ispace+=curwidth-dx[nch];
}
CopyAttr(l.attr,pp.cflags,len);
for (int j=0;j<len;++j)
l.dx[j]=dx[j+1]-dx[j];
la.Add(l);
pos.off=len;
} else {
Line l(str+pos.off,nch,addhyp);
if (addhyp)
l.str[nch]=L'-';
l.pos=pos;
l.ispace=ispace;
l.height=lh;
l.base=lbase;
l.flags=0;
if (pos.off==0)
l.flags|=Line::first;
if (pos.off+nch==pp.str.size())
l.flags|=Line::last;
for (int j=0;j<nch;++j)
l.dx[j]=dx[j+1]-dx[j];
int extra_width=0;
if (addhyp)
l.dx[nch]=extra_width=dc.GetHypWidth();
// 3. justify/center text if needed
if (dx[nch]<curwidth) {
if (addhyp)
curwidth-=extra_width;
if (pp.flags&Paragraph::center) {
l.ispace+=(curwidth-dx[nch])/2;
} else if (pp.flags&Paragraph::right) {
l.ispace+=curwidth-dx[nch];
} else if ((m_justified || pp.flags&Paragraph::justify) &&
!(l.flags&Line::last))
{
// count spaces in string
int nspc=0,i;
for (i=0;i<nch;++i)
if (L' '==str[pos.off+i])
++nspc;
// and distribute extra width to them
if (nspc>0) {
int addw=(curwidth-dx[nch])/nspc;
int extraddw=curwidth-dx[nch]-addw*nspc;
for (i=0;i<nch;++i) {
if (str[pos.off+i]==L' ') {
l.dx[i]+=addw;
if (extraddw) {
++l.dx[i];
--extraddw;
}
}
}
}
}
}
CopyAttr(l.attr,pp.cflags+pos.off,nch);
if (addhyp)
l.attr[nch]=l.attr[nch-1];
la.Add(l);
pos.off+=nch;
while (pos.off<len && str[pos.off]==L' ')
++pos.off;
}
toth+=lh;
}
return toth;
}
bool TextFormatter::FormatFwd(CFDC& dc,FilePos start) {
AdjustPos(start); // just to be safe
if (start.para>=m_tf->Length(start.docid))
return false; // at eof
m_lines.RemoveAll();
m_top=start;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?