// // VROText.h // ViroRenderer // // Created by Raj Advani on 11/24/16. // Copyright © 2016 Viro Media. All rights reserved. // #ifndef VROText_h #define VROText_h #include #include #include #include #include FT_FREETYPE_H #include "VROGeometry.h" #include "VROShapeUtils.h" #include "VROVector4f.h" class VROMaterial; class VROTexture; class VROGlyph; enum class VROTextHorizontalAlignment { Left, Right, Center }; enum class VROTextVerticalAlignment { Top, Bottom, Center }; enum class VROLineBreakMode { WordWrap, CharWrap, Justify, None }; enum class VROTextClipMode { ClipToBounds, None }; class VROTextLayout { float width; float height; VROTextHorizontalAlignment horizontalAlignment; VROTextVerticalAlignment verticalAlignment; }; class VROTextLine { public: std::wstring line; float spacingRatio; VROTextLine(std::wstring &line) : line(line), spacingRatio(1) {} VROTextLine(std::wstring &line, float spacingRatio) : line(line), spacingRatio(spacingRatio) {} virtual ~VROTextLine() {} }; class VROText : public VROGeometry { public: /* Create a text object for displaying the given string with the given typeface, constrained to the bounds defined by the provided width and height, and aligned according to the given alignment parameters and linebreak mode. The clip mode determines whether the text is clipped to the given bounds. The maxLines parameter, if set, caps the number of lines; when zero, there is no limit to the number of lines generated. */ static std::shared_ptr createText(std::wstring text, std::shared_ptr typeface, VROVector4f color, float width, float height, VROTextHorizontalAlignment horizontalAlignment, VROTextVerticalAlignment verticalAlignment, VROLineBreakMode lineBreakMode, VROTextClipMode clipMode, int maxLines = 0); /* Helper method to create a single-line text in a horizontal box of the given width. The box is centered at the parent node's position, and the text is aligned within the box according to the given alignment. */ static std::shared_ptr createSingleLineText(std::wstring text, std::shared_ptr typeface, VROVector4f color, float width, VROTextHorizontalAlignment alignment, VROTextClipMode clipMode); /* Helper method to create a centered single-line text. The text will be centered (vertically and horizontally) about the parent node's position. */ static std::shared_ptr createSingleLineText(std::wstring text, std::shared_ptr typeface, VROVector4f color); /* Return the width and height of a text object displaying the given string, with the given typeface. */ static VROVector3f getTextSize(std::wstring text, std::shared_ptr typeface, float maxWidth, float maxHeight, VROLineBreakMode lineBreakMode, VROTextClipMode clipMode, int maxLines = 0); /* Standard constructor. Update() must be invoked from the rendering thread if this constructor is used. */ VROText(std::wstring text, std::shared_ptr typeface, VROVector4f color, float width, float height, VROTextHorizontalAlignment horizontalAlignment, VROTextVerticalAlignment verticalAlignment, VROLineBreakMode lineBreakMode, VROTextClipMode clipMode, int maxLines); virtual ~VROText(); /* Initialize the VROText if any fields have changed. This must be invoked on the rendering thread because it creates glyphs. */ void update(); /* Get the width and height of the text. This is not the width and height of the bounds used when the text was created, but the width and height of the actual text. */ float getRealizedWidth() const { return _realizedWidth; } float getRealizedHeight() const { return _realizedHeight; } void setText(std::wstring text); void setTypeface(std::shared_ptr typeface); void setColor(VROVector4f color); void setWidth(float width); void setHeight(float height); void setHorizontalAlignment(VROTextHorizontalAlignment horizontalAlignment); void setVerticalAlignment(VROTextVerticalAlignment verticalAlignment); void setLineBreakMode(VROLineBreakMode lineBreakMode); void setClipMode(VROTextClipMode clipMode); void setMaxLines(int maxLines); private: std::wstring _text; std::shared_ptr _typeface; VROVector4f _color; float _width, _height; VROTextHorizontalAlignment _horizontalAlignment; VROTextVerticalAlignment _verticalAlignment; VROLineBreakMode _lineBreakMode; VROTextClipMode _clipMode; int _maxLines; std::atomic _realizedWidth, _realizedHeight; VROText(std::vector> sources, std::vector> elements, float width, float height) : VROGeometry(sources, elements), _width(width), _height(height) {} static void buildText(std::wstring &text, std::shared_ptr &typeface, VROVector4f color, float width, float height, VROTextHorizontalAlignment horizontalAlignment, VROTextVerticalAlignment verticalAlignment, VROLineBreakMode lineBreakMode, VROTextClipMode clipMode, int maxLines, std::vector> &sources, std::vector> &elements, std::vector> &materials, float *outRealizedWidth, float *outRealizedHeight); /* Build a standard Viro geometry from the given vertex array and material/indices pairs. */ static void buildGeometry(std::vector &var, std::map, std::vector>> &materialMap, std::vector> &sources, std::vector> &elements, std::vector> &materials); /* Write the geometry for the given glyph (at the given position) into the provided vertex array, and write the associated indices into the indices array as well. */ static void buildChar(std::shared_ptr &glyph, float x, float y, std::vector &var, std::vector &indices); /* Simple methods for processing the line-break mode. All of the methods below use a 'greedy' algorithm, filling as much space in the current line as possible then moving to the next line. These methods also introduce a newline on hard breaks (i.e. whenever the '\n' character is encountered). In particular, the wrapByNewlines function *only* processes hard breaks; the rest process both hard and soft. These functions also handle clipping. When char/word wrapping is on, we only have to clip text vertically (horizontal edges are implicitly taken care of by the wrapping function). When char/word wrapping is off, we also have to clip text horizontally. */ static std::vector wrapByWords(std::wstring &text, float maxWidth, float maxHeight, int maxLines, std::shared_ptr &typeface, VROTextClipMode clipMode, std::map> &glyphMap); static std::vector wrapByChars(std::wstring &text, float maxWidth, float maxHeight, int maxLines, std::shared_ptr &typeface, VROTextClipMode clipMode, std::map> &glyphMap); static std::vector wrapByNewlines(std::wstring &text, float maxWidth, float maxHeight, int maxLines, std::shared_ptr &typeface, VROTextClipMode clipMode, std::map> &glyphMap); /* Justification routine. Considerably more complex than the greedy algorithms above. Note that justification is a word-wrapping technique that reduces the 'raggedness' of the text edges; it can be used with left, right, and centered horizontal alignment. To achieve traditional justified text as seen in newspapers, use it with VROTextHorizontalAlignment::Left. */ static std::vector justify(std::wstring &text, float maxWidth, float maxHeight, int maxLines, std::shared_ptr &typeface, VROTextClipMode clipMode, std::map> &glyphMap); /* Helpers for wrapping/clipping. */ static std::vector divideIntoParagraphs(std::wstring &text); static float getLengthOfWord(const std::wstring &word, std::map> &glyphMap); static bool isAnotherLineAvailable(size_t numLinesNow, float maxHeight, int maxLines, std::shared_ptr &typeface, VROTextClipMode clipMode); }; #endif /* VROText_h */