docs: def breakLines(self, width):
          """
          Returns a broken line structure. There are two cases
  
          A) For the simple case of a single formatting input fragment the output is
              A fragment specifier with
                  - kind = 0
                  - fontName, fontSize, leading, textColor
                  - lines=  A list of lines
  
                          Each line has two items.
  
                          1. unused width in points
                          2. word list
  
          B) When there is more than one input formatting fragment the output is
              A fragment specifier with
                 - kind = 1
                 - lines=  A list of fragments each having fields
                              - extraspace (needed for justified)
                              - fontSize
                              - words=word list
                                  each word is itself a fragment with
                                  various settings
  
          This structure can be used to easily draw paragraphs with the various alignments.
          You can supply either a single width or a list of widths; the latter will have its
          last item repeated until necessary. A 2-element list is useful when there is a
          different first line indent; a longer list could be created to facilitate custom wraps
          around irregular objects.
          """
  
          if self.debug:
              print (id(self), "breakLines")
  
          if not isinstance(width, (tuple, list)):
              maxWidths = [width]
          else:
              maxWidths = width
          lines = []
          lineno = 0
          style = self.style
  
          #for bullets, work out width and ensure we wrap the right amount onto line one
          _handleBulletWidth(self.bulletText, style, maxWidths)
  
          maxWidth = maxWidths[0]
  
          self.height = 0
          autoLeading = getattr(self, 'autoLeading', getattr(style, 'autoLeading', ''))
          calcBounds = autoLeading not in ('', 'off')
          frags = self.frags
          nFrags = len(frags)
          if nFrags == 1 and not hasattr(frags[0], 'cbDefn'):
              f = frags[0]
              fontSize = f.fontSize
              fontName = f.fontName
              ascent, descent = getAscentDescent(fontName, fontSize)
              words = hasattr(f, 'text') and split(f.text, ' ') or f.words
              spaceWidth = stringWidth(' ', fontName, fontSize, self.encoding)
              cLine = []
              currentWidth = -spaceWidth   # hack to get around extra space for word 1
              for word in words:
                  #this underscores my feeling that Unicode throughout would be easier!
                  wordWidth = stringWidth(word, fontName, fontSize, self.encoding)
                  newWidth = currentWidth + spaceWidth + wordWidth
                  if newWidth <= maxWidth or not len(cLine):
                      # fit one more on this line
                      cLine.append(word)
                      currentWidth = newWidth
                  else:
                      if currentWidth > self.width: self.width = currentWidth
                      #end of line
                      lines.append((maxWidth - currentWidth, cLine))
                      cLine = [word]
                      currentWidth = wordWidth
                      lineno += 1
                      try:
                          maxWidth = maxWidths[lineno]
                      except IndexError:
                          maxWidth = maxWidths[-1]  # use the last one
  
              #deal with any leftovers on the final line
              if cLine != []:
                  if currentWidth > self.width: self.width = currentWidth
                  lines.append((maxWidth - currentWidth, cLine))
  
              return f.clone(kind=0, lines=lines, ascent=ascent, descent=descent, fontSize=fontSize)
          elif nFrags <= 0:
              return ParaLines(kind=0, fontSize=style.fontSize, fontName=style.fontName,
                               textColor=style.textColor, ascent=style.fontSize, descent=-0.2 * style.fontSize,
                               lines=[])
          else:
              if hasattr(self, 'blPara') and getattr(self, '_splitpara', 0):
                  #NB this is an utter hack that awaits the proper information
                  #preserving splitting algorithm
                  return self.blPara
              n = 0
              words = []
              for w in _getFragWords(frags):
                  f = w[-1][0]
                  fontName = f.fontName
                  fontSize = f.fontSize
                  spaceWidth = stringWidth(' ', fontName, fontSize)
  
                  if not words:
                      currentWidth = -spaceWidth   # hack to get around extra space for word 1
                      maxSize = fontSize
                      maxAscent, minDescent = getAscentDescent(fontName, fontSize)
  
                  wordWidth = w[0]
                  f = w[1][0]
                  if wordWidth > 0:
                      newWidth = currentWidth + spaceWidth + wordWidth
                  else:
                      newWidth = currentWidth
  
                  #test to see if this frag is a line break. If it is we will only act on it
                  #if the current width is non-negative or the previous thing was a deliberate lineBreak
                  lineBreak = hasattr(f, 'lineBreak')
                  endLine = (newWidth > maxWidth and n > 0) or lineBreak
                  if not endLine:
                      if lineBreak: continue      #throw it away
                      if type(w[1][1]) != six.text_type:
                          nText = six.text_type(w[1][1], 'utf-8')
                      else:
                          nText = w[1][1]
                          
                      if nText: n += 1
                      fontSize = f.fontSize
                      if calcBounds:
                          cbDefn = getattr(f, 'cbDefn', None)
                          if getattr(cbDefn, 'width', 0):
                              descent, ascent = imgVRange(cbDefn.height, cbDefn.valign, fontSize)
                          else:
                              ascent, descent = getAscentDescent(f.fontName, fontSize)
                      else:
                          ascent, descent = getAscentDescent(f.fontName, fontSize)
                      maxSize = max(maxSize, fontSize)
                      maxAscent = max(maxAscent, ascent)
                      minDescent = min(minDescent, descent)
                      if not words:
                          g = f.clone()
                          words = [g]
                          g.text = nText
                      elif not _sameFrag(g, f):
                          if currentWidth > 0 and ((nText != '' and nText[0] != ' ') or hasattr(f, 'cbDefn')):
                              if hasattr(g, 'cbDefn'):
                                  i = len(words) - 1
                                  while i >= 0:
                                      wi = words[i]
                                      cbDefn = getattr(wi, 'cbDefn', None)
                                      if cbDefn:
                                          if not getattr(cbDefn, 'width', 0):
                                              i -= 1
                                              continue
                                      if not wi.text.endswith(' '):
                                          wi.text += ' '
                                      break
                              else:
                                  if type(g.text) == type(' '):
                                      space = " "
                                  else:
                                      space = b" "
                                  if not g.text.endswith(space):
                                      g.text += space
                          g = f.clone()
                          words.append(g)
                          g.text = nText
                      else:
                          if type(g.text) is bytes:
                              g.text = g.text.decode("utf8")
                          if type(nText) is bytes:
                              nText = nText.decode("utf8")
                          if nText != '' and nText[0] != ' ':
                              g.text += ' ' + nText
  
                      for i in w[2:]:
                          g = i[0].clone()
                          g.text = i[1]
                          words.append(g)
                          fontSize = g.fontSize
                          if calcBounds:
                              cbDefn = getattr(g, 'cbDefn', None)
                              if getattr(cbDefn, 'width', 0):
                                  descent, ascent = imgVRange(cbDefn.height, cbDefn.valign, fontSize)
                              else:
                                  ascent, descent = getAscentDescent(g.fontName, fontSize)
                          else:
                              ascent, descent = getAscentDescent(g.fontName, fontSize)
                          maxSize = max(maxSize, fontSize)
                          maxAscent = max(maxAscent, ascent)
                          minDescent = min(minDescent, descent)
  
                      currentWidth = newWidth
                  else:  # either it won't fit, or it's a lineBreak tag
                      if lineBreak:
                          g = f.clone()
                          words.append(g)
  
                      if currentWidth > self.width: self.width = currentWidth
                      #end of line
                      lines.append(FragLine(extraSpace=maxWidth - currentWidth, wordCount=n,
                                            lineBreak=lineBreak, words=words, fontSize=maxSize, ascent=maxAscent,
                                            descent=minDescent))
  
                      #start new line
                      lineno += 1
                      try:
                          maxWidth = maxWidths[lineno]
                      except IndexError:
                          maxWidth = maxWidths[-1]  # use the last one
  
                      if lineBreak:
                          n = 0
                          words = []
                          continue
  
                      currentWidth = wordWidth
                      n = 1
                      g = f.clone()
                      maxSize = g.fontSize
                      if calcBounds:
                          cbDefn = getattr(g, 'cbDefn', None)
                          if getattr(cbDefn, 'width', 0):
                              minDescent, maxAscent = imgVRange(cbDefn.height, cbDefn.valign, maxSize)
                          else:
                              maxAscent, minDescent = getAscentDescent(g.fontName, maxSize)
                      else:
                          maxAscent, minDescent = getAscentDescent(g.fontName, maxSize)
                      words = [g]
                      g.text = w[1][1]
  
                      for i in w[2:]:
                          g = i[0].clone()
                          g.text = i[1]
                          words.append(g)
                          fontSize = g.fontSize
                          if calcBounds:
                              cbDefn = getattr(g, 'cbDefn', None)
                              if getattr(cbDefn, 'width', 0):
                                  descent, ascent = imgVRange(cbDefn.height, cbDefn.valign, fontSize)
                              else:
                                  ascent, descent = getAscentDescent(g.fontName, fontSize)
                          else:
                              ascent, descent = getAscentDescent(g.fontName, fontSize)
                          maxSize = max(maxSize, fontSize)
                          maxAscent = max(maxAscent, ascent)
                          minDescent = min(minDescent, descent)
  
              #deal with any leftovers on the final line
              if words != []:
                  if currentWidth > self.width: self.width = currentWidth
                  lines.append(ParaLines(extraSpace=(maxWidth - currentWidth), wordCount=n,
                                         words=words, fontSize=maxSize, ascent=maxAscent, descent=minDescent))
              return ParaLines(kind=1, lines=lines)
  
          return lines