'''
Text
====

An abstraction of text creation. Depending of the selected backend, the
accuracy of text rendering may vary.

.. versionchanged:: 1.10.1
    :meth:`LabelBase.find_base_direction` added.

.. versionchanged:: 1.5.0
    :attr:`LabelBase.line_height` added.

.. versionchanged:: 1.0.7
    The :class:`LabelBase` does not generate any texture if the text has a
    width <= 1.

This is the backend layer for rendering text with different text providers,
you should only be using this directly if your needs aren't fulfilled by the
:class:`~kivy.uix.label.Label`.

Usage example::

    from kivy.core.text import Label as CoreLabel

    ...
    ...
    my_label = CoreLabel()
    my_label.text = 'hello'
    # the label is usually not drawn until needed, so force it to draw.
    my_label.refresh()
    # Now access the texture of the label and use it wherever and
    # however you may please.
    hello_texture = my_label.texture


Font Context Manager
====================

A font context is a namespace where multiple fonts are loaded; if a font is
missing a glyph needed to render text, it can fall back to a different font in
the same context. The font context manager can be used to query and manipulate
the state of font contexts when using the Pango text provider (no other
provider currently implements it).

.. versionadded:: 1.11.0

.. warning:: This feature requires the Pango text provider.

Font contexts can be created automatically by :class:`kivy.uix.label.Label` or
:class:`kivy.uix.textinput.TextInput`; if a non-existant context is used in
one of these classes, it will be created automatically, or if a font file is
specified without a context (this creates an isolated context, without
support for fallback).

Usage example::

    from kivy.uix.label import Label
    from kivy.core.text import FontContextManager as FCM

    # Create a font context containing system fonts + one custom TTF
    FCM.create('system://myapp')
    family = FCM.add_font('/path/to/file.ttf')

    # These are now interchangeable ways to refer to the custom font:
    lbl1 = Label(font_context='system://myapp', family_name=family)
    lbl2 = Label(font_context='system://myapp', font_name='/path/to/file.ttf')

    # You could also refer to a system font by family, since this is a
    # system:// font context
    lbl3 = Label(font_context='system://myapp', family_name='Arial')
'''

__all__ = ('LabelBase', 'Label',
           'FontContextManagerBase', 'FontContextManager')

import re
import os
from ast import literal_eval
from functools import partial
from copy import copy
from kivy import kivy_data_dir
from kivy.config import Config
from kivy.utils import platform
from kivy.graphics.texture import Texture
from kivy.core import core_select_lib
from kivy.core.text.text_layout import layout_text, LayoutWord
from kivy.resources import resource_find, resource_add_path
from kivy.compat import PY2
from kivy.setupconfig import USE_SDL2, USE_PANGOFT2


if 'KIVY_DOC' not in os.environ:
    _default_font_paths = literal_eval(Config.get('kivy', 'default_font'))
    DEFAULT_FONT = _default_font_paths.pop(0)
else:
    DEFAULT_FONT = None

FONT_REGULAR = 0
FONT_ITALIC = 1
FONT_BOLD = 2
FONT_BOLDITALIC = 3

whitespace_pat = re.compile('( +)')


class LabelBase(object):
    '''Core text label.
    This is the abstract class used by different backends to render text.

    .. warning::
        The core text label can't be changed at runtime. You must recreate one.

    :Parameters:
        `font_size`: int, defaults to 12
            Font size of the text
        `font_context`: str, defaults to None
            Context for the specified font (see :class:`kivy.uix.label.Label`
            for details). `None` will autocreate an isolated context named
            after the resolved font file.
        `font_name`: str, defaults to DEFAULT_FONT
            Font name of the text
        `font_family`: str, defaults to None
            Font family name to request for drawing, this can only be used
            with `font_context`.
        `bold`: bool, defaults to False
            Activate "bold" text style
        `italic`: bool, defaults to False
            Activate "italic" text style
        `text_size`: tuple, defaults to (None, None)
            Add constraint to render the text (inside a bounding box).
            If no size is given, the label size will be set to the text size.
        `padding`: float, defaults to None
            If it's a float, it will set padding_x and padding_y
        `padding_x`: float, defaults to 0.0
            Left/right padding
        `padding_y`: float, defaults to 0.0
            Top/bottom padding
        `halign`: str, defaults to "left"
            Horizontal text alignment inside the bounding box
        `valign`: str, defaults to "bottom"
            Vertical text alignment inside the bounding box
        `shorten`: bool, defaults to False
            Indicate whether the label should attempt to shorten its textual
            contents as much as possible if a `size` is given.
            Setting this to True without an appropriately set size will lead to
            unexpected results.
        `shorten_from`: str, defaults to `center`
            The side from which we should shorten the text from, can be left,
            right, or center. E.g. if left, the ellipsis will appear towards
            the left side and it will display as much text starting from the
            right as possible.
        `split_str`: string, defaults to `' '` (space)
          
  The string to use to split the words by when shortening. If empty,
            we can split after every character filling up the line as much as
            possible.

        `max_lines`: int, defaults to 0 (unlimited)
            If set, this indicate how maximum line are allowed to render the
            text. Works only if a limitation on text_size is set.
        `mipmap`: bool, defaults to False
            Create a mipmap for the texture
        `strip`: bool, defaults to False
            Whether each row of text has its leading and trailing spaces
            stripped. If `halign` is `justify` it is implicitly True.
        `strip_reflow`: bool, defaults to True
            Whether text that has been reflowed into a second line should
            be stripped, even if `strip` is False. This is only in effect when
            `size_hint_x` is not None, because otherwise lines are never
            split.
        `unicode_errors`: str, defaults to `'replace'`
            How to handle unicode decode errors. Can be `'strict'`, `'replace'`
            or `'ignore'`.
        `outline_width`: int, defaults to None
            Width in pixels for the outline.
        `outline_color`: tuple, defaults to (0, 0, 0)
            Color of the outline.
        `font_features`: str, defaults to None
            OpenType font features in CSS format (Pango only)
        `base_direction`: str, defaults to None (auto)
            Text direction, one of `None`, `'ltr'`, `'rtl'`, `'weak_ltr'`,
            or `'weak_rtl'` (Pango only)
        `text_language`: str, defaults to None (user locale)
            RFC-3066 format language tag as a string (Pango only)

    .. versionchanged:: 1.10.1
        `font_context`, `font_family`, `font_features`, `base_direction`
        and `text_language` were added.

    .. versionchanged:: 1.10.0
        `outline_width` and `outline_color` were added.

    .. versionchanged:: 1.9.0
        `strip`, `strip_reflow`, `shorten_from`, `split_str`, and
        `unicode_errors` were added.

    .. versionchanged:: 1.9.0
        `padding_x` and `padding_y` has been fixed to work as expected.
        In the past, the text was padded by the negative of their values.

    .. versionchanged:: 1.8.0
        `max_lines` parameters has been added.

    .. versionchanged:: 1.0.8
        `size` have been deprecated and replaced with `text_size`.

    .. versionchanged:: 1.0.7
        The `valign` is now respected. This wasn't the case previously
        so you might have an issue in your application if you have not
        considered this.

    '''

    __slots__ = ('opt