/* * This source file is part of RmlUi, the HTML/CSS Interface Middleware * * For the latest information, see http://github.com/mikke89/RmlUi * * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd * Copyright (c) 2019 The RmlUi Team, and contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ #ifndef RMLUI_CORE_LAYOUTBLOCKBOX_H #define RMLUI_CORE_LAYOUTBLOCKBOX_H #include "LayoutLineBox.h" #include "../../Include/RmlUi/Core/Box.h" #include "../../Include/RmlUi/Core/Types.h" namespace Rml { class LayoutBlockBoxSpace; class LayoutEngine; /** @author Peter Curry */ class LayoutBlockBox { public: enum FormattingContext { BLOCK, INLINE }; enum CloseResult { OK, LAYOUT_SELF, LAYOUT_PARENT }; /// Creates a new block box for rendering a block element. /// @param parent[in] The parent of this block box. This will be nullptr for the root element. /// @param element[in] The element this block box is laying out. /// @param box[in] The box used for this block box. /// @param min_height[in] The minimum height of the content box. /// @param max_height[in] The maximum height of the content box. LayoutBlockBox(LayoutBlockBox* parent, Element* element, const Box& box, float min_height, float max_height); /// Creates a new block box in an inline context. /// @param parent[in] The parent of this block box. LayoutBlockBox(LayoutBlockBox* parent); /// Releases the block box. ~LayoutBlockBox(); /// Closes the box. This will determine the element's height (if it was unspecified). /// @return The result of the close; this may request a reformat of this element or our parent. CloseResult Close(); /// Called by a closing block box child. Increments the cursor. /// @param child[in] The closing child block box. /// @return False if the block box caused an automatic vertical scrollbar to appear, forcing an entire reformat of the block box. bool CloseBlockBox(LayoutBlockBox* child); /// Called by a closing line box child. Increments the cursor, and creates a new line box to fit the overflow /// (if any). /// @param child[in] The closing child line box. /// @param overflow[in] The overflow from the closing line box. May be nullptr if there was no overflow. /// @param overflow_chain[in] The end of the chained hierarchy to be spilled over to the new line, as the parent to the overflow box (if one exists). /// @return If the line box had overflow, this will be the last inline box created by the overflow. LayoutInlineBox* CloseLineBox(LayoutLineBox* child, UniquePtr overflow, LayoutInlineBox* overflow_chain); /// Adds a new block element to this block-context box. /// @param element[in] The new block element. /// @param box[in] The box used for the new block box. /// @param min_height[in] The minimum height of the content box. /// @param max_height[in] The maximum height of the content box. /// @return The block box representing the element. Once the element's children have been positioned, Close() must be called on it. LayoutBlockBox* AddBlockElement(Element* element, const Box& box, float min_height, float max_height); /// Adds a new inline element to this inline-context box. /// @param element[in] The new inline element. /// @param box[in] The box defining the element's bounds. /// @return The inline box representing the element. Once the element's children have been positioned, Close() must be called on it. LayoutInlineBox* AddInlineElement(Element* element, const Box& box); /// Adds a line-break to this block box. void AddBreak(); /// Adds an element to this block box to be handled as a floating element. bool AddFloatElement(Element* element); /// Adds an element to this block box to be handled as an absolutely-positioned element. This element will be /// laid out, sized and positioned appropriately once this box is finished. This should only be called on boxes /// rendering in a block-context. /// @param element[in] The element to be positioned absolutely within this block box. void AddAbsoluteElement(Element* element); /// Formats, sizes, and positions all absolute elements in this block. void CloseAbsoluteElements(); /// Returns the offset from the top-left corner of this box's offset element the next child box will be /// positioned at. /// @param[out] box_position The box cursor position. /// @param[in] top_margin The top margin of the box. This will be collapsed as appropriate against other block boxes. /// @param[in] clear_property The value of the underlying element's clear property. void PositionBox(Vector2f& box_position, float top_margin = 0, Style::Clear clear_property = Style::Clear::None) const; /// Returns the offset from the top-left corner of this box's offset element the next child block box, of the /// given dimensions, will be positioned at. This will include the margins on the new block box. /// @param[out] box_position The block box cursor position. /// @param[in] box The dimensions of the new box. /// @param[in] clear_property The value of the underlying element's clear property. void PositionBlockBox(Vector2f& box_position, const Box& box, Style::Clear clear_property) const; /// Returns the offset from the top-left corner of this box for the next line. /// @param box_position[out] The line box position. /// @param box_width[out] The available width for the line box. /// @param wrap_content[out] Set to true if the line box should grow to fit inline boxes, false if it should wrap them. /// @param dimensions[in] The minimum dimensions of the line. void PositionLineBox(Vector2f& box_position, float& box_width, bool& wrap_content, Vector2f dimensions) const; /// Calculate the dimensions of the box's internal content width; i.e. the size used to calculate the shrink-to-fit width. float GetShrinkToFitWidth() const; /// Get the visible overflow size. Note: This is only well-defined after the layout box has been closed. Vector2f GetVisibleOverflowSize() const; /// Set the inner content size if it is larger than the current value on each axis individually. void ExtendInnerContentSize(Vector2f inner_content_size); /// Returns the block box's element. /// @return The block box's element. Element* GetElement() const; /// Returns the block box's parent. /// @return The block box's parent. LayoutBlockBox* GetParent() const; /// Returns the position of the block box, relative to its parent's content area. /// @return The relative position of the block box. Vector2f GetPosition() const; /// Returns the block box against which all positions of boxes in the hierarchy are set relative to. /// @return This box's offset parent. const LayoutBlockBox* GetOffsetParent() const; /// Returns the block box against which all positions of boxes in the hierarchy are calculated relative to. /// @return This box's offset root. const LayoutBlockBox* GetOffsetRoot() const; /// Returns the block box's dimension box. Box& GetBox(); /// Returns the block box's dimension box. const Box& GetBox() const; void* operator new(size_t size); void operator delete(void* chunk, size_t size); private: struct AbsoluteElement { Element* element; Vector2f position; }; // Closes our last block box, if it is an open inline block box. CloseResult CloseInlineBlockBox(); // Positions a floating element within this block box. void PositionFloat(Element* element, float offset = 0); // Checks if we have a new vertical overflow on an auto-scrolling element. If so, our vertical scrollbar will // be enabled and our block boxes will be destroyed. All content will need to re-formatted. Returns true if no // overflow occured, false if it did. bool CatchVerticalOverflow(float cursor = -1); using AbsoluteElementList = Vector< AbsoluteElement >; using BlockBoxList = Vector< UniquePtr >; using LineBoxList = Vector< UniquePtr >; // The object managing our space, as occupied by floating elements of this box and our ancestors. LayoutBlockBoxSpace* space; // The element this box represents. This will be nullptr for boxes rendering in an inline context. Element* element; // The element we'll be computing our offset relative to during layout. const LayoutBlockBox* offset_root; // The element this block box's children are to be offset from. LayoutBlockBox* offset_parent; // The box's block parent. This will be nullptr for the root of the box tree. LayoutBlockBox* parent; // The context of the box's context; either block or inline. FormattingContext context; // The block box's position. Vector2f position; // The block box's size. Box box; float min_height; float max_height; // Used by inline contexts only; set to true if the block box's line boxes should stretch to fit their inline content instead of wrapping. bool wrap_content; // The vertical position of the next block box to be added to this box, relative to the top of this box. float box_cursor; // Used by block contexts only; stores the list of block boxes under this box. BlockBoxList block_boxes; // Used by block contexts only; stores any elements that are to be absolutely positioned within this block box. AbsoluteElementList absolute_elements; // Used by block contexts only; stores any elements that are relatively positioned and whose containing block is this. ElementList relative_elements; // Used by block contexts only; stores the block box space pointed to by the 'space' member. UniquePtr space_owner; // Used by block contexts only; stores an inline element hierarchy that was interrupted by a child block box. // The hierarchy will be resumed in an inline-context box once the intervening block box is completed. LayoutInlineBox* interrupted_chain; // Used by block contexts only; stores the value of the overflow property for the element. Style::Overflow overflow_x_property; Style::Overflow overflow_y_property; // The outer size of this box including overflowing content. Similar to scroll width, but shrinked if overflow is caught here. // This can be wider than the box if we are overflowing. Only available after the box has been closed. Vector2f visible_overflow_size; // The inner content size (excluding any padding/border/margins). // This is extended as child block boxes are closed, or from external formatting contexts. Vector2f inner_content_size; // Used by block contexts only; if true, we've enabled our vertical scrollbar. bool vertical_overflow; // Used by inline contexts only; stores the list of line boxes flowing inline content. LineBoxList line_boxes; // Used by inline contexts only; stores any floating elements that are waiting for a line break to be positioned. ElementList float_elements; }; } // namespace Rml #endif