// 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; }
// 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; }