Return - the rotated, axis-aligned text bbox; - a list of ``(line, (width, ascent, descent), xy)`` tuples for each line; - a ``(xy, (width, height))` pair of the lower-left corner and size of the rotated, *text-aligned* text box (i.e. describing how to dra
(self, renderer)
| 414 | self.stale = True |
| 415 | |
| 416 | def _get_layout(self, renderer): |
| 417 | """ |
| 418 | Return |
| 419 | |
| 420 | - the rotated, axis-aligned text bbox; |
| 421 | - a list of ``(line, (width, ascent, descent), xy)`` tuples for each line; |
| 422 | - a ``(xy, (width, height))` pair of the lower-left corner and size of the |
| 423 | rotated, *text-aligned* text box (i.e. describing how to draw the |
| 424 | text-surrounding box). |
| 425 | """ |
| 426 | thisx, thisy = 0.0, 0.0 |
| 427 | lines = self._get_wrapped_text().split("\n") # Ensures lines is not empty. |
| 428 | |
| 429 | # Reminder: The ascent (a) goes from the baseline to the top and the |
| 430 | # descent (d) from the baseline to the bottom; both are (typically) |
| 431 | # nonnegative. The height h is the sum, h = a + d. |
| 432 | wads = [] # (width, ascents, descents) |
| 433 | xs = [] |
| 434 | ys = [] |
| 435 | |
| 436 | min_ascent = min_descent = line_gap = None |
| 437 | dpi = self.get_figure(root=True).dpi |
| 438 | # Determine full vertical extent of font, including ascenders and descenders: |
| 439 | if not self.get_usetex(): |
| 440 | if hasattr(renderer, '_get_font_height_metrics'): |
| 441 | # TODO: This is a temporary internal method call (for _backend_pdf_ps to |
| 442 | # support AFM files) until we design a proper API for the backends. |
| 443 | min_ascent, min_descent, line_gap = renderer._get_font_height_metrics( |
| 444 | self._fontproperties) |
| 445 | if min_ascent is None: |
| 446 | font = get_font(fontManager._find_fonts_by_props(self._fontproperties)) |
| 447 | possible = [ |
| 448 | ('OS/2', 'sTypoLineGap', 'sTypoAscender', 'sTypoDescender'), |
| 449 | ('hhea', 'lineGap', 'ascent', 'descent') |
| 450 | ] |
| 451 | for table_name, linegap_key, ascent_key, descent_key in possible: |
| 452 | table = font.get_sfnt_table(table_name) |
| 453 | if table is None: |
| 454 | continue |
| 455 | # Rescale to font size/DPI if the metrics were available. |
| 456 | fontsize = self._fontproperties.get_size_in_points() |
| 457 | units_per_em = font.get_sfnt_table('head')['unitsPerEm'] |
| 458 | scale = 1 / units_per_em * fontsize * dpi / 72 |
| 459 | line_gap = table[linegap_key] * scale |
| 460 | min_ascent = table[ascent_key] * scale |
| 461 | min_descent = -table[descent_key] * scale |
| 462 | break |
| 463 | if None in (min_ascent, min_descent): |
| 464 | # Fallback to font measurement. |
| 465 | _, h, min_descent = _get_text_metrics_with_cache( |
| 466 | renderer, "lp", self._fontproperties, |
| 467 | ismath="TeX" if self.get_usetex() else False, |
| 468 | dpi=dpi) |
| 469 | min_ascent = h - min_descent |
| 470 | line_gap = 0 |
| 471 | |
| 472 | # Don't increase text height too much if it's not multiple lines. |
| 473 | if len(lines) == 1: |
no test coverage detected