src/reportlab/platypus/paragraph.py
changeset 4389 61a7f0840d00
parent 4387 c9accf85d669
child 4409 e1546608f841
equal deleted inserted replaced
4388:9f93d62b9f6e 4389:61a7f0840d00
     5 __doc__='''The standard paragraph implementation'''
     5 __doc__='''The standard paragraph implementation'''
     6 from string import whitespace
     6 from string import whitespace
     7 from operator import truth
     7 from operator import truth
     8 from unicodedata import category
     8 from unicodedata import category
     9 from reportlab.pdfbase.pdfmetrics import stringWidth, getFont, getAscentDescent
     9 from reportlab.pdfbase.pdfmetrics import stringWidth, getFont, getAscentDescent
    10 from reportlab.platypus.paraparser import ParaParser, _PCT
    10 from reportlab.platypus.paraparser import ParaParser, _PCT, _num as _parser_num, _re_us_value
    11 from reportlab.platypus.flowables import Flowable
    11 from reportlab.platypus.flowables import Flowable
    12 from reportlab.lib.colors import Color
    12 from reportlab.lib.colors import Color
    13 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
    13 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
    14 from reportlab.lib.geomutils import normalizeTRBL
    14 from reportlab.lib.geomutils import normalizeTRBL
    15 from reportlab.lib.textsplit import wordSplit, ALL_CANNOT_START
    15 from reportlab.lib.textsplit import wordSplit, ALL_CANNOT_START
    16 from copy import deepcopy
    16 from copy import deepcopy
    17 from reportlab.lib.abag import ABag
    17 from reportlab.lib.abag import ABag
    18 from reportlab.rl_config import platypus_link_underline, decimalSymbol, _FUZZ, paraFontSizeHeightOffset
    18 from reportlab.rl_config import platypus_link_underline, decimalSymbol, _FUZZ, paraFontSizeHeightOffset, \
    19 from reportlab.lib.utils import _className, isBytes, unicodeT, bytesT, strTypes
    19                                 strikeGap, underlineGap
       
    20 from reportlab.lib.utils import _className, isBytes, unicodeT, bytesT, isStr
    20 from reportlab.lib.rl_accel import sameFrag
    21 from reportlab.lib.rl_accel import sameFrag
    21 from reportlab import xrange
    22 from reportlab import xrange
    22 import re
    23 import re
    23 from types import MethodType
    24 from types import MethodType
    24 
    25 
    58     u'\u3000',  # IDEOGRAPHIC SPACE
    59     u'\u3000',  # IDEOGRAPHIC SPACE
    59     ))
    60     ))
    60 _wsc_re_split=re.compile('[%s]+'% re.escape(_wsc)).split
    61 _wsc_re_split=re.compile('[%s]+'% re.escape(_wsc)).split
    61 _wsc_end_search=re.compile('[%s]+$'% re.escape(_wsc)).search
    62 _wsc_end_search=re.compile('[%s]+$'% re.escape(_wsc)).search
    62 
    63 
       
    64 def _usConv(s, vMap, default=None):
       
    65     '''convert a strike/underline distance to a number'''
       
    66     if isStr(s):
       
    67         s = s.strip()
       
    68         if s:
       
    69             m = _re_us_value.match(s)
       
    70             if m:
       
    71                 return float(m.group(1))*vMap[m.group(2)]
       
    72             else:
       
    73                 return _parser_num(s,allowRelative=False)
       
    74         elif default:
       
    75             return default
       
    76     return s
       
    77 
    63 def split(text, delim=None):
    78 def split(text, delim=None):
    64     if isBytes(text): text = text.decode('utf8')
    79     if isBytes(text): text = text.decode('utf8')
    65     if delim is not None and isBytes(delim): delim = delim.decode('utf8')
    80     if delim is not None and isBytes(delim): delim = delim.decode('utf8')
    66     return [uword for uword in (_wsc_re_split(text) if delim is None and u'\xa0' in text else text.split(delim))]
    81     return [uword for uword in (_wsc_re_split(text) if delim is None and u'\xa0' in text else text.split(delim))]
    67 
    82 
   174     else:
   189     else:
   175         return v
   190         return v
   176 
   191 
   177 def _getDotsInfo(style):
   192 def _getDotsInfo(style):
   178     dots = style.endDots
   193     dots = style.endDots
   179     if isinstance(dots,strTypes):
   194     if isStr(dots):
   180         text = dots
   195         text = dots
   181         fontName = style.fontName
   196         fontName = style.fontName
   182         fontSize = style.fontSize
   197         fontSize = style.fontSize
   183         textColor = style.textColor
   198         textColor = style.textColor
   184         backColor = style.backColor
   199         backColor = style.backColor
   225         tx._olb = cur_y - descent
   240         tx._olb = cur_y - descent
   226         tx._oleading = leading
   241         tx._oleading = leading
   227     ws = getattr(tx,'_wordSpace',0)
   242     ws = getattr(tx,'_wordSpace',0)
   228     nSpaces = 0
   243     nSpaces = 0
   229     words = line.words
   244     words = line.words
       
   245     AL = []
       
   246     LL = []
       
   247     us_lines = xs.us_lines
       
   248     links = xs.links
   230     for i, f in enumerate(words):
   249     for i, f in enumerate(words):
   231         if hasattr(f,'cbDefn'):
   250         if hasattr(f,'cbDefn'):
   232             cbDefn = f.cbDefn
   251             cbDefn = f.cbDefn
   233             kind = cbDefn.kind
   252             kind = cbDefn.kind
   234             if kind=='img':
   253             if kind=='img':
   262                     tx.setFont(xs.style.fontName,xs.style.fontSize)
   281                     tx.setFont(xs.style.fontName,xs.style.fontSize)
   263                 tx._textOut('',1)
   282                 tx._textOut('',1)
   264         else:
   283         else:
   265             cur_x_s = cur_x + nSpaces*ws
   284             cur_x_s = cur_x + nSpaces*ws
   266             end_x = cur_x_s
   285             end_x = cur_x_s
       
   286             fontSize = f.fontSize
       
   287             textColor = f.textColor
       
   288             rise = f.rise
   267             if i > 0:
   289             if i > 0:
   268                 end_x = cur_x_s - _trailingSpaceLength(words[i-1].text, tx)
   290                 end_x = cur_x_s - _trailingSpaceLength(words[i-1].text, tx)
   269             if (tx._fontname,tx._fontsize)!=(f.fontName,f.fontSize):
   291             if (tx._fontname,tx._fontsize)!=(f.fontName,fontSize):
   270                 tx._setFont(f.fontName, f.fontSize)
   292                 tx._setFont(f.fontName, fontSize)
   271             if xs.textColor!=f.textColor:
   293             if xs.textColor!=textColor:
   272                 xs.textColor = f.textColor
   294                 xs.textColor = textColor
   273                 tx.setFillColor(f.textColor)
   295                 tx.setFillColor(textColor)
   274             if xs.rise!=f.rise:
   296             if xs.rise!=rise:
   275                 xs.rise=f.rise
   297                 xs.rise=rise
   276                 tx.setRise(f.rise)
   298                 tx.setRise(rise)
   277             text = f.text
   299             text = f.text
   278             tx._textOut(text,f is words[-1])    # cheap textOut
   300             tx._textOut(text,f is words[-1])    # cheap textOut
   279             if not xs.underline and f.underline:
   301             if LL != f.us_lines:
   280                 xs.underline = 1
   302                 S = set(LL)
   281                 xs.underline_x = cur_x_s
   303                 NS = set(f.us_lines)
   282                 xs.underlineColor = f.textColor
   304                 nL = NS - S #new lines
   283             elif xs.underline:
   305                 eL = S - NS #ending lines
   284                 if not f.underline:
   306                 for l in eL:
   285                     xs.underline = 0
   307                     us_lines[l] = us_lines[l],end_x
   286                     xs.underlines.append( (xs.underline_x, end_x, xs.underlineColor) )
   308                 for l in nL:
   287                     xs.underlineColor = None
   309                     us_lines[l] = (l,fontSize,textColor,cur_x),fontSize
   288                 elif xs.textColor!=xs.underlineColor:
   310                 LL = f.us_lines
   289                     xs.underlines.append( (xs.underline_x, end_x, xs.underlineColor) )
   311             if LL:
   290                     xs.underlineColor = xs.textColor
   312                 for l in LL:
   291                     xs.underline_x = cur_x_s
   313                     l0, fsmax = us_lines[l]
   292             if not xs.strike and f.strike:
   314                     if fontSize>fsmax:
   293                 xs.strike = 1
   315                         us_lines[l] = l0, fontSize
   294                 xs.strike_x = cur_x_s
   316 
   295                 xs.strikeColor = f.textColor
   317             nlo = rise - 0.2*fontSize
   296             elif xs.strike:
   318             nhi = rise + fontSize
   297                 if not f.strike:
   319             if AL != f.link:
   298                     xs.strike = 0
   320                 S = set(AL)
   299                     xs.strikes.append( (xs.strike_x, end_x, xs.strikeColor) )
   321                 NS = set(f.link)
   300                     xs.strikeColor = None
   322                 nL = NS - S #new linkis
   301                 elif xs.textColor!=xs.strikeColor:
   323                 eL = S - NS #ending links
   302                     xs.strikes.append( (xs.strike_x, end_x, xs.strikeColor) )
   324                 for l in eL:
   303                     xs.strikeColor = xs.textColor
   325                     links[l] = links[l],end_x
   304                     xs.strike_x = cur_x_s
   326                 for l in nL:
   305             if f.link and not xs.link:
   327                     links[l] = (l,cur_x),nlo,nhi
   306                 if not xs.link:
   328                 AL = f.link
   307                     xs.link = f.link
   329             if AL:
   308                     xs.link_x = cur_x_s
   330                 for l in AL:
   309                     xs.linkColor = xs.textColor
   331                     l0, lo, hi = links[l]
   310             elif xs.link:
   332                     if nlo<lo or nhi>hi:
   311                 if not f.link:
   333                         links[l] = l0,min(nlo,lo),max(nhi,hi)
   312                     xs.links.append( (xs.link_x, end_x, xs.link, xs.linkColor) )
   334 
   313                     xs.link = None
       
   314                     xs.linkColor = None
       
   315                 elif f.link!=xs.link or xs.textColor!=xs.linkColor:
       
   316                     xs.links.append( (xs.link_x, end_x, xs.link, xs.linkColor) )
       
   317                     xs.link = f.link
       
   318                     xs.link_x = cur_x_s
       
   319                     xs.linkColor = xs.textColor
       
   320             bg = getattr(f,'backColor',None)
   335             bg = getattr(f,'backColor',None)
   321             if bg and not xs.backColor:
   336             if bg and not xs.backColor:
   322                 xs.backColor = bg
   337                 xs.backColor = bg
   323                 xs.backColor_x = cur_x_s
   338                 xs.backColor_x = cur_x_s
   324             elif xs.backColor:
   339             elif xs.backColor:
   330                     xs.backColor = bg
   345                     xs.backColor = bg
   331                     xs.backColor_x = cur_x_s
   346                     xs.backColor_x = cur_x_s
   332             txtlen = tx._canvas.stringWidth(text, tx._fontname, tx._fontsize)
   347             txtlen = tx._canvas.stringWidth(text, tx._fontname, tx._fontsize)
   333             cur_x += txtlen
   348             cur_x += txtlen
   334             nSpaces += text.count(' ')+_nbspCount(text)
   349             nSpaces += text.count(' ')+_nbspCount(text)
       
   350 
   335     cur_x_s = cur_x+(nSpaces-1)*ws
   351     cur_x_s = cur_x+(nSpaces-1)*ws
   336     if last and pKind!='right' and xs.style.endDots:
   352     if last and pKind!='right' and xs.style.endDots:
   337         _do_dots_frag(cur_x,cur_x_s,line.maxWidth,xs,tx)
   353         _do_dots_frag(cur_x,cur_x_s,line.maxWidth,xs,tx)
   338     if xs.underline:
   354 
   339         xs.underlines.append( (xs.underline_x, cur_x_s, xs.underlineColor) )
   355     if LL:
   340     if xs.strike:
   356         for l in LL:
   341         xs.strikes.append( (xs.strike_x, cur_x_s, xs.strikeColor) )
   357             us_lines[l] = us_lines[l], cur_x_s
   342     if xs.link:
   358 
   343         xs.links.append( (xs.link_x, cur_x_s, xs.link,xs.linkColor) )
   359     if AL:
       
   360         for l in AL:
       
   361             links[l] = links[l], cur_x_s
       
   362 
   344     if xs.backColor:
   363     if xs.backColor:
   345         xs.backColors.append( (xs.backColor_x, cur_x_s, xs.backColor) )
   364         xs.backColors.append( (xs.backColor_x, cur_x_s, xs.backColor) )
   346     if tx._x0!=x0:
   365     if tx._x0!=x0:
   347         setXPos(tx,x0-tx._x0)
   366         setXPos(tx,x0-tx._x0)
   348 
   367 
   706 def _drawBullet(canvas, offset, cur_y, bulletText, style, rtl):
   725 def _drawBullet(canvas, offset, cur_y, bulletText, style, rtl):
   707     '''draw a bullet text could be a simple string or a frag list'''
   726     '''draw a bullet text could be a simple string or a frag list'''
   708     bulletAnchor = style.bulletAnchor
   727     bulletAnchor = style.bulletAnchor
   709     if rtl or style.bulletAnchor!='start':
   728     if rtl or style.bulletAnchor!='start':
   710         numeric = bulletAnchor=='numeric'
   729         numeric = bulletAnchor=='numeric'
   711         if isinstance(bulletText,strTypes):
   730         if isStr(bulletText):
   712             t =  bulletText
   731             t =  bulletText
   713             q = numeric and decimalSymbol in t
   732             q = numeric and decimalSymbol in t
   714             if q: t = t[:t.index(decimalSymbol)]
   733             if q: t = t[:t.index(decimalSymbol)]
   715             bulletWidth = stringWidth(t, style.bulletFontName, style.bulletFontSize)
   734             bulletWidth = stringWidth(t, style.bulletFontName, style.bulletFontSize)
   716             if q: bulletWidth += 0.5 * stringWidth(decimalSymbol, style.bulletFontName, style.bulletFontSize)
   735             if q: bulletWidth += 0.5 * stringWidth(decimalSymbol, style.bulletFontName, style.bulletFontSize)
   736         width = rtl[0]
   755         width = rtl[0]
   737         bulletStart = width+style.rightIndent-(style.bulletIndent+bulletWidth)
   756         bulletStart = width+style.rightIndent-(style.bulletIndent+bulletWidth)
   738         tx2 = canvas.beginText(bulletStart, cur_y)
   757         tx2 = canvas.beginText(bulletStart, cur_y)
   739     tx2.setFont(style.bulletFontName, style.bulletFontSize)
   758     tx2.setFont(style.bulletFontName, style.bulletFontSize)
   740     tx2.setFillColor(getattr(style,'bulletColor',style.textColor))
   759     tx2.setFillColor(getattr(style,'bulletColor',style.textColor))
   741     if isinstance(bulletText,strTypes):
   760     if isStr(bulletText):
   742         tx2.textOut(bulletText)
   761         tx2.textOut(bulletText)
   743     else:
   762     else:
   744         for f in bulletText:
   763         for f in bulletText:
   745             tx2.setFont(f.fontName, f.fontSize)
   764             tx2.setFont(f.fontName, f.fontSize)
   746             tx2.setFillColor(f.textColor)
   765             tx2.setFillColor(f.textColor)
   756 
   775 
   757 def _handleBulletWidth(bulletText,style,maxWidths):
   776 def _handleBulletWidth(bulletText,style,maxWidths):
   758     '''work out bullet width and adjust maxWidths[0] if neccessary
   777     '''work out bullet width and adjust maxWidths[0] if neccessary
   759     '''
   778     '''
   760     if bulletText:
   779     if bulletText:
   761         if isinstance(bulletText,strTypes):
   780         if isStr(bulletText):
   762             bulletWidth = stringWidth( bulletText, style.bulletFontName, style.bulletFontSize)
   781             bulletWidth = stringWidth( bulletText, style.bulletFontName, style.bulletFontSize)
   763         else:
   782         else:
   764             #it's a list of fragments
   783             #it's a list of fragments
   765             bulletWidth = 0
   784             bulletWidth = 0
   766             for f in bulletText:
   785             for f in bulletText:
   830                 g = (f,start,j)
   849                 g = (f,start,j)
   831                 line.append(g)
   850                 line.append(g)
   832             if j==lim:
   851             if j==lim:
   833                 i += 1
   852                 i += 1
   834 
   853 
   835 def _old_do_line(tx, x1, y1, x2, y2):
   854 def _do_line(tx, x1, y1, x2, y2, nlw, nsc):
   836     tx._canvas.line(x1, y1, x2, y2)
   855     canv = tx._canvas
   837 
   856     olw = canv._lineWidth
   838 def _do_line(tx, x1, y1, x2, y2):
       
   839     olw = tx._canvas._lineWidth
       
   840     nlw = tx._underlineProportion*tx._fontsize
       
   841     if nlw!=olw:
   857     if nlw!=olw:
   842         tx._canvas.setLineWidth(nlw)
   858         canv.setLineWidth(nlw)
   843         tx._canvas.line(x1, y1, x2, y2)
   859     osc = canv._strokeColorObj
   844         tx._canvas.setLineWidth(olw)
   860     if nsc!=osc:
   845     else:
   861         canv.setStrokeColor(nsc)
   846         tx._canvas.line(x1, y1, x2, y2)
   862     canv.line(x1, y1, x2, y2)
   847 
   863 
   848 def _do_under_line(i, t_off, ws, tx, lm=-0.125):
   864 def _do_under_line(i, x1, ws, tx, us_lines):
   849     y = tx.XtraState.cur_y - i*tx.XtraState.style.leading + lm*tx.XtraState.f.fontSize
   865     xs = tx.XtraState
   850     textlen = tx._canvas.stringWidth(' '.join(tx.XtraState.lines[i][1]), tx._fontname, tx._fontsize)
   866     style = xs.style
   851     tx._do_line(t_off, y, t_off+textlen, y)
   867     y0 = xs.cur_y - i*style.leading
       
   868     f = xs.f
       
   869     fs = f.fontSize
       
   870     tc = f.textColor
       
   871     values = dict(L=fs,F=fs,f=fs)
       
   872     dw = tx._defaultLineWidth
       
   873     x2 = x1 + tx._canvas.stringWidth(' '.join(tx.XtraState.lines[i][1]), tx._fontname, fs)
       
   874     for n,k,c,w,o,r,m,g in us_lines:
       
   875         underline = k=='underline'
       
   876         lw = _usConv(w,values,default=tx._defaultLineWidth)
       
   877         lg = _usConv(g,values,default=1)
       
   878         dy = lg+lw
       
   879         if not underline: dy = -dy
       
   880         y = y0 + r + _usConv(('-0.125*L' if underline else '0.25*L') if o=='' else o,values)
       
   881         if not c: c = tc
       
   882         while m>0:
       
   883             tx._do_line(x1, y, x2, y, lw, c)
       
   884             y -= dy
       
   885             m -= 1
   852 
   886 
   853 _scheme_re = re.compile('^[a-zA-Z][-+a-zA-Z0-9]+$')
   887 _scheme_re = re.compile('^[a-zA-Z][-+a-zA-Z0-9]+$')
   854 def _doLink(tx,link,rect):
   888 def _doLink(tx,link,rect):
   855     parts = link.split(':',1)
   889     parts = link.split(':',1)
   856     scheme = len(parts)==2 and parts[0].lower() or ''
   890     scheme = len(parts)==2 and parts[0].lower() or ''
   857     if _scheme_re.match(scheme) and scheme!='document':
   891     if _scheme_re.match(scheme) and scheme!='document':
   858         kind=scheme.lower()=='pdf' and 'GoToR' or 'URI'
   892         kind=scheme.lower()=='pdf' and 'GoToR' or 'URI'
   859         if kind=='GoToR': link = parts[1]
   893         if kind=='GoToR': link = parts[1]
   860         tx._canvas.linkURL(link, rect, relative=1, kind=kind)
   894         tx._canvas.linkURL(link, rect, relative=1, kind=kind)
   861     else:
   895     else:
       
   896         if not link: return
   862         if link[0]=='#':
   897         if link[0]=='#':
   863             link = link[1:]
   898             link = link[1:]
   864             scheme=''
   899             scheme=''
   865         tx._canvas.linkRect("", scheme!='document' and link or parts[1], rect, relative=1)
   900         tx._canvas.linkRect("", scheme!='document' and link or parts[1], rect, relative=1)
   866 
   901 
   868     xs = tx.XtraState
   903     xs = tx.XtraState
   869     leading = xs.style.leading
   904     leading = xs.style.leading
   870     y = xs.cur_y - i*leading - xs.f.fontSize/8.0 # 8.0 factor copied from para.py
   905     y = xs.cur_y - i*leading - xs.f.fontSize/8.0 # 8.0 factor copied from para.py
   871     text = ' '.join(xs.lines[i][1])
   906     text = ' '.join(xs.lines[i][1])
   872     textlen = tx._canvas.stringWidth(text, tx._fontname, tx._fontsize)
   907     textlen = tx._canvas.stringWidth(text, tx._fontname, tx._fontsize)
   873     _doLink(tx, xs.link, (t_off, y, t_off+textlen, y+leading))
   908     for n, link in xs.link:
       
   909         _doLink(tx, link, (t_off, y, t_off+textlen, y+leading))
   874 
   910 
   875 def _do_post_text(tx):
   911 def _do_post_text(tx):
   876     xs = tx.XtraState
   912     xs = tx.XtraState
       
   913     y0 = xs.cur_y
       
   914     f = xs.f
   877     leading = xs.style.leading
   915     leading = xs.style.leading
   878     autoLeading = xs.autoLeading
   916     autoLeading = xs.autoLeading
   879     y0 = xs.cur_y
   917     fontSize = f.fontSize
   880     f = xs.f
       
   881     ff = 0.125*f.fontSize
       
   882     yl = y0 + f.fontSize
       
   883     if autoLeading=='max':
   918     if autoLeading=='max':
   884         leading = max(leading,1.2*f.fontSize)
   919         leading = max(leading,1.2*fontSize)
   885     elif autoLeading=='min':
   920     elif autoLeading=='min':
   886         leading = 1.2*f.fontSize
   921         leading = 1.2*fontSize
   887     ydesc = yl - leading
   922 
   888 
   923     if xs.backColors:
   889     for x1,x2,c in xs.backColors:
   924         yl = y0 + fontSize
   890         tx._canvas.setFillColor(c)
   925         ydesc = yl - leading
   891         tx._canvas.rect(x1,ydesc,x2-x1,leading,stroke=0,fill=1)
   926 
   892     xs.backColors=[]
   927         for x1,x2,c in xs.backColors:
   893     xs.backColor=None
   928             tx._canvas.setFillColor(c)
   894 
   929             tx._canvas.rect(x1,ydesc,x2-x1,leading,stroke=0,fill=1)
   895     y = y0 - ff
   930         xs.backColors=[]
   896     csc = None
   931         xs.backColor=None
   897     for x1,x2,c in xs.underlines:
   932 
   898         if c!=csc:
   933     for (((n,link),x1),lo,hi),x2 in sorted(xs.links.values()):
   899             tx._canvas.setStrokeColor(c)
   934         _doLink(tx, link, (x1, y0+lo, x2, y0+hi))
   900             csc = c
   935     xs.links = {}
   901         tx._do_line(x1, y, x2, y)
   936 
   902     xs.underlines = []
   937     if xs.us_lines:
   903     xs.underline=0
   938         #print 'lines'
   904     xs.underlineColor=None
   939         dw = tx._defaultLineWidth
   905 
   940         values = dict(L=fontSize)
   906     ys = y0 + 2*ff
   941         for (((n,k,c,w,o,r,m,g),fs,tc,x1),fsmax),x2 in sorted(xs.us_lines.values()):
   907     for x1,x2,c in xs.strikes:
   942             underline = k=='underline'
   908         if c!=csc:
   943             values['f'] = fs
   909             tx._canvas.setStrokeColor(c)
   944             values['F'] = fsmax
   910             csc = c
   945             lw = _usConv(w,values,default=tx._defaultLineWidth)
   911         tx._do_line(x1, ys, x2, ys)
   946             lg = _usConv(g,values,default=1)
   912     xs.strikes = []
   947             dy = lg+lw
   913     xs.strike=0
   948             if not underline: dy = -dy
   914     xs.strikeColor=None
   949             y = y0 + r + _usConv(o if o!='' else ('-0.125*L' if underline else '0.25*L'),values)
   915 
   950             #print 'n=%s k=%s x1=%s x2=%s r=%s c=%s w=%r o=%r fs=%r tc=%s y=%s lW=%r offs=%r' % (n,k,x1,x2,r,(c.hexval() if c else ''),w,o,fs,tc.hexval(),y,lW,y-y0-r)
   916     for x1,x2,link,c in xs.links:
   951             if not c: c = tc
   917         if platypus_link_underline:
   952             while m>0:
   918             if c!=csc:
   953                 tx._do_line(x1, y, x2, y, lw, c)
   919                 tx._canvas.setStrokeColor(c)
   954                 y -= dy
   920                 csc = c
   955                 m -= 1
   921             tx._do_line(x1, y, x2, y)
   956         xs.us_lines = {}
   922         _doLink(tx, link, (x1, ydesc, x2, yl))
       
   923     xs.links = []
       
   924     xs.link=None
       
   925     xs.linkColor=None
       
   926 
   957 
   927     xs.cur_y -= leading
   958     xs.cur_y -= leading
   928 
   959 
   929 def textTransformFrags(frags,style):
   960 def textTransformFrags(frags,style):
   930     tt = style.textTransform
   961     tt = style.textTransform
  1100         This class is a flowable that can format a block of text
  1131         This class is a flowable that can format a block of text
  1101         into a paragraph with a given style.
  1132         into a paragraph with a given style.
  1102 
  1133 
  1103         The paragraph Text can contain XML-like markup including the tags:
  1134         The paragraph Text can contain XML-like markup including the tags:
  1104         <b> ... </b> - bold
  1135         <b> ... </b> - bold
       
  1136         < u [color="red"] [width="pts"] [offset="pts"]> < /u > - underline
       
  1137             width and offset can be empty meaning use existing canvas line width
       
  1138             or with an f/F suffix regarded as a fraction of the font size
       
  1139         < strike > < /strike > - strike through has the same parameters as underline
  1105         <i> ... </i> - italics
  1140         <i> ... </i> - italics
  1106         <u> ... </u> - underline
  1141         <u> ... </u> - underline
  1107         <strike> ... </strike> - strike through
  1142         <strike> ... </strike> - strike through
  1108         <super> ... </super> - superscript
  1143         <super> ... </super> - superscript
  1109         <sub> ... </sub> - subscript
  1144         <sub> ... </sub> - subscript
  1110         <font name=fontfamily/fontname color=colorname size=float>
  1145         <font name=fontfamily/fontname color=colorname size=float>
  1111         <span name=fontfamily/fontname color=colorname backcolor=colorname size=float style=stylename>
  1146         <span name=fontfamily/fontname color=colorname backcolor=colorname size=float style=stylename>
  1112         <onDraw name=callable label="a label"/>
  1147         <onDraw name=callable label="a label"/>
  1113         <index [name="callablecanvasattribute"] label="a label"/>
  1148         <index [name="callablecanvasattribute"] label="a label"/>
  1114         <link>link text</link>
  1149         <link>link text</link>
  1115         attributes of links
  1150             attributes of links
  1116         size/fontSize=num
  1151                 size/fontSize/uwidth/uoffset=num
  1117         name/face/fontName=name
  1152                 name/face/fontName=name
  1118         fg/textColor/color=color
  1153                 fg/textColor/color/ucolor=color
  1119         backcolor/backColor/bgcolor=color
  1154                 backcolor/backColor/bgcolor=color
  1120         dest/destination/target/href/link=target
  1155                 dest/destination/target/href/link=target
       
  1156                 underline=bool turn on underline
  1121         <a>anchor text</a>
  1157         <a>anchor text</a>
  1122         attributes of anchors
  1158             attributes of anchors
  1123         fontSize=num
  1159                 size/fontSize/uwidth/uoffset=num
  1124         fontName=name
  1160                 fontName=name
  1125         fg/textColor/color=color
  1161                 fg/textColor/color/ucolor=color
  1126         backcolor/backColor/bgcolor=color
  1162                 backcolor/backColor/bgcolor=color
  1127         href=href
  1163                 href=href
       
  1164                 underline="yes|no"
  1128         <a name="anchorpoint"/>
  1165         <a name="anchorpoint"/>
  1129         <unichar name="unicode character name"/>
  1166         <unichar name="unicode character name"/>
  1130         <unichar value="unicode code point"/>
  1167         <unichar value="unicode code point"/>
  1131         <img src="path" width="1in" height="1in" valign="bottom"/>
  1168         <img src="path" width="1in" height="1in" valign="bottom"/>
  1132                 width="w%" --> fontSize*w/100   idea from Roberto Alsina
  1169                 width="w%" --> fontSize*w/100   idea from Roberto Alsina
  1742 
  1779 
  1743                 #set up the font etc.
  1780                 #set up the font etc.
  1744                 canvas.setFillColor(f.textColor)
  1781                 canvas.setFillColor(f.textColor)
  1745 
  1782 
  1746                 tx = self.beginText(cur_x, cur_y)
  1783                 tx = self.beginText(cur_x, cur_y)
  1747                 if style.underlineProportion:
       
  1748                     tx._underlineProportion = style.underlineProportion
       
  1749                     tx._do_line = _do_line
       
  1750                 else:
       
  1751                     tx._do_line = _old_do_line
       
  1752                 tx._do_line = MethodType(tx._do_line,tx)
       
  1753                 if autoLeading=='max':
  1784                 if autoLeading=='max':
  1754                     leading = max(leading,blPara.ascent-blPara.descent)
  1785                     leading = max(leading,blPara.ascent-blPara.descent)
  1755                 elif autoLeading=='min':
  1786                 elif autoLeading=='min':
  1756                     leading = blPara.ascent-blPara.descent
  1787                     leading = blPara.ascent-blPara.descent
  1757 
  1788 
  1764                 words = lines[0][1]
  1795                 words = lines[0][1]
  1765                 lastLine = noJustifyLast and nLines==1
  1796                 lastLine = noJustifyLast and nLines==1
  1766                 if lastLine and jllwc and len(words)>jllwc:
  1797                 if lastLine and jllwc and len(words)>jllwc:
  1767                     lastLine=False
  1798                     lastLine=False
  1768                 t_off = dpl( tx, offset, ws, words, lastLine)
  1799                 t_off = dpl( tx, offset, ws, words, lastLine)
  1769                 if f.underline or f.link or f.strike or style.endDots:
  1800                 if f.us_lines or f.link or style.endDots:
  1770                     xs = tx.XtraState = ABag()
  1801                     tx._do_line = MethodType(_do_line,tx)
       
  1802                     tx.xs = xs = tx.XtraState = ABag()
       
  1803                     tx._defaultLineWidth = canvas._lineWidth
  1771                     xs.cur_y = cur_y
  1804                     xs.cur_y = cur_y
  1772                     xs.f = f
  1805                     xs.f = f
  1773                     xs.style = style
  1806                     xs.style = style
  1774                     xs.lines = lines
  1807                     xs.lines = lines
  1775                     xs.underlines=[]
       
  1776                     xs.underlineColor=None
       
  1777                     xs.strikes=[]
       
  1778                     xs.strikeColor=None
       
  1779                     xs.links=[]
       
  1780                     xs.link=f.link
  1808                     xs.link=f.link
  1781                     xs.textColor = f.textColor
  1809                     xs.textColor = f.textColor
  1782                     xs.backColors = []
  1810                     xs.backColors = []
  1783                     canvas.setStrokeColor(f.textColor)
       
  1784                     dx = t_off+leftIndent
  1811                     dx = t_off+leftIndent
  1785                     if dpl!=_justifyDrawParaLine: ws = 0
  1812                     if dpl!=_justifyDrawParaLine: ws = 0
  1786                     underline = f.underline or (f.link and platypus_link_underline)
  1813                     if f.us_lines:
  1787                     strike = f.strike
  1814                         _do_under_line(0, t_off, ws, tx, f.us_lines)
  1788                     link = f.link
  1815                     if f.link: _do_link_line(0, dx, ws, tx)
  1789                     if underline: _do_under_line(0, dx, ws, tx)
       
  1790                     if strike: _do_under_line(0, dx, ws, tx, lm=0.125)
       
  1791                     if link: _do_link_line(0, dx, ws, tx)
       
  1792                     if lastLine and style.endDots and dpl!=_rightDrawParaLine: _do_dots(0, dx, ws, xs, tx, dpl)
  1816                     if lastLine and style.endDots and dpl!=_rightDrawParaLine: _do_dots(0, dx, ws, xs, tx, dpl)
  1793 
  1817 
  1794                     #now the middle of the paragraph, aligned with the left margin which is our origin.
  1818                     #now the middle of the paragraph, aligned with the left margin which is our origin.
  1795                     for i in xrange(1, nLines):
  1819                     for i in xrange(1, nLines):
  1796                         ws = lines[i][0]
  1820                         ws = lines[i][0]
  1799                         if lastLine and jllwc and len(words)>jllwc:
  1823                         if lastLine and jllwc and len(words)>jllwc:
  1800                             lastLine=False
  1824                             lastLine=False
  1801                         t_off = dpl( tx, _offsets[i], ws, words, lastLine)
  1825                         t_off = dpl( tx, _offsets[i], ws, words, lastLine)
  1802                         dx = t_off+leftIndent
  1826                         dx = t_off+leftIndent
  1803                         if dpl!=_justifyDrawParaLine: ws = 0
  1827                         if dpl!=_justifyDrawParaLine: ws = 0
  1804                         if underline: _do_under_line(i, dx, ws, tx)
  1828                         if f.us_lines:
  1805                         if strike: _do_under_line(i, dx, ws, tx, lm=0.125)
  1829                             _do_under_line(i, t_off, ws, tx, f.us_lines)
  1806                         if link: _do_link_line(i, dx, ws, tx)
  1830                         if f.link: _do_link_line(i, dx, ws, tx)
  1807                         if lastLine and style.endDots and dpl!=_rightDrawParaLine: _do_dots(i, dx, ws, xs, tx, dpl)
  1831                         if lastLine and style.endDots and dpl!=_rightDrawParaLine: _do_dots(i, dx, ws, xs, tx, dpl)
  1808                 else:
  1832                 else:
  1809                     for i in xrange(1, nLines):
  1833                     for i in xrange(1, nLines):
  1810                         words = lines[i][1]
  1834                         words = lines[i][1]
  1811                         lastLine = noJustifyLast and i==lim
  1835                         lastLine = noJustifyLast and i==lim
  1837                 else:
  1861                 else:
  1838                     raise ValueError("bad align %s" % repr(alignment))
  1862                     raise ValueError("bad align %s" % repr(alignment))
  1839 
  1863 
  1840                 #set up the font etc.
  1864                 #set up the font etc.
  1841                 tx = self.beginText(cur_x, cur_y)
  1865                 tx = self.beginText(cur_x, cur_y)
  1842                 if style.underlineProportion:
  1866                 tx._defaultLineWidth = canvas._lineWidth
  1843                     tx._underlineProportion = style.underlineProportion
  1867                 tx._underlineWidth = getattr(style,'underlineWidth','')
  1844                     tx._do_line = _do_line
  1868                 tx._underlineOffset = getattr(style,'underlineOffset','') or '-0.125f'
  1845                 else:
  1869                 tx._strikeWidth = getattr(style,'strikeWidth','')
  1846                     tx._do_line = _old_do_line
  1870                 tx._strikeOffset = getattr(style,'strikeOffset','') or '0.25f'
  1847                 tx._do_line = MethodType(tx._do_line,tx)
  1871                 tx._do_line = MethodType(_do_line,tx)
  1848                 # set the paragraph direction
  1872                 # set the paragraph direction
  1849                 tx.direction = self.style.wordWrap
  1873                 tx.direction = self.style.wordWrap
  1850 
  1874 
  1851                 xs = tx.XtraState=ABag()
  1875                 xs = tx.XtraState=ABag()
  1852                 xs.textColor=None
  1876                 xs.textColor=None
  1853                 xs.backColor=None
  1877                 xs.backColor=None
  1854                 xs.rise=0
  1878                 xs.rise=0
  1855                 xs.underline=0
       
  1856                 xs.underlines=[]
       
  1857                 xs.underlineColor=None
       
  1858                 xs.strike=0
       
  1859                 xs.strikes=[]
       
  1860                 xs.strikeColor=None
       
  1861                 xs.backColors=[]
  1879                 xs.backColors=[]
  1862                 xs.links=[]
  1880                 xs.us_lines = {}
  1863                 xs.link=None
  1881                 xs.links = {}
       
  1882                 xs.link={}
  1864                 xs.leading = style.leading
  1883                 xs.leading = style.leading
  1865                 xs.leftIndent = leftIndent
  1884                 xs.leftIndent = leftIndent
  1866                 tx._leading = None
  1885                 tx._leading = None
  1867                 tx._olb = None
  1886                 tx._olb = None
  1868                 xs.cur_y = cur_y
  1887                 xs.cur_y = cur_y