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 + -
显示快捷键?