1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2010 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 #ifndef RENDER_BLOCK_H_
8 #define RENDER_BLOCK_H_
9 
10 #include <Wt/WFont.h>
11 #include <Wt/WGlobal.h>
12 #include <Wt/WWebWidget.h>
13 #include <Wt/WPainter.h>
14 
15 #include "web/DomElement.h"
16 #include "LayoutBox.h"
17 #include "3rdparty/rapidxml/rapidxml.hpp"
18 #include "Wt/Render/Specificity.h"
19 
20 namespace Wt {
21   namespace Render {
22 
23 class WTextRenderer;
24 class Block;
25 class Line;
26 class StyleSheet;
27 
28 typedef std::vector<Block *> BlockList;
29 
30 struct PageState
31 {
PageStatePageState32   PageState()
33     : y(0), minX(0), maxX(0), page(0)
34   { }
35 
36   double y;
37   double minX, maxX;
38   BlockList floats;
39   int page;
40 };
41 
42 struct CellState : public PageState
43 {
44   int lastRow;
45   double x;
46   Block *cell;
47 };
48 
49 struct Range
50 {
RangeRange51   Range(double start, double end)
52     : start(start), end(end)
53   { }
54 
55   double start, end;
56 };
57 
58 enum class FloatSide {
59   None,
60   Left,
61   Right
62 };
63 
64 // exported for test.exe
65 class WT_API Block
66 {
67 public:
68   Block(Wt::rapidxml::xml_node<> *node, Block *parent);
69   virtual ~Block();
70 
parent()71   const Block* parent() const { return parent_; }
children()72   BlockList children() const { return children_; }
73   void determineDisplay();
74   bool normalizeWhitespace(bool haveWhitespace,
75 			   Wt::rapidxml::xml_document<> &doc);
76 
isFloat()77   bool isFloat() const { return float_ != FloatSide::None; }
isInline()78   bool isInline() const { return inline_; }
type()79   DomElementType type() const { return type_; }
80   bool isText() const;
81   std::string text() const;
82   bool inlineChildren() const;
83   AlignmentFlag horizontalAlignment() const;
84   AlignmentFlag verticalAlignment() const;
floatSide()85   FloatSide floatSide() const { return float_; }
86 
isTableCell()87   bool isTableCell() const
88     { return type_ == DomElementType::TD || type_ == DomElementType::TH; }
89 
isTable()90   bool isTable() const
91     { return type_ == DomElementType::TABLE; }
92 
93   Block *table() const;
94   bool tableCollapseBorders() const;
95 
96   double layoutBlock(PageState &ps,
97 		     bool canIncreaseWidth,
98 		     const WTextRenderer& renderer,
99 		     double collapseMarginTop,
100 		     double collapseMarginBottom,
101 		     double cellHeight = -1);
102 
103   void collectStyles(WStringStream& ss);
104   void setStyleSheet(StyleSheet* styleSheet);
105   void actualRender(WTextRenderer& renderer, WPainter& painter, LayoutBox& lb);
106 
107   void render(WTextRenderer& renderer, WPainter& painter, int page);
108 
109   static void clearFloats(PageState &ps);
110   static void clearFloats(PageState &ps,
111 			  double minWidth);
112 
113   std::vector<InlineBox> inlineLayout; // for inline elements, one per line
114   std::vector<BlockBox>  blockLayout;  // otherwise, one per page
115 
116   static void adjustAvailableWidth(double y, int page,
117 				   const BlockList& floats,
118 				   Range &rangeX);
119 
120   static bool isWhitespace(char c);
121 
122   std::string id() const;
classes()123   const std::vector<std::string>& classes() const { return classes_; }
124   std::string cssProperty(Property property) const;
125   std::string attributeValue(const char *attribute) const;
126 
127 private:
128   struct CssLength {
129     double length;
130     bool defined;
131   };
132 
133   enum class PercentageRule {
134     PercentageOfFontSize,
135     PercentageOfParentSize,
136     IgnorePercentage
137   };
138 
139   struct PropertyValue
140   {
PropertyValuePropertyValue141     PropertyValue() { }
PropertyValuePropertyValue142     PropertyValue(const std::string& value, const Specificity& s)
143       : value_(value), s_(s) { }
144 
145     std::string value_;
146     Specificity s_;
147   };
148 
149   enum Corner { TopLeft, TopRight, BottomLeft, BottomRight };
150 
151   enum class WidthType {
152     AsSetWidth,
153     MinimumWidth,
154     MaximumWidth
155   };
156 
157   struct BorderElement {
158     const Block *block;
159     Side side;
160 
BorderElementBorderElement161     BorderElement() : block(nullptr), side(Side::Left) { }
BorderElementBorderElement162     BorderElement(const Block *aBlock, Side aSide)
163       : block(aBlock), side(aSide) { }
164   };
165 
166   Wt::rapidxml::xml_node<> *node_;
167   Block *parent_;
168   BlockList offsetChildren_;
169   Block *offsetParent_;
170   DomElementType type_;
171   std::vector<std::string> classes_;
172   FloatSide float_;
173   bool inline_;
174   BlockList children_;
175   const LayoutBox *currentTheadBlock_;
176   double currentWidth_;
177   double contentsHeight_;
178   mutable std::map<std::string, PropertyValue> css_;
179   mutable WFont font_;
180   StyleSheet* styleSheet_;
181   mutable std::set<Property> noPropertyCache_;
182 
183   /* For table */
184   int tableRowCount_, tableColCount_;
185 
186   /* For table cell */
187   int cellRow_, cellCol_;
188 
189   int attributeValue(const char *attribute, int defaultValue) const;
190 
191   void updateAggregateProperty(const std::string& property,
192                                const std::string& aggregate,
193                                const Specificity& spec,
194                                const std::string& value) const;
195   void fillinStyle(const std::string& style,
196                    const Specificity &specificity) const;
197   bool isPositionedAbsolutely() const;
198   std::string inheritedCssProperty(Property property) const;
199   double cssWidth(double fontScale) const;
200   double cssHeight(double fontScale) const;
201   CssLength cssLength(Property top, Side side, double fontScale) const;
202   double cssMargin(Side side, double fontScale) const;
203   double cssPadding(Side side, double fontScale) const;
204   double cssBorderSpacing(double fontScale) const;
205 
206   double cssBorderWidth(Side side, double fontScale) const;
207   double collapsedBorderWidth(Side side, double fontScale) const;
208   double rawCssBorderWidth(Side side, double fontScale,
209 			   bool indicateHidden = false) const;
210   WColor cssBorderColor(Side side) const;
211   WColor collapsedBorderColor(Side side) const;
212   WColor rawCssBorderColor(Side side) const;
213 
214   WColor cssColor() const;
215   AlignmentFlag cssTextAlign() const;
216   double cssBoxMargin(Side side, double fontScale) const;
217   double cssLineHeight(double fontLineHeight, double fontScale) const;
218   double cssFontSize(double fontScale = 1) const;
219   std::string cssPosition() const;
220   FontStyle cssFontStyle() const;
221   int cssFontWeight() const;
222   WFont cssFont(double fontScale) const;
223   std::string cssTextDecoration() const;
224   double cssDecodeLength(const std::string& length, double fontScale,
225 			 double defaultValue,
226 			 PercentageRule percentage =
227 			   PercentageRule::PercentageOfFontSize,
228 			 double parentSize = 0)
229     const;
230   static bool isPercentageLength(const std::string& length);
231 
232   double currentParentWidth() const;
233 
234   bool isInside(DomElementType type) const;
235 
236   void pageBreak(PageState& ps);
237   void inlinePageBreak(const std::string& pageBreak,
238 		       Line& line, BlockList& floats,
239 		       double minX, double maxX,
240 		       const WTextRenderer& renderer);
241   double layoutInline(Line& line, BlockList& floats,
242 		      double minX, double maxX, bool canIncreaseWidth,
243 		      const WTextRenderer& renderer);
244   void layoutTable(PageState &ps,
245 		   bool canIncreaseWidth,
246 		   const WTextRenderer& renderer,
247 		   double cssSetWidth);
248   double layoutFloat(double y, int page, BlockList& floats,
249 		     double lineX, double lineHeight,
250 		     double minX, double maxX,
251 		     bool canIncreaseWidth,
252 		     const WTextRenderer& renderer);
253   void layoutAbsolute(const WTextRenderer& renderer);
254 
255   void tableDoLayout(double x, PageState &ps, double cellSpacing,
256 		     const std::vector<double>& widths,
257 		     std::vector<CellState>& rowSpanBackLog,
258 		     bool protectRows, Block *repeatHead,
259 		     const WTextRenderer& renderer);
260   void tableRowDoLayout(double x, PageState &ps,
261 			double cellSpacing,
262 			const std::vector<double>& widths,
263 			std::vector<CellState>& rowSpanBackLog,
264 			const WTextRenderer& renderer,
265 			double rowHeight);
266   void tableCellDoLayout(double x, const PageState &ps,
267 			 double cellSpacing, PageState& rowEnd,
268 			 const std::vector<double>& widths,
269 			 const WTextRenderer& renderer,
270 			 double rowHeight);
271   double tableCellX(const std::vector<double>& widths,
272 		    double cellSpacing) const;
273   double tableCellWidth(const std::vector<double>& widths,
274 			double cellSpacing) const;
275   void tableComputeColumnWidths(std::vector<double>& minima,
276 				std::vector<double>& maxima,
277 				std::vector<double>& asSet,
278 				const WTextRenderer& renderer,
279 				Block *table);
280 
281   BorderElement collapseCellBorders(Side side) const;
282   int numberTableCells(int row, std::vector<int>& rowSpan);
283   Block *findTableCell(int row, int col) const;
284   Block *siblingTableCell(Side side) const;
285 
286   void cellComputeColumnWidths(WidthType type,
287 			       std::vector<double>& values,
288 			       const WTextRenderer& renderer,
289 			       Block *table);
290 
291   void setOffsetParent();
292   Block *findOffsetParent();
293   LayoutBox layoutTotal();
294   LayoutBox firstInlineLayoutBox();
295 
296   LayoutBox toBorderBox(const LayoutBox& bb, double fontScale) const;
297   double maxLayoutY(int page) const;
298   double minLayoutY(int page) const;
299   double maxChildrenLayoutY(int page) const;
300   double minChildrenLayoutY(int page) const;
301   double childrenLayoutHeight(int page) const;
302   void reLayout(const LayoutBox& from, const LayoutBox& to);
303 
304   void renderText(const std::string& text, WTextRenderer& renderer,
305                    WPainter& painter, int page);
306   void renderBorders(const LayoutBox& bb, WTextRenderer& renderer, WPainter &painter,
307                      WFlags<Side> verticals);
308 
309   WString generateItem() const;
310 
311   int firstLayoutPage() const;
312 
313   int lastLayoutPage() const;
314 
315   static void advance(PageState &ps, double height,
316 		      const WTextRenderer& renderer);
317   static double diff(double y, int page, double startY, int startPage,
318 		     const WTextRenderer& renderer);
319 
320   static double positionFloat(double x,
321 			      PageState &ps,
322 			      double lineHeight, double width,
323 			      bool canIncreaseWidth,
324 			      const WTextRenderer& renderer,
325 			      FloatSide floatSide);
326 
327   static void unsupportedAttributeValue(const char *attribute,
328 					const std::string& value);
329   static void unsupportedCssValue(Property property,
330 				  const std::string& value);
331 
332   static bool isAggregate(const std::string& cssProperty);
333 
334   static double maxBorderWidth(Block *b1, Side s1,
335 			       Block *b2, Side s2,
336 			       Block *b3, Side s3,
337 			       Block *b4, Side s4,
338 			       double fontScale);
339 
340   friend class Line;
341 };
342 
343   }
344 }
345 
346 #endif // RENDER_BLOCK_H_
347