src/reportlab/platypus/paraparser.py
changeset 4389 61a7f0840d00
parent 4370 823a8c33ce43
child 4410 bd848827483f
equal deleted inserted replaced
4388:9f93d62b9f6e 4389:61a7f0840d00
    18 from reportlab.lib.utils import ImageReader, isPy3, annotateException, encode_label, asUnicode, asBytes, uniChr, isStr
    18 from reportlab.lib.utils import ImageReader, isPy3, annotateException, encode_label, asUnicode, asBytes, uniChr, isStr
    19 from reportlab.lib.colors import toColor, white, black, red, Color
    19 from reportlab.lib.colors import toColor, white, black, red, Color
    20 from reportlab.lib.fonts import tt2ps, ps2tt
    20 from reportlab.lib.fonts import tt2ps, ps2tt
    21 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
    21 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
    22 from reportlab.lib.units import inch,mm,cm,pica
    22 from reportlab.lib.units import inch,mm,cm,pica
       
    23 from reportlab.rl_config import platypus_link_underline
    23 if isPy3:
    24 if isPy3:
    24     from html.parser import HTMLParser
    25     from html.parser import HTMLParser
    25     from html.entities import name2codepoint
    26     from html.entities import name2codepoint
    26 else:
    27 else:
    27     from HTMLParser import HTMLParser
    28     from HTMLParser import HTMLParser
    45         try:
    46         try:
    46             return int(s)*unit
    47             return int(s)*unit
    47         except ValueError:
    48         except ValueError:
    48             return float(s)*unit
    49             return float(s)*unit
    49 
    50 
    50 def _num(s, unit=1, allowRelative=True):
    51 def _num(s, unit=1, allowRelative=True,
       
    52         _unit_map = {'i':inch,'in':inch,'pt':1,'cm':cm,'mm':mm,'pica':pica },
       
    53         _re_unit = re.compile('^\s*(.*)(i|in|cm|mm|pt|pica)\s*$'),
       
    54         ):
    51     """Convert a string like '10cm' to an int or float (in points).
    55     """Convert a string like '10cm' to an int or float (in points).
    52        The default unit is point, but optionally you can use other
    56        The default unit is point, but optionally you can use other
    53        default units like mm.
    57        default units like mm.
    54     """
    58     """
    55     if s.endswith('cm'):
    59     m = _re_unit.match(s)
    56         unit=cm
    60     if m:
    57         s = s[:-2]
    61         unit = _unit_map[m.group(2)]
    58     if s.endswith('in'):
    62         s = m.group(1)
    59         unit=inch
       
    60         s = s[:-2]
       
    61     if s.endswith('pt'):
       
    62         unit=1
       
    63         s = s[:-2]
       
    64     if s.endswith('i'):
       
    65         unit=inch
       
    66         s = s[:-1]
       
    67     if s.endswith('mm'):
       
    68         unit=mm
       
    69         s = s[:-2]
       
    70     if s.endswith('pica'):
       
    71         unit=pica
       
    72         s = s[:-4]
       
    73     return _convnum(s,unit,allowRelative)
    63     return _convnum(s,unit,allowRelative)
    74 
    64 
    75 def _int(s):
    65 def _int(s):
    76     try:
    66     try:
    77         return int(s)
    67         return int(s)
   110 def fontSizeNormalize(frag,attr,default):
   100 def fontSizeNormalize(frag,attr,default):
   111     if not hasattr(frag,attr): return default
   101     if not hasattr(frag,attr): return default
   112     v = _numpct(getattr(frag,attr),allowRelative=True)
   102     v = _numpct(getattr(frag,attr),allowRelative=True)
   113     return (v[1]+frag.fontSize) if isinstance(v,tuple) else v.normalizedValue(frag.fontSize) if isinstance(v,_PCT) else v
   103     return (v[1]+frag.fontSize) if isinstance(v,tuple) else v.normalizedValue(frag.fontSize) if isinstance(v,_PCT) else v
   114 
   104 
   115 class _CheckSup:
   105 class _ExValidate:
   116     '''class for syntax checking <sup> attributes
   106     '''class for syntax checking attributes
   117     if the check succeeds then we always return the string for later evaluation
       
   118     '''
   107     '''
   119     def __init__(self,kind):
   108     def __init__(self,tag,attr):
   120         self.kind = kind
   109         self.tag = tag
   121         self.fontSize = 10
   110         self.attr = attr
   122 
   111 
   123     def __call__(self,s):
   112     def invalid(self,s):
   124         setattr(self,self.kind,s)
   113         raise ValueError('<%s> invalid value %r for attribute %s' % (self.tag,s,self.attr))
       
   114 
       
   115     def validate(self, parser,s):
       
   116         raise ValueError('abstract method called')
       
   117         return s
       
   118 
       
   119     def __call__(self, parser, s):
   125         try:
   120         try:
   126             fontSizeNormalize(self,self.kind,None)
   121             return self.validate(parser, s)
   127             return s
       
   128         except:
   122         except:
   129             raise ValueError('<sup> invalid value %r for attribute %s' % (s,self.kind))
   123             self.invalid(s)
       
   124 
       
   125 class _CheckSup(_ExValidate):
       
   126     '''class for syntax checking <sup|sub> attributes
       
   127     if the check succeeds then we always return the string for later evaluation'''
       
   128     def validate(self,parser,s):
       
   129         self.fontSize = parser._stack[-1].fontSize
       
   130         fontSizeNormalize(self,self.attr,'')
       
   131         return s
       
   132 
       
   133     def __call__(self, parser, s):
       
   134         setattr(self,self.attr,s)
       
   135         return _ExValidate.__call__(self,parser,s)
       
   136 
       
   137 _lineRepeats = dict(single=1,double=2,triple=3)
       
   138 _re_us_value = re.compile(r'^\s*(.*)\s*\*\s*(P|L|f|F)\s*$')
       
   139 class _CheckUS(_ExValidate):
       
   140     '''class for syntax checking <u|strike> width/offset attributes'''
       
   141     def validate(self,parser,s):
       
   142         s = s.strip()
       
   143         if s:
       
   144             m = _re_us_value.match(s)
       
   145             if m:
       
   146                 v = float(m.group(1))
       
   147                 if m.group(2)=='P':
       
   148                     return parser._stack[0].fontSize*v
       
   149             else:
       
   150                 _num(s,allowRelative=False)
       
   151         return s
   130 
   152 
   131 def _valignpc(s):
   153 def _valignpc(s):
   132     s = s.lower()
   154     s = s.lower()
   133     if s in ('baseline','sub','super','top','text-top','middle','bottom','text-bottom'):
   155     if s in ('baseline','sub','super','top','text-top','middle','bottom','text-bottom'):
   134         return s
   156         return s
   209                 'borderpadding': ('borderpadding',_num),
   231                 'borderpadding': ('borderpadding',_num),
   210                 'bordercolor': ('borderColor',toColor),
   232                 'bordercolor': ('borderColor',toColor),
   211                 'borderradius': ('borderRadius',_num),
   233                 'borderradius': ('borderRadius',_num),
   212                 'texttransform':('textTransform',_textTransformConv),
   234                 'texttransform':('textTransform',_textTransformConv),
   213                 'enddots':('endDots',None),
   235                 'enddots':('endDots',None),
   214                 'underlineproportion':('underlineProportion',_num),
   236                 'underlinewidth':('underlineWidth',_CheckUS('para','underlineWidth')),
       
   237                 'underlinecolor':('underlineColor',toColor),
       
   238                 'underlineoffset':('underlineOffset',_CheckUS('para','underlineOffset')),
       
   239                 'underlinegap':('underlineGap',_CheckUS('para','underlineGap')),
       
   240                 'strikewidth':('strikeWidth',_CheckUS('para','strikeWidth')),
       
   241                 'strikecolor':('strikeColor',toColor),
       
   242                 'strikeoffset':('strikeOffset',_CheckUS('para','strikeOffset')),
       
   243                 'strikegap':('strikeGap',_CheckUS('para','strikeGap')),
   215                 'spaceshrinkage':('spaceShrinkage',_num),
   244                 'spaceshrinkage':('spaceShrinkage',_num),
   216                 }
   245                 }
   217 
   246 
   218 _bulletAttrMap = {
   247 _bulletAttrMap = {
   219                 'font': ('bulletFontName', None),
   248                 'font': ('bulletFontName', None),
   256                 'bgcolor':('backColor',toColor),
   285                 'bgcolor':('backColor',toColor),
   257                 'dest': ('link', None),
   286                 'dest': ('link', None),
   258                 'destination': ('link', None),
   287                 'destination': ('link', None),
   259                 'target': ('link', None),
   288                 'target': ('link', None),
   260                 'href': ('link', None),
   289                 'href': ('link', None),
       
   290                 'ucolor': ('underlineColor', toColor),
       
   291                 'uoffset': ('underlineOffset', _CheckUS('link','underlineOffset')),
       
   292                 'uwidth': ('underlineWidth', _CheckUS('link','underlineWidth')),
       
   293                 'ugap': ('underlineGap', _CheckUS('link','underlineGap')),
       
   294                 'underline': ('underline',_bool),
       
   295                 'ukind': ('underlineKind',None),
   261                 }
   296                 }
   262 _anchorAttrMap = {'fontSize': ('fontSize', _num),
   297 _anchorAttrMap = {
   263                 'fontName': ('fontName', None),
       
   264                 'name': ('name', None),
   298                 'name': ('name', None),
   265                 'fg':   ('textColor', toColor),
       
   266                 'color':('textColor', toColor),
       
   267                 'backcolor':('backColor',toColor),
       
   268                 'bgcolor':('backColor',toColor),
       
   269                 'href': ('href', None),
       
   270                 }
   299                 }
   271 _imgAttrMap = {
   300 _imgAttrMap = {
   272                 'src': ('src', None),
   301                 'src': ('src', None),
   273                 'width': ('width',_numpct),
   302                 'width': ('width',_numpct),
   274                 'height':('height',_numpct),
   303                 'height':('height',_numpct),
   279                 'item': ('item',None),
   308                 'item': ('item',None),
   280                 'offset': ('offset',None),
   309                 'offset': ('offset',None),
   281                 'format': ('format',None),
   310                 'format': ('format',None),
   282                 }
   311                 }
   283 _supAttrMap = {
   312 _supAttrMap = {
   284                 'rise': ('supr', _CheckSup('rise')),
   313                 'rise': ('supr', _CheckSup('sup|sub','rise')),
   285                 'size': ('sups', _CheckSup('size')),
   314                 'size': ('sups', _CheckSup('sup|sub','size')),
   286                 }
   315                 }
       
   316 _uAttrMap = {
       
   317             'color':('underlineColor', toColor),
       
   318             'width':('underlineWidth', _CheckUS('underline','underlineWidth')),
       
   319             'offset':('underlineOffset', _CheckUS('underline','underlineOffset')),
       
   320             'gap':('underlineGap', _CheckUS('underline','underlineGap')),
       
   321             'kind':('underlineKind',None),
       
   322             }
       
   323 _strikeAttrMap = {
       
   324             'color':('strikeColor', toColor),
       
   325             'width':('strikeWidth', _CheckUS('strike','strikeWidth')),
       
   326             'offset':('strikeOffset', _CheckUS('strike','strikeOffset')),
       
   327             'gap':('strikeGap', _CheckUS('strike','strikeGap')),
       
   328             'kind':('strikeKind',None),
       
   329             }
   287 
   330 
   288 def _addAttributeNames(m):
   331 def _addAttributeNames(m):
   289     K = list(m.keys())
   332     K = list(m.keys())
   290     for k in K:
   333     for k in K:
   291         n = m[k][0]
   334         n = m[k][0]
   611 # !!! NOTE !!! THIS TEXT IS NOW REPLICATED IN PARAGRAPH.PY !!!
   654 # !!! NOTE !!! THIS TEXT IS NOW REPLICATED IN PARAGRAPH.PY !!!
   612 # The ParaFormatter will be able to format the following
   655 # The ParaFormatter will be able to format the following
   613 # tags:
   656 # tags:
   614 #       < /b > - bold
   657 #       < /b > - bold
   615 #       < /i > - italics
   658 #       < /i > - italics
   616 #       < u > < /u > - underline
   659 #       < u [color="red"] [width="pts"] [offset="pts"]> < /u > - underline
   617 #       < strike > < /strike > - strike through
   660 #           width and offset can be empty meaning use existing canvas line width
       
   661 #           or with an f/F suffix regarded as a fraction of the font size
       
   662 #       < strike > < /strike > - strike through has the same parameters as underline
   618 #       < super [size="pts"] [rise="pts"]> < /super > - superscript
   663 #       < super [size="pts"] [rise="pts"]> < /super > - superscript
   619 #       < sup ="pts"] [rise="pts"]> < /sup > - superscript
   664 #       < sup ="pts"] [rise="pts"]> < /sup > - superscript
   620 #       < sub ="pts"] [rise="pts"]> < /sub > - subscript
   665 #       < sub ="pts"] [rise="pts"]> < /sub > - subscript
   621 #       <font name=fontfamily/fontname color=colorname size=float>
   666 #       <font name=fontfamily/fontname color=colorname size=float>
   622 #        <span name=fontfamily/fontname color=colorname backcolor=colorname size=float style=stylename>
   667 #        <span name=fontfamily/fontname color=colorname backcolor=colorname size=float style=stylename>
   623 #       < bullet > </bullet> - bullet text (at head of para only)
   668 #       < bullet > </bullet> - bullet text (at head of para only)
   624 #       <onDraw name=callable label="a label"/>
   669 #       <onDraw name=callable label="a label"/>
   625 #       <index [name="callablecanvasattribute"] label="a label"/>
   670 #       <index [name="callablecanvasattribute"] label="a label"/>
   626 #       <link>link text</link>
   671 #       <link>link text</link>
   627 #           attributes of links 
   672 #           attributes of links
   628 #               size/fontSize=num
   673 #               size/fontSize/uwidth/uoffset=num
   629 #               name/face/fontName=name
   674 #               name/face/fontName=name
   630 #               fg/textColor/color=color
   675 #               fg/textColor/color/ucolor=color
   631 #               backcolor/backColor/bgcolor=color
   676 #               backcolor/backColor/bgcolor=color
   632 #               dest/destination/target/href/link=target
   677 #               dest/destination/target/href/link=target
       
   678 #               underline=bool turn on underline
   633 #       <a>anchor text</a>
   679 #       <a>anchor text</a>
   634 #           attributes of anchors 
   680 #           attributes of anchors
   635 #               fontSize=num
   681 #               fontSize=num
   636 #               fontName=name
   682 #               fontName=name
   637 #               fg/textColor/color=color
   683 #               fg/textColor/color=color
   638 #               backcolor/backColor/bgcolor=color
   684 #               backcolor/backColor/bgcolor=color
   639 #               href=href
   685 #               href=href
   696         self._push('em', italic=1)
   742         self._push('em', italic=1)
   697 
   743 
   698     def end_em( self ):
   744     def end_em( self ):
   699         self._pop('em')
   745         self._pop('em')
   700 
   746 
       
   747     def _new_line(self,k):
       
   748         frag = self._stack[-1]
       
   749         frag.us_lines = frag.us_lines + [(
       
   750                     self.nlines,
       
   751                     k,
       
   752                     getattr(frag,k+'Color',None),
       
   753                     getattr(frag,k+'Width',self._defaultLineWidths[k]),
       
   754                     getattr(frag,k+'Offset',self._defaultLineOffsets[k]),
       
   755                     frag.rise,
       
   756                     _lineRepeats[getattr(frag,k+'Kind','single')],
       
   757                     getattr(frag,k+'Gap',self._defaultLineGaps[k]),
       
   758                     )]
       
   759         self.nlines += 1
       
   760 
   701     #### underline
   761     #### underline
   702     def start_u( self, attributes ):
   762     def start_u( self, attributes ):
   703         self._push('u',underline=1)
   763         A = self.getAttributes(attributes,_uAttrMap)
       
   764         self._push('u',**A)
       
   765         self._new_line('underline')
   704 
   766 
   705     def end_u( self ):
   767     def end_u( self ):
   706         self._pop('u')
   768         self._pop('u')
   707 
   769 
   708     #### strike
   770     #### strike
   709     def start_strike( self, attributes ):
   771     def start_strike( self, attributes ):
   710         self._push('strike',strike=1)
   772         A = self.getAttributes(attributes,_strikeAttrMap)
       
   773         self._push('strike',strike=1,**A)
       
   774         self._new_line('strike')
   711 
   775 
   712     def end_strike( self ):
   776     def end_strike( self ):
   713         self._pop('strike')
   777         self._pop('strike')
   714 
   778 
   715     #### link
   779     #### link
   716     def start_link(self, attributes):
   780     def _handle_link(self, tag, attributes):
   717         self._push('link',**self.getAttributes(attributes,_linkAttrMap))
   781         A = self.getAttributes(attributes,_linkAttrMap)
       
   782         underline = A.pop('underline',self._defaultLinkUnderline)
       
   783         A['link'] = self._stack[-1].link + [(
       
   784                         self.nlinks,
       
   785                         A.pop('link','').strip(),
       
   786                         )]
       
   787         self.nlinks += 1
       
   788         self._push(tag,**A)
       
   789         if underline:
       
   790             self._new_line('underline')
       
   791 
       
   792     def start_link(self,attributes):
       
   793         self._handle_link('link',attributes)
   718 
   794 
   719     def end_link(self):
   795     def end_link(self):
   720         if self._pop('link').link is None:
   796         if self._pop('link').link is None:
   721             raise ValueError('<link> has no target or href')
   797             raise ValueError('<link> has no target or href')
   722 
   798 
   723     #### anchor
   799     #### anchor
   724     def start_a(self, attributes):
   800     def start_a(self, attributes):
   725         A = self.getAttributes(attributes,_anchorAttrMap)
   801         anchor = 'name' in attributes
   726         name = A.get('name',None)
   802         if anchor:
   727         if name is not None:
   803             A = self.getAttributes(attributes,_anchorAttrMap)
       
   804             name = A.get('name',None)
   728             name = name.strip()
   805             name = name.strip()
   729             if not name:
   806             if not name:
   730                 self._syntax_error('<a name="..."/> anchor variant requires non-blank name')
   807                 self._syntax_error('<a name="..."/> anchor variant requires non-blank name')
   731             if len(A)>1:
   808             if len(A)>1:
   732                 self._syntax_error('<a name="..."/> anchor variant only allows name attribute')
   809                 self._syntax_error('<a name="..."/> anchor variant only allows name attribute')
   733                 A = dict(name=A['name'])
   810                 A = dict(name=A['name'])
   734             A['_selfClosingTag'] = 'anchor'
   811             A['_selfClosingTag'] = 'anchor'
       
   812             self._push('a',**A)
   735         else:
   813         else:
   736             href = A.get('href','').strip()
   814             self._handle_link('a',attributes)
   737             A['link'] = href    #convert to our link form
       
   738             A.pop('href',None)
       
   739         self._push('a',**A)
       
   740 
   815 
   741     def end_a(self):
   816     def end_a(self):
   742         frag = self._stack[-1]
   817         frag = self._stack[-1]
   743         sct = getattr(frag,'_selfClosingTag','')
   818         sct = getattr(frag,'_selfClosingTag','')
   744         if sct:
   819         if sct:
   778         self._pop('img')
   853         self._pop('img')
   779 
   854 
   780     #### super script
   855     #### super script
   781     def start_super( self, attributes ):
   856     def start_super( self, attributes ):
   782         A = self.getAttributes(attributes,_supAttrMap)
   857         A = self.getAttributes(attributes,_supAttrMap)
   783         A['sup']=1
   858         #A['sup']=1
   784         self._push('super',**A)
   859         self._push('super',**A)
       
   860         frag = self._stack[-1]
       
   861         frag.rise += fontSizeNormalize(frag,'supr',frag.fontSize*supFraction)
       
   862         frag.fontSize = fontSizeNormalize(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
   785 
   863 
   786     def end_super( self ):
   864     def end_super( self ):
   787         self._pop('super')
   865         self._pop('super')
   788 
   866 
   789     def start_sup( self, attributes ):
   867     start_sup = start_super
   790         A = self.getAttributes(attributes,_supAttrMap)
   868     end_sup = end_super
   791         A['sup']=1
       
   792         self._push('sup',**A)
       
   793 
       
   794     def end_sup( self ):
       
   795         self._pop('sup')
       
   796 
   869 
   797     #### sub script
   870     #### sub script
   798     def start_sub( self, attributes ):
   871     def start_sub( self, attributes ):
   799         A = self.getAttributes(attributes,_supAttrMap)
   872         A = self.getAttributes(attributes,_supAttrMap)
   800         A['sub']=1
       
   801         self._push('sub',**A)
   873         self._push('sub',**A)
       
   874         frag = self._stack[-1]
       
   875         frag.rise -= fontSizeNormalize(frag,'supr',frag.fontSize*subFraction)
       
   876         frag.fontSize = fontSizeNormalize(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
   802 
   877 
   803     def end_sub( self ):
   878     def end_sub( self ):
   804         self._pop('sub')
   879         self._pop('sub')
   805 
   880 
   806     #### greek script
   881     #### greek script
   886     def end_span(self):
   961     def end_span(self):
   887         self._pop('span')
   962         self._pop('span')
   888 
   963 
   889     def start_br(self, attr):
   964     def start_br(self, attr):
   890         self._push('br',_selfClosingTag='br',lineBreak=True,text='')
   965         self._push('br',_selfClosingTag='br',lineBreak=True,text='')
   891         
   966 
   892     def end_br(self):
   967     def end_br(self):
   893         #print('\nend_br called, %d frags in list' % len(self.fragList))
   968         #print('\nend_br called, %d frags in list' % len(self.fragList))
   894         frag = self._stack[-1]
   969         frag = self._stack[-1]
   895         if not (frag._selfClosingTag=='br' and frag.lineBreak):
   970         if not (frag._selfClosingTag=='br' and frag.lineBreak):
   896                 raise ValueError('Parser failure in <br/>')
   971                 raise ValueError('Parser failure in <br/>')
   905             _applyAttributes(style,self.getAttributes(attr,attrMap))
   980             _applyAttributes(style,self.getAttributes(attr,attrMap))
   906             self._style = style
   981             self._style = style
   907 
   982 
   908         # initialize semantic values
   983         # initialize semantic values
   909         frag = ParaFrag()
   984         frag = ParaFrag()
   910         frag.sub = 0
       
   911         frag.sup = 0
       
   912         frag.rise = 0
   985         frag.rise = 0
   913         frag.underline = 0
       
   914         frag.strike = 0
       
   915         frag.greek = 0
   986         frag.greek = 0
   916         frag.link = None
   987         frag.link = []
   917         if bullet:
   988         if bullet:
   918             frag.fontName, frag.bold, frag.italic = ps2tt(style.bulletFontName)
   989             frag.fontName, frag.bold, frag.italic = ps2tt(style.bulletFontName)
   919             frag.fontSize = style.bulletFontSize
   990             frag.fontSize = style.bulletFontSize
   920             frag.textColor = hasattr(style,'bulletColor') and style.bulletColor or style.textColor
   991             frag.textColor = hasattr(style,'bulletColor') and style.bulletColor or style.textColor
   921         else:
   992         else:
   922             frag.fontName, frag.bold, frag.italic = ps2tt(style.fontName)
   993             frag.fontName, frag.bold, frag.italic = ps2tt(style.fontName)
   923             frag.fontSize = style.fontSize
   994             frag.fontSize = style.fontSize
   924             frag.textColor = style.textColor
   995             frag.textColor = style.textColor
       
   996         frag.us_lines = []
       
   997         self.nlinks = self.nlines = 0
       
   998         self._defaultLineWidths = dict(
       
   999                                     underline = getattr(style,'underlineWidth',''),
       
  1000                                     strike = getattr(style,'strikeWidth',''),
       
  1001                                     )
       
  1002         self._defaultLineOffsets = dict(
       
  1003                                     underline = getattr(style,'underlineOffset',''),
       
  1004                                     strike = getattr(style,'strikeOffset',''),
       
  1005                                     )
       
  1006         self._defaultLineGaps = dict(
       
  1007                                     underline = getattr(style,'underlineGap',''),
       
  1008                                     strike = getattr(style,'strikeGap',''),
       
  1009                                     )
       
  1010         self._defaultLinkUnderline = getattr(style,'linkUnderline',platypus_link_underline)
   925         return frag
  1011         return frag
   926 
  1012 
   927     def start_para(self,attr):
  1013     def start_para(self,attr):
   928         frag = self._initial_frag(attr,_paraAttrMap)
  1014         frag = self._initial_frag(attr,_paraAttrMap)
   929         frag.__tag__ = 'para'
  1015         frag.__tag__ = 'para'
  1039         defn.label = attr.get('label',None)
  1125         defn.label = attr.get('label',None)
  1040         defn.kind='onDraw'
  1126         defn.kind='onDraw'
  1041         self._push('ondraw',cbDefn=defn)
  1127         self._push('ondraw',cbDefn=defn)
  1042         self.handle_data('')
  1128         self.handle_data('')
  1043         self._pop('ondraw')
  1129         self._pop('ondraw')
  1044     start_onDraw=start_ondraw 
  1130     start_onDraw=start_ondraw
  1045     end_onDraw=end_ondraw=end_seq
  1131     end_onDraw=end_ondraw=end_seq
  1046 
  1132 
  1047     def start_index(self,attr):
  1133     def start_index(self,attr):
  1048         attr=self.getAttributes(attr,_indexAttrMap)
  1134         attr=self.getAttributes(attr,_indexAttrMap)
  1049         defn = ABag()
  1135         defn = ABag()
  1094             if not self.caseSensitive:
  1180             if not self.caseSensitive:
  1095                 k = k.lower()
  1181                 k = k.lower()
  1096             if k in attrMap:
  1182             if k in attrMap:
  1097                 j = attrMap[k]
  1183                 j = attrMap[k]
  1098                 func = j[1]
  1184                 func = j[1]
  1099                 A[j[0]] = v if func is None else func(v)
  1185                 if func is not None:
       
  1186                     #it's a function
       
  1187                     v = func(self,v) if isinstance(func,_ExValidate) else func(v)
       
  1188                 A[j[0]] = v
  1100             else:
  1189             else:
  1101                 self._syntax_error('invalid attribute name %s attrMap=%r'% (k,list(sorted(attrMap.keys()))))
  1190                 self._syntax_error('invalid attribute name %s attrMap=%r'% (k,list(sorted(attrMap.keys()))))
  1102         return A
  1191         return A
  1103 
  1192 
  1104     #----------------------------------------------------------------
  1193     #----------------------------------------------------------------
  1142             if data: self._syntax_error('Only empty <%s> tag allowed' % kind)
  1231             if data: self._syntax_error('Only empty <%s> tag allowed' % kind)
  1143         elif hasattr(frag,'_selfClosingTag'):
  1232         elif hasattr(frag,'_selfClosingTag'):
  1144             if data!='': self._syntax_error('No content allowed in %s tag' % frag._selfClosingTag)
  1233             if data!='': self._syntax_error('No content allowed in %s tag' % frag._selfClosingTag)
  1145             return
  1234             return
  1146         else:
  1235         else:
  1147             # if sub and sup are both on they will cancel each other out
  1236             #get the right parameters for the
  1148             if frag.sub == 1 and frag.sup == 1:
       
  1149                 frag.sub = 0
       
  1150                 frag.sup = 0
       
  1151 
       
  1152             if frag.sub:
       
  1153                 frag.rise = -fontSizeNormalize(frag,'supr',frag.fontSize*subFraction)
       
  1154                 frag.fontSize = fontSizeNormalize(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
       
  1155             elif frag.sup:
       
  1156                 frag.rise = fontSizeNormalize(frag,'supr',frag.fontSize*supFraction)
       
  1157                 frag.fontSize = fontSizeNormalize(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
       
  1158 
       
  1159             if frag.greek:
  1237             if frag.greek:
  1160                 frag.fontName = 'symbol'
  1238                 frag.fontName = 'symbol'
  1161                 data = _greekConvert(data)
  1239                 data = _greekConvert(data)
  1162 
  1240 
  1163         # bold, italic, and underline
  1241         # bold, italic
  1164         frag.fontName = tt2ps(frag.fontName,frag.bold,frag.italic)
  1242         frag.fontName = tt2ps(frag.fontName,frag.bold,frag.italic)
  1165 
  1243 
  1166         #save our data
  1244         #save our data
  1167         frag.text = data
  1245         frag.text = data
  1168 
  1246 
  1179         self._seq = reportlab.lib.sequencer.getSequencer()
  1257         self._seq = reportlab.lib.sequencer.getSequencer()
  1180         self._reset(style)  # reinitialise the parser
  1258         self._reset(style)  # reinitialise the parser
  1181 
  1259 
  1182     def _complete_parse(self):
  1260     def _complete_parse(self):
  1183         "Reset after parsing, to be ready for next paragraph"
  1261         "Reset after parsing, to be ready for next paragraph"
       
  1262         if self._stack:
       
  1263             self._syntax_error('parse ended with %d unclosed tags\n %s' % (len(self._stack),'\n '.join((x.__tag__ for x in reversed(self._stack)))))
  1184         del self._seq
  1264         del self._seq
  1185         style = self._style
  1265         style = self._style
  1186         del self._style
  1266         del self._style
  1187         if len(self.errors)==0:
  1267         if len(self.errors)==0:
  1188             fragList = self.fragList
  1268             fragList = self.fragList
  1265             if not self.ignoreUnknownTags:
  1345             if not self.ignoreUnknownTags:
  1266                 raise ValueError('Invalid tag "%s"' % tag)
  1346                 raise ValueError('Invalid tag "%s"' % tag)
  1267             start = self.start_unknown
  1347             start = self.start_unknown
  1268         #call it
  1348         #call it
  1269         start(attrs or {})
  1349         start(attrs or {})
  1270         
  1350 
  1271     def handle_endtag(self, tag):
  1351     def handle_endtag(self, tag):
  1272         "Called by HTMLParser when a tag ends"
  1352         "Called by HTMLParser when a tag ends"
  1273         #find the existing end_tagname method
  1353         #find the existing end_tagname method
  1274         if not self.caseSensitive: tag = tag.lower()
  1354         if not self.caseSensitive: tag = tag.lower()
  1275         try:
  1355         try: