/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkTypeface_DEFINED
#define SkTypeface_DEFINED

#include "../private/SkBitmaskEnum.h"
#include "../private/SkOnce.h"
#include "../private/SkWeakRefCnt.h"
#include "SkFontStyle.h"
#include "SkRect.h"
#include "SkString.h"

class SkDescriptor;
class SkFontData;
class SkFontDescriptor;
class SkScalerContext;
struct SkScalerContextRec;
struct SkScalerContextEffects;
class SkStream;
class SkStreamAsset;
class SkAdvancedTypefaceMetrics;
class SkWStream;

typedef uint32_t SkFontID;
/** Machine endian. */
typedef uint32_t SkFontTableTag;

/** \class SkTypeface

    The SkTypeface class specifies the typeface and intrinsic style of a font.
    This is used in the paint, along with optionally algorithmic settings like
    textSize, textSkewX, textScaleX, kFakeBoldText_Mask, to specify
    how text appears when drawn (and measured).

    Typeface objects are immutable, and so they can be shared between threads.
*/
class SK_API SkTypeface : public SkWeakRefCnt {
public:
    /** Style specifies the intrinsic style attributes of a given typeface
    */
    enum Style {
        kNormal = 0,
        kBold   = 0x01,
        kItalic = 0x02,

        // helpers
        kBoldItalic = 0x03
    };

    /** Returns the typeface's intrinsic style attributes. */
    SkFontStyle fontStyle() const {
        return fStyle;
    }

    /** Returns the typeface's intrinsic style attributes.
     *  @deprecated use fontStyle() instead.
     */
    Style style() const {
        return static_cast<Style>(
            (fStyle.weight() >= SkFontStyle::kSemiBold_Weight ? kBold : kNormal) |
            (fStyle.slant()  != SkFontStyle::kUpright_Slant ? kItalic : kNormal));
    }

    /** Returns true if style() has the kBold bit set. */
    bool isBold() const { return fStyle.weight() >= SkFontStyle::kSemiBold_Weight; }

    /** Returns true if style() has the kItalic bit set. */
    bool isItalic() const { return fStyle.slant() != SkFontStyle::kUpright_Slant; }

    /** Returns true if the typeface claims to be fixed-pitch.
     *  This is a style bit, advance widths may vary even if this returns true.
     */
    bool isFixedPitch() const { return fIsFixedPitch; }

    /** Return a 32bit value for this typeface, unique for the underlying font
        data. Will never return 0.
     */
    SkFontID uniqueID() const { return fUniqueID; }

    /** Return the uniqueID for the specified typeface. If the face is null,
        resolve it to the default font and return its uniqueID. Will never
        return 0.
    */
    static SkFontID UniqueID(const SkTypeface* face);

    /** Returns true if the two typefaces reference the same underlying font,
        handling either being null (treating null as the default font)
     */
    static bool Equal(const SkTypeface* facea, const SkTypeface* faceb);

    /** Returns the default typeface, which is never nullptr. */
    static sk_sp<SkTypeface> MakeDefault(Style style = SkTypeface::kNormal);
#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR
    static SkTypeface* RefDefault(Style style = SkTypeface::kNormal) {
        return MakeDefault(style).release();
    }
#endif

  /** Creates a new reference to the typeface that most closely matches the
      requested familyName and fontStyle. This method allows extended font
      face specifiers as in the SkFontStyle type. Will never return null.

      @param familyName  May be NULL. The name of the font family.
      @param fontStyle   The style of the typeface.
      @return reference to the closest-matching typeface. Call must call
              unref() when they are done.
    */
  static sk_sp<SkTypeface> MakeFromName(const char familyName[], SkFontStyle fontStyle);

#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR
    static SkTypeface* CreateFromName(const char familyName[], Style style) {
        return MakeFromName(familyName, SkFontStyle::FromOldStyle(style)).release();
    }
#endif

    /** Return the typeface that most closely matches the requested typeface and style.
        Use this to pick a new style from the same family of the existing typeface.
        If family is nullptr, this selects from the default font's family.

        @param family  May be NULL. The name of the existing type face.
        @param s       The style (normal, bold, italic) of the type face.
        @return the closest-matching typeface.
    */
    static sk_sp<SkTypeface> MakeFromTypeface(SkTypeface* family, Style);

    /** Return a new typeface given a file. If the file does not exist, or is
        not a valid font file, returns nullptr.
    */
    static sk_sp<SkTypeface> MakeFromFile(const char path[], int index = 0);
#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR
    static SkTypeface* CreateFromFile(const char path[], int index = 0) {
        return MakeFromFile(path, index).release();
    }
#endif

    /** Return a new typeface given a stream. If the stream is
        not a valid font file, returns nullptr. Ownership of the stream is
        transferred, so the caller must not reference it again.
    */
    static sk_sp<SkTypeface> MakeFromStream(SkStreamAsset* stream, int index = 0);
#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR
    static SkTypeface* CreateFromStream(SkStreamAsset* stream, int index = 0) {
        return MakeFromStream(stream, index).release();
    }
#endif

    /** Return a new typeface given font data and configuration. If the data
        is not valid font data, returns nullptr.
    */
    static sk_sp<SkTypeface> MakeFromFontData(std::unique_ptr<SkFontData>);

    /** Write a unique signature to a stream, sufficient to reconstruct a
        typeface referencing the same font when Deserialize is called.
     */
    void serialize(SkWStream*) const;

    /** Given the data previously written by serialize(), return a new instance
        of a typeface referring to the same font. If that font is not available,
        return nullptr.
        Does not affect ownership of SkStream.
     */
    static sk_sp<SkTypeface> MakeDeserialize(SkStream*);

    enum Encoding {
        kUTF8_Encoding,
        kUTF16_Encoding,
        kUTF32_Encoding
    };

    /**
     *  Given an array of character codes, of the specified encoding,
     *  optionally return their corresponding glyph IDs (if glyphs is not NULL).
     *
     *  @param chars pointer to the array of character codes
     *  @param encoding how the characters are encoded
     *  @param glyphs (optional) returns the corresponding glyph IDs for each
     *          character code, up to glyphCount values. If a character code is
     *          not found in the typeface, the corresponding glyph ID will be 0.
     *  @param glyphCount number of code points in 'chars' to process. If glyphs
     *          is not NULL, then it must point sufficient memory to write
     *          glyphCount values into it.
     *  @return the number of number of continuous non-zero glyph IDs computed
     *          from the beginning of chars. This value is valid, even if the
     *          glyphs parameter is NULL.
     */
    int charsToGlyphs(const void* chars, Encoding encoding, SkGlyphID glyphs[],
                      int glyphCount) const;

    /**
     *  Return the number of glyphs in the typeface.
     */
    int countGlyphs() const;

    // Table getters -- may fail if the underlying font format is not organized
    // as 4-byte tables.

    /** Return the number of tables in the font. */
    int countTables() const;

    /** Copy into tags[] (allocated by the caller) the list of table tags in
     *  the font, and return the number. This will be the same as CountTables()
     *  or 0 if an error occured. If tags == NULL, this only returns the count
     *  (the same as calling countTables()).
     */
    int getTableTags(SkFontTableTag tags[]) const;

    /** Given a table tag, return the size of its contents, or 0 if not present
     */
    size_t getTableSize(SkFontTableTag) const;

    /** Copy the contents of a table into data (allocated by the caller). Note
     *  that the contents of the table will be in their native endian order
     *  (which for most truetype tables is big endian). If the table tag is
     *  not found, or there is an error copying the data, then 0 is returned.
     *  If this happens, it is possible that some or all of the memory pointed
     *  to by data may have been written to, even though an error has occured.
     *
     *  @param fontID the font to copy the table from
     *  @param tag  The table tag whose contents are to be copied
     *  @param offset The offset in bytes into the table's contents where the
     *  copy should start from.
     *  @param length The number of bytes, starting at offset, of table data
     *  to copy.
     *  @param data storage address where the table contents are copied to
     *  @return the number of bytes actually copied into data. If offset+length
     *  exceeds the table's size, then only the bytes up to the table's
     *  size are actually copied, and this is the value returned. If
     *  offset > the table's size, or tag is not a valid table,
     *  then 0 is returned.
     */
    size_t getTableData(SkFontTableTag tag, size_t offset, size_t length,
                        void* data) const;

    /**
     *  Return the units-per-em value for this typeface, or zero if there is an
     *  error.
     */
    int getUnitsPerEm() const;

    /**
     *  Given a run of glyphs, return the associated horizontal adjustments.
     *  Adjustments are in "design units", which are integers relative to the
     *  typeface's units per em (see getUnitsPerEm).
     *
     *  Some typefaces are known to never support kerning. Calling this method
     *  with all zeros (e.g. getKerningPairAdustments(NULL, 0, NULL)) returns
     *  a boolean indicating if the typeface might support kerning. If it
     *  returns false, then it will always return false (no kerning) for all
     *  possible glyph runs. If it returns true, then it *may* return true for
     *  somne glyph runs.
     *
     *  If count is non-zero, then the glyphs parameter must point to at least
     *  [count] valid glyph IDs, and the adjustments parameter must be
     *  sized to at least [count - 1] entries. If the method returns true, then
     *  [count-1] entries in the adjustments array will be set. If the method
     *  returns false, then no kerning should be applied, and the adjustments
     *  array will be in an undefined state (possibly some values may have been
     *  written, but none of them should be interpreted as valid values).
     */
    bool getKerningPairAdjustments(const SkGlyphID glyphs[], int count,
                                   int32_t adjustments[]) const;

    struct LocalizedString {
        SkString fString;
        SkString fLanguage;
    };
    class LocalizedStrings : ::SkNoncopyable {
    public:
        virtual ~LocalizedStrings() { }
        virtual bool next(LocalizedString* localizedString) = 0;
        void unref() { delete this; }
    };
    /**
     *  Returns an iterator which will attempt to enumerate all of the
     *  family names specified by the font.
     *  It is the caller's responsibility to unref() the returned pointer.
     */
    LocalizedStrings* createFamilyNameIterator() const;

    /**
     *  Return the family name for this typeface. It will always be returned
     *  encoded as UTF8, but the language of the name is whatever the host
     *  platform chooses.
     */
    void getFamilyName(SkString* name) const;

    /**
     *  Return a stream for the contents of the font data, or NULL on failure.
     *  If ttcIndex is not null, it is set to the TrueTypeCollection index
     *  of this typeface within the stream, or 0 if the stream is not a
     *  collection.
     *  The caller is responsible for deleting the stream.
     */
    SkStreamAsset* openStream(int* ttcIndex) const;

    /**
     *  Return the font data, or nullptr on failure.
     */
    std::unique_ptr<SkFontData> makeFontData() const;

    /**
     *  Return a scalercontext for the given descriptor. If this fails, then
     *  if allowFailure is true, this returns NULL, else it returns a
     *  dummy scalercontext that will not crash, but will draw nothing.
     */
    SkScalerContext* createScalerContext(const SkScalerContextEffects&, const SkDescriptor*,
                                         bool allowFailure = false) const;

    /**
     *  Return a rectangle (scaled to 1-pt) that represents the union of the bounds of all
     *  of the glyphs, but each one positioned at (0,). This may be conservatively large, and
     *  will not take into account any hinting or other size-specific adjustments.
     */
    SkRect getBounds() const;

    /***
     * Returns whether this typeface has color glyphs and therefore cannot be
     * rendered as a path. e.g. Emojis.
     */
    virtual bool hasColorGlyphs() const { return false; }

    // PRIVATE / EXPERIMENTAL -- do not call
    void filterRec(SkScalerContextRec* rec) const {
        this->onFilterRec(rec);
    }
    // PRIVATE / EXPERIMENTAL -- do not call
    void getFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
        this->onGetFontDescriptor(desc, isLocal);
    }

protected:
    // The type of advance data wanted.
    enum PerGlyphInfo {
        kNo_PerGlyphInfo         = 0x0, // Don't populate any per glyph info.
        kGlyphNames_PerGlyphInfo = 0x1, // Populate glyph names (Type 1 only).
        kToUnicode_PerGlyphInfo  = 0x2  // Populate ToUnicode table, ignored
                                        // for Type 1 fonts
    };

    /** uniqueID must be unique and non-zero
    */
    SkTypeface(const SkFontStyle& style, bool isFixedPitch = false);
    virtual ~SkTypeface();

    /** Sets the fixedPitch bit. If used, must be called in the constructor. */
    void setIsFixedPitch(bool isFixedPitch) { fIsFixedPitch = isFixedPitch; }
    /** Sets the font style. If used, must be called in the constructor. */
    void setFontStyle(SkFontStyle style) { fStyle = style; }

    friend class SkScalerContext;
    static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal);

    virtual SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
                                                   const SkDescriptor*) const = 0;
    virtual void onFilterRec(SkScalerContextRec*) const = 0;
    virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
                        PerGlyphInfo,
                        const uint32_t* glyphIDs,
                        uint32_t glyphIDsCount) const = 0;

    virtual SkStreamAsset* onOpenStream(int* ttcIndex) const = 0;
    // TODO: make pure virtual.
    virtual std::unique_ptr<SkFontData> onMakeFontData() const;

    virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0;

    virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[],
                                int glyphCount) const = 0;
    virtual int onCountGlyphs() const = 0;

    virtual int onGetUPEM() const = 0;
    virtual bool onGetKerningPairAdjustments(const SkGlyphID glyphs[], int count,
                                             int32_t adjustments[]) const;

    /** Returns the family name of the typeface as known by its font manager.
     *  This name may or may not be produced by the family name iterator.
     */
    virtual void onGetFamilyName(SkString* familyName) const = 0;

    /** Returns an iterator over the family names in the font. */
    virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0;

    virtual int onGetTableTags(SkFontTableTag tags[]) const = 0;
    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
                                  size_t length, void* data) const = 0;

    virtual bool onComputeBounds(SkRect*) const;

private:
    friend class SkGTypeface;
    friend class SkRandomTypeface;
    friend class SkPDFFont;
    friend class GrPathRendering;
    friend class GrGLPathRendering;

    /** Retrieve detailed typeface metrics.  Used by the PDF backend.
     @param perGlyphInfo Indicate what glyph specific information (advances,
     names, etc.) should be populated.
     @param glyphIDs  For per-glyph info, specify subset of the font by
     giving glyph ids.  Each integer represents a glyph
     id.  Passing NULL means all glyphs in the font.
     @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if
     glyphIDs is NULL.
     @return The returned object has already been referenced.
     */
    SkAdvancedTypefaceMetrics* getAdvancedTypefaceMetrics(
                          PerGlyphInfo,
                          const uint32_t* glyphIDs = NULL,
                          uint32_t glyphIDsCount = 0) const;

private:
    SkFontID            fUniqueID;
    SkFontStyle         fStyle;
    mutable SkRect      fBounds;
    mutable SkOnce      fBoundsOnce;
    bool                fIsFixedPitch;

    friend class SkPaint;
    friend class SkGlyphCache;  // GetDefaultTypeface

    typedef SkWeakRefCnt INHERITED;
};

namespace skstd {
template <> struct is_bitmask_enum<SkTypeface::PerGlyphInfo> : std::true_type {};
}

#endif
