├── .gitignore ├── .travis.yml ├── CHANGELOG ├── LICENSE ├── README.md ├── build.sbt ├── doc ├── devel │ ├── boxes.xmi │ ├── boxes_simple.xmi │ └── stacks.ods ├── examples │ ├── README │ ├── example.bat │ └── example.sh ├── manual │ ├── box_classes.png │ ├── doc.xsl │ ├── doc_php.xsl │ ├── gen │ ├── index.php │ ├── manual.css │ ├── manual.html │ └── manual.xml └── pic │ ├── floats.svg │ └── inline.svg ├── project ├── build.properties └── plugins.sbt └── src └── main ├── java └── org │ └── fit │ └── cssbox │ ├── css │ ├── CSSNorm.java │ ├── CSSUnits.java │ ├── DOMAnalyzer.java │ ├── HTMLNorm.java │ ├── NormalOutput.java │ └── Output.java │ ├── demo │ ├── BoxBrowser.java │ ├── ComputeStyles.java │ ├── ImageRenderer.java │ ├── SimpleBrowser.java │ └── TextBoxes.java │ ├── io │ ├── DOMSource.java │ ├── DefaultDOMSource.java │ ├── DefaultDocumentSource.java │ ├── DocumentSource.java │ └── StreamDocumentSource.java │ ├── layout │ ├── BackgroundImage.java │ ├── BlockBox.java │ ├── BlockReplacedBox.java │ ├── BlockTableBox.java │ ├── Box.java │ ├── BoxFactory.java │ ├── BrowserCanvas.java │ ├── BrowserConfig.java │ ├── CSSDecoder.java │ ├── ContentImage.java │ ├── ElementBox.java │ ├── FloatList.java │ ├── HTMLBoxFactory.java │ ├── Inline.java │ ├── InlineBlockBox.java │ ├── InlineBlockReplacedBox.java │ ├── InlineBox.java │ ├── InlineElement.java │ ├── InlineReplacedBox.java │ ├── LengthSet.java │ ├── LineBox.java │ ├── ListItemBox.java │ ├── ReplacedBox.java │ ├── ReplacedContent.java │ ├── ReplacedImage.java │ ├── ReplacedText.java │ ├── StackingContext.java │ ├── TableBodyBox.java │ ├── TableBox.java │ ├── TableCaptionBox.java │ ├── TableCellBox.java │ ├── TableColumn.java │ ├── TableColumnGroup.java │ ├── TableRowBox.java │ ├── TextBox.java │ ├── Viewport.java │ └── VisualContext.java │ ├── misc │ ├── Base64Coder.java │ └── CSSStroke.java │ └── render │ ├── BoxRenderer.java │ ├── GraphicsRenderer.java │ └── SVGRenderer.java └── resources └── logback.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | 3 | /target 4 | /lib_managed 5 | /project/boot 6 | /project/build/target 7 | /project/plugins/target 8 | /project/plugins/lib_managed 9 | /project/plugins/src_managed 10 | /project/project 11 | /project/target 12 | /src/main/generated 13 | /.cache 14 | /.project 15 | /.classpath 16 | /.settings 17 | /.idea 18 | /.iml 19 | /.idea_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | script: "sbt test" -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2013-12-05 - Version 4.3 2 | - Basic support for rendering form fields using CSS (closes #37) 3 | - vertical-align support for tables (closes #21) 4 | - text-indent support 5 | - clip support 6 | - Support for attr() function in content CSS property 7 | - Logback framework used for logging (closes #25) 8 | - Replaced box size computation fixes 9 | - Static position computation reworked 10 | - Table layout fixes (closes #34) 11 | - Better API for font sizes (closes #35) 12 | 13 | 2013-05-25 - Version 4.2 14 | - Drawing text decorations (underline and line-through) (closes #12) 15 | - z-index and stacking context support 16 | - text-transform support 17 | - Positioned boxes in viewport fixed (closes #11) 18 | - Do not load HTML objects when data URL is not specified (closes #15) 19 | - Table layout computation fix (closes #18) 20 | - Custom default font configuration 21 | - List item marker drawing fixes 22 | 23 | 2013-01-22 - Version 4.1 24 | - New I/O framework and connetcion handling API (see the manual) 25 | - Support for data: URLs 26 | - Embedded object support 27 | - Optimized image loading 28 | - Default charset detection for referenced style sheets 29 | - HTML tag support in CSS analyzer 30 | - Relative positioning not limited to block elements 31 | - Canvas size computation fixes 32 | - Fix inline positioning around floating boxes 33 | - Fixed behavior of replaced boxes in table cells 34 | - Replaced box size computation fixes (percentage widths and heights) 35 | - Border drawing fix (null pointer with 0-width or 0-height boxes) 36 | - Table cell position computation and footer rendering fix 37 | - Table row organization fix (closes #3545215) 38 | - Fixed floating box position inside of relatively positioned boxes 39 | - Whitespace processing fixes 40 | - Anchor handling 41 | 42 | 2012-06-18 - Version 4.0 43 | - Background image support 44 | - Reworked configuration API (static configuration removed) 45 | - Minor bugfixes 46 | 47 | 2012-06-08 - Version 3.5 48 | - Improved performance (faster style computation, less rendering phases) 49 | - Support for style sheet origin specification (for priority computation) 50 | - White-space property support (including 'pre' and 'nowrap' modes) 51 | - Viewport and block width computation fixes 52 | - Fixed processing of the presentational HTML attributes (mainly for tables) 53 | - Line alignment bugfixes 54 | 55 | 2011-12-06 - Version 3.4 56 | - Support for display:inline-block layout 57 | - Vertical alignment fixed for the "top" and "bottom" values 58 | - Whitespace processing fixes 59 | - API extension for accessing list properties 60 | - Block width computation fixes 61 | - Image loading improvements 62 | 63 | 2011-06-09 - Version 3.3 64 | - Fixes in table column width computation 65 | - Table background color computation adjusted 66 | 67 | 2011-02-08 - Version 3.2 68 | - Improvements and fixes in the DOM structure analysis 69 | - Fixed static position determination for absolutely positioned boxes 70 | - Small documentation updates 71 | 72 | 2011-01-24 - Version 3.1 73 | - table layout algorithm fixes 74 | - line height computation reworked 75 | - vertical alignment reworked 76 | - new box tree creation algorithm 77 | - whitespace processing improvements 78 | - border rendering reworked 79 | - static position determination fixed 80 | 81 | 2009-12-03 - Version 3.0 82 | - new margin collapsing algorithm 83 | - removed the jTidy dependency. Now, any DOM Traversal capable DOM implementation may be used. 84 | - visibility inheritance fixed 85 | - font-weight processing updated 86 | - license change to LGPLv3 87 | 88 | 2009-03-04 - Version 2.2 89 | - New ImageRenderer tools that stores the rendered document in PNG or SVG 90 | - New box clipping implementation (overflow: hidden) 91 | - Box width computation fixes 92 | - Layout fixes for absolutely positioned elements 93 | - New ReplaceBox interface for joining the inline and block ones 94 | 95 | 2009-01-29 - Version 2.1 96 | - Box size computation fixes (absolutely positioned boxes) 97 | - Floating block positioning fixes 98 | - Other small bugfixes 99 | 100 | 2008-12-22 - Version 2.0 101 | CSSBox 2.0 introduces a brand new CSS parser - jStyleParser. 102 | This parser is much more efficient and reliable than the 103 | previous 'naive' parser based on the CSS Parser project. 104 | 105 | Most Important Changes in the CSSBox API 106 | ---------------------------------------- 107 | 108 | - if the DOMAnalyzer.attributesToStyles() method is used for 109 | interpreting HTML visual attributes, it must be called 110 | BEFORE calling the DOMAnalyzer.getStyleSheets() method -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/philborlin/CSSBox.png)](https://travis-ci.org/philborlin/CSSBox) 2 | 3 | CSSBox 4 | ============ 5 | 6 | CSSBox is an (X)HTML/CSS rendering engine written in pure Java. Its primary purpose is to provide a complete and further processable 7 | information about the rendered page contents and layout. However, it may be also used for browsing the rendered documents in Java Swing applications. 8 | 9 | The input of the rendering engine is the document DOM tree and a set of style sheets referenced from the document. 10 | The output is an object-oriented model of the page layout. This model can be directly displayed but mainly, it is suitable for further processing 11 | by the layout analysis algorithms as for example the page segmentation or information extraction algorithms. 12 | 13 | The core CSSBox library may be also used for obtaining a bitmap or vector (SVG) image of the rendered document. Using the SwingBox package, 14 | CSSBox may be used as an interactive web browser component in a Java Swing application. 15 | 16 | See the CHANGELOG for the most important changes to the previous versions. 17 | 18 | All the source code of CSSBox itself is licensed under the GNU Lesser General 19 | Public License (LGPL), version 3. A copy of the LGPL can be found 20 | in the LICENSE file. 21 | 22 | Building 23 | -------- 24 | 25 | - CSSBox uses [sbt 0.13](http://www.scala-sbt.org/release/docs/Getting-Started/Setup.html) 26 | to build the project. 27 | - Use `sbt compile` to compile the project 28 | - Use `sbt test` to run the tests 29 | - Use `sbt eclipse` to create an Eclipse project that can be imported using `Import Existing Projects into Workspace` 30 | 31 | Required Libraries 32 | ------------------ 33 | CSSBox relies on the [jStyleParser](https://github.com/philborlin/jStyleParser) open source CSS parser 34 | 35 | In the demos contained in the org.fit.cssbox.demo package, the 36 | [NekoHTML parser](http://nekohtml.sourceforge.net/) is used for creating the DOM tree. 37 | As an alternative, the The [Validator.nu HTML Parser](http://about.validator.nu/htmlparser/) 38 | has been tested with CSSBox too. 39 | 40 | The Xerces library may be replaced by any other DOM implementation. 41 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | organization := "org.fit.cssbox" 2 | 3 | name := "CSSBox" 4 | 5 | version := "4.3" 6 | 7 | homepage := Some(url("https://github.com/philborlin/CSSBox")) 8 | 9 | licenses += ("GNU Lesser General Public License, version 3.0", url("http://opensource.org/licenses/lgpl-3.0.html")) 10 | 11 | scmInfo := Some(ScmInfo(url("https://github.com/philborlin/CSSBox.git"), "scm:git@github.com:philborlin/CSSBox.git")) 12 | 13 | // Dependencies 14 | libraryDependencies ++= Seq( 15 | "net.sourceforge.nekohtml" % "nekohtml" % "1.9.19", 16 | "xerces" % "xercesImpl" % "2.11.0", 17 | "xml-apis" % "xml-apis" % "1.0.b2", 18 | "cz.vutbr" % "jstyleparser" % "1.14" 19 | ) 20 | 21 | // Testing 22 | libraryDependencies ++= Seq( 23 | "com.novocode" % "junit-interface" % "0.10" % "test" 24 | ) 25 | 26 | // Logging 27 | libraryDependencies ++= Seq( 28 | "ch.qos.logback" % "logback-classic" % "1.0.13", 29 | "ch.qos.logback" % "logback-core" % "1.0.13", 30 | "org.slf4j" % "slf4j-api" % "1.7.5" 31 | ) 32 | 33 | javacOptions ++= Seq("-encoding", "utf-8") 34 | 35 | EclipseKeys.projectFlavor := EclipseProjectFlavor.Java 36 | 37 | unmanagedSourceDirectories in Compile <<= (javaSource in Compile)(Seq(_)) 38 | 39 | unmanagedSourceDirectories in Test <<= (javaSource in Test)(Seq(_)) 40 | 41 | publishTo := Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") 42 | 43 | pomIncludeRepository := { _ => false } 44 | 45 | autoScalaLibrary := false 46 | 47 | crossPaths := false 48 | 49 | pomExtra := ( 50 | 51 | 52 | radkovo 53 | Radek Burget 54 | http://www.fit.vutbr.cz/~burgetr 55 | 56 | 57 | ) -------------------------------------------------------------------------------- /doc/devel/stacks.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philborlin/CSSBox/a15df249c7ec15ad7e9d3994dc57d61c11e23d5f/doc/devel/stacks.ods -------------------------------------------------------------------------------- /doc/examples/README: -------------------------------------------------------------------------------- 1 | Running the Examples 2 | -------------------- 3 | The examples are implemented in the org.fit.cssbox.demo package. For running the 4 | examples, following jar files must be in the classpath: 5 | - CSSBox.jar -- the CSSBox library 6 | - lib/*.jar -- the CSS and HTML parsers 7 | 8 | For convenience, scripts are provided for running the examples. For Unix, example.sh 9 | should be used, for Windows, there is the example.bat batch file. The example 10 | name must be specified as the first argument, other arguments depend on the example. 11 | E.g.: 12 | 13 | ./example.sh SimpleBrowser http://www.cnn.com/ 14 | 15 | 16 | Available Examples 17 | ------------------ 18 | 19 | ComputeStyles 20 | This example computes the effective style of each element and encodes it into the 21 | "style" attribute of this element. The modified HTML document is then saved 22 | to the output file. 23 | 24 | TextBoxes 25 | Shows how the rendered box tree can be accessed. It renders the document 26 | and prints the list of text boxes together with their positions on the page. 27 | 28 | SimpleBrowser 29 | An example of using CSSBox for the HTML page rendering and display. It parses 30 | the style sheets and creates, box tree describing the final layout and displays 31 | the resulting document. 32 | 33 | BoxBrowser 34 | Implements a browser that displays the rendered box tree and the corresponding 35 | page. Each box corresponds to an HTML element or a text node and it can be 36 | interactiveli highlighted documents either by selecting a tree node or by clicking 37 | the appropriate position in the page. 38 | 39 | ImageRenderer 40 | Renders a document at the specified URL and stores the document image to the specified file. 41 | Supported formats: 42 | png: a Portable Network Graphics file (bitmap image) 43 | svg: a SVG file (vector image with bitmap images included) 44 | -------------------------------------------------------------------------------- /doc/examples/example.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if not "%1"=="" GOTO cont 4 | echo Usage: example.bat ExampleClassName arguments 5 | echo See the documentation for the available examples 6 | GOTO end 7 | 8 | :cont 9 | set CLASSPATH=%CLASSPATH%;..\..\CSSBox.jar 10 | set CLASSPATH=%CLASSPATH%;..\..\lib\antlr-runtime-3.1.jar 11 | set CLASSPATH=%CLASSPATH%;..\..\lib\slf4j-api-1.5.2.jar 12 | set CLASSPATH=%CLASSPATH%;..\..\lib\jStyleParser_SNAPSHOT.jar 13 | set CLASSPATH=%CLASSPATH%;..\..\lib\nekohtml.jar 14 | set CLASSPATH=%CLASSPATH%;..\..\lib\xercesImpl.jar 15 | set CLASSPATH=%CLASSPATH%;..\..\lib\xml-apis.jar 16 | set CLASSPATH=%CLASSPATH%;..\..\lib\logback-classic-0.9.9.jar 17 | set CLASSPATH=%CLASSPATH%;..\..\lib\logback-core-0.9.9.jar 18 | 19 | java org.fit.cssbox.demo.%1 %2 %3 %4 20 | 21 | 22 | :end 23 | 24 | -------------------------------------------------------------------------------- /doc/examples/example.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ $# -lt 1 ]; then 3 | echo "Usage: example.sh " 4 | echo "See the documentation for the available examples" 5 | exit 6 | fi 7 | 8 | ROOT="../.." 9 | 10 | DEPS=$ROOT/CSSBox.jar 11 | DEPS=$DEPS:$ROOT/lib/antlr-runtime-3.1.jar 12 | DEPS=$DEPS:$ROOT/lib/slf4j-api-1.5.2.jar 13 | DEPS=$DEPS:$ROOT/lib/jStyleParser_SNAPSHOT.jar 14 | DEPS=$DEPS:$ROOT/lib/nekohtml.jar 15 | DEPS=$DEPS:$ROOT/lib/xercesImpl.jar 16 | DEPS=$DEPS:$ROOT/lib/xml-apis.jar 17 | DEPS=$DEPS:$ROOT/lib/logback-classic-0.9.9.jar 18 | DEPS=$DEPS:$ROOT/lib/logback-core-0.9.9.jar 19 | 20 | export CLASSPATH=$CLASSPATH:$DEPS 21 | java org.fit.cssbox.demo.$1 $2 $3 $4 22 | -------------------------------------------------------------------------------- /doc/manual/box_classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philborlin/CSSBox/a15df249c7ec15ad7e9d3994dc57d61c11e23d5f/doc/manual/box_classes.png -------------------------------------------------------------------------------- /doc/manual/doc.xsl: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | <xsl:value-of select="doc:title" /> 17 | 18 | 23 | 24 | 25 |

26 |

27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 |

Table of Contents

44 | 72 |
73 |
74 | 75 | 76 |
77 | 78 |

79 | 80 |
81 |
82 | 83 | 84 |
85 | 86 |

87 | 88 |
89 |
90 | 91 | 92 |
93 | 94 |

95 | 96 |
97 |
98 | 99 | 100 |
101 |
102 |     			
103 |     		
104 |
105 |
106 | 107 | 108 |

109 | 110 |

111 |
112 | 113 | 114 | 115 | 116 | ../api/ 117 | 118 | 119 | 120 | .html 121 | 122 | 123 | index.html 124 | 125 | 126 | 127 | # 128 | 129 | 130 | 131 | api 132 | 133 | 134 | 135 | 136 | 137 | 138 | < 139 | 140 | > 141 | 142 | 143 | 144 | 145 | 146 | 147 | # 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
156 | 157 | 158 | 159 | 160 |

161 | Figure 162 | 163 | : 164 | 165 |

166 |
167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 |
181 | -------------------------------------------------------------------------------- /doc/manual/doc_php.xsl: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | <? 14 | require "../include/page.php"; 15 | make_header("documentation", "Manual", "../", "@import \"manual.css\";"); 16 | ?> 17 |

18 |

19 | 20 | [ Downloadable version ] 21 |

22 | 23 | 24 | <? 25 | make_footer(); 26 | ?> 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |

Table of Contents

40 | 68 |
69 |
70 | 71 | 72 |
73 | 74 |

75 | 76 |
77 |
78 | 79 | 80 |
81 | 82 |

83 | 84 |
85 |
86 | 87 | 88 |
89 | 90 |

91 | 92 |
93 |
94 | 95 | 96 |
97 |
 98 |     			
 99 |     		
100 |
101 |
102 | 103 | 104 |

105 | 106 |

107 |
108 | 109 | 110 | 111 | 112 | ../api/ 113 | 114 | 115 | 116 | .html 117 | 118 | 119 | index.html 120 | 121 | 122 | 123 | # 124 | 125 | 126 | 127 | api 128 | 129 | 130 | 131 | 132 | 133 | 134 | < 135 | 136 | > 137 | 138 | 139 | 140 | 141 | 142 | 143 | # 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 |
152 | 153 | 154 | 155 | 156 |

157 | Figure 158 | 159 | : 160 | 161 |

162 |
163 |
164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
177 | -------------------------------------------------------------------------------- /doc/manual/gen: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | xsltproc doc.xsl manual.xml >manual.html 3 | xsltproc doc_php.xsl manual.xml >index.php 4 | -------------------------------------------------------------------------------- /doc/manual/manual.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial, sans-serif; 3 | font-size: medium; 4 | } 5 | 6 | h2, h3, h4 { 7 | padding: 0; 8 | margin: 1.5em 0 0.5em 0; 9 | } 10 | 11 | .toc { 12 | float: left; 13 | padding: 1em; 14 | margin: 1em 1em 1em 0; 15 | border: 1px solid black; 16 | background-color: #eee; 17 | } 18 | 19 | .toc h2 { 20 | margin: 0 0 0.5em 0; 21 | } 22 | 23 | .toc ul { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | .toc li { 29 | list-style-type: none; 30 | margin: 0 0 0.5em 0; 31 | padding: 0; 32 | } 33 | 34 | .toc li li { 35 | margin-left: 2em; 36 | margin-bottom: 0em; 37 | font-size: 90%; 38 | } 39 | 40 | #basic { 41 | clear: left; 42 | } 43 | 44 | .code { 45 | margin: 0.5em; 46 | padding: 0.5em; 47 | border: 1px solid blue; 48 | background-color: #eef; 49 | } 50 | 51 | .code pre { 52 | margin: 0; 53 | padding: 0; 54 | white-space: pre-wrap; 55 | } 56 | 57 | .subsection { 58 | margin-left: 1em; 59 | } 60 | 61 | .subsubsection { 62 | margin-left: 1em; 63 | } 64 | 65 | .figure { 66 | text-align: center; 67 | margin: 1.5em 0; 68 | } 69 | 70 | .author { 71 | text-indent: 0; 72 | } -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.0 -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += "Typesafe Repository (releases)" at "http://repo.typesafe.com/typesafe/releases/" 2 | 3 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0") -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/css/CSSUnits.java: -------------------------------------------------------------------------------- 1 | /* 2 | * CSSUnits.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 31. leden 2005, 15:49 19 | */ 20 | 21 | package org.fit.cssbox.css; 22 | 23 | import java.awt.GraphicsEnvironment; 24 | import java.awt.Toolkit; 25 | 26 | import cz.vutbr.web.css.CSSProperty; 27 | 28 | /** 29 | * CSS unit conversion functions. 30 | * 31 | * @author burgetr 32 | */ 33 | public class CSSUnits 34 | { 35 | //public static final double dpi = 100; //100 DPI display 36 | public static final double dpi = GraphicsEnvironment.isHeadless() ? 100 : Toolkit.getDefaultToolkit().getScreenResolution(); 37 | public static final double medium_font = 16; //16px 38 | private static final double font_step = 1.2; 39 | public static final int THIN_BORDER = 1; 40 | public static final int MEDIUM_BORDER = 3; 41 | public static final int THICK_BORDER = 5; 42 | 43 | /** Converts points to pixels according to the DPI set */ 44 | public static double pixels(double pt) 45 | { 46 | return pt * dpi / 72.0; 47 | } 48 | 49 | /** Converts pixels to points according to the DPI set */ 50 | public static double points(double px) 51 | { 52 | return px * 72.0 / dpi; 53 | } 54 | 55 | /** 56 | * Converts the font size given by an identifier to absolute length in pixels. 57 | * @param parent Parent font size (taken as 1em) 58 | * @param value The size specification to be converted 59 | * @return absolute font size in px 60 | */ 61 | public static double convertFontSize(double parent, CSSProperty.FontSize value) 62 | { 63 | double em = parent; 64 | double ret = em; 65 | if (value == CSSProperty.FontSize.MEDIUM) 66 | ret = medium_font; 67 | else if (value == CSSProperty.FontSize.SMALL) 68 | ret = medium_font / font_step; 69 | else if (value == CSSProperty.FontSize.X_SMALL) 70 | ret = medium_font / font_step / font_step; 71 | else if (value == CSSProperty.FontSize.XX_SMALL) 72 | ret = medium_font / font_step / font_step / font_step; 73 | else if (value == CSSProperty.FontSize.LARGE) 74 | ret = medium_font * font_step; 75 | else if (value == CSSProperty.FontSize.X_LARGE) 76 | ret = medium_font * font_step * font_step; 77 | else if (value == CSSProperty.FontSize.XX_LARGE) 78 | ret = medium_font * font_step * font_step * font_step; 79 | else if (value == CSSProperty.FontSize.SMALLER) 80 | ret = em / font_step; 81 | else if (value == CSSProperty.FontSize.LARGER) 82 | ret = em * font_step; 83 | return ret; 84 | } 85 | 86 | /** 87 | * Converts the border size given by an identifier to an absolute value. 88 | * @param width the border-width identifier 89 | * @return absolute length in pixels 90 | */ 91 | public static int convertBorderWidth(CSSProperty.BorderWidth width) 92 | { 93 | if (width == CSSProperty.BorderWidth.THIN) 94 | return THIN_BORDER; 95 | else if (width == CSSProperty.BorderWidth.MEDIUM) 96 | return MEDIUM_BORDER; 97 | else 98 | return THICK_BORDER; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/css/NormalOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * NormalOutput.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 30. leden 2005, 19:02 19 | */ 20 | 21 | package org.fit.cssbox.css; 22 | 23 | import org.w3c.dom.*; 24 | 25 | /** 26 | * An output generator that outputs the DOM tree in a standard (xml) way 27 | * 28 | * @author radek 29 | */ 30 | public class NormalOutput extends Output 31 | { 32 | 33 | public NormalOutput(Node root) 34 | { 35 | super(root); 36 | } 37 | 38 | /** 39 | * Formats the complete tag tree to an output stream 40 | */ 41 | public void dumpTo(java.io.PrintStream out) 42 | { 43 | recursiveDump(root, 0, out); 44 | } 45 | 46 | //======================================================================== 47 | 48 | private void recursiveDump(Node n, int level, java.io.PrintStream p) 49 | { 50 | //Opening tag 51 | if (n.getNodeType() == Node.ELEMENT_NODE) 52 | { 53 | String tag = ""; 54 | Element el = (Element) n; 55 | //do not dump original style definitions 56 | if (el.getTagName().equals("style")) 57 | return; 58 | if (el.getTagName().equals("link") && 59 | (el.getAttribute("rel").equalsIgnoreCase("stylesheet") || 60 | el.getAttribute("type").equalsIgnoreCase("text/css"))) 61 | return; 62 | //Replace meta generator 63 | if (el.getTagName().equals("meta") && el.getAttribute("name").equals("generator")) 64 | el.setAttribute("content", "CSS Transformer by Radek Burget, burgetr@fit.vutbr.cz"); 65 | //Dump the tag 66 | tag = tag + "<" + el.getTagName(); 67 | NamedNodeMap attrs = el.getAttributes(); 68 | for (int i = 0; i < attrs.getLength(); i++) 69 | { 70 | Node attr = attrs.item(i); 71 | tag = tag + " " + attr.getNodeName() + "=\"" + attr.getNodeValue() + "\""; 72 | } 73 | tag = tag + ">"; 74 | p.print(tag); 75 | } 76 | else if (n.getNodeType() == Node.TEXT_NODE) 77 | { 78 | p.print(n.getNodeValue()); 79 | } 80 | 81 | NodeList child = n.getChildNodes(); 82 | for (int i = 0; i < child.getLength(); i++) 83 | recursiveDump(child.item(i), level+1, p); 84 | 85 | //Closing tag 86 | if (n.getNodeType() == Node.ELEMENT_NODE) 87 | { 88 | //if (n.getNodeName().equals("head")) 89 | // p.print(""); 90 | p.print(""); 91 | } 92 | } 93 | 94 | @SuppressWarnings("unused") 95 | private void recursiveDumpNice(Node n, int level, java.io.PrintStream p) 96 | { 97 | 98 | //Opening tag 99 | if (n.getNodeType() == Node.ELEMENT_NODE) 100 | { 101 | String tag = ""; 102 | Element el = (Element) n; 103 | if (el.getTagName().equals("style")) 104 | return; 105 | tag = tag + "<" + el.getTagName(); 106 | NamedNodeMap attrs = el.getAttributes(); 107 | for (int i = 0; i < attrs.getLength(); i++) 108 | { 109 | Node attr = attrs.item(i); 110 | tag = tag + " " + attr.getNodeName() + "=\"" + attr.getNodeValue() + "\""; 111 | } 112 | tag = tag + ">"; 113 | indent(level, p); 114 | p.println(tag); 115 | } 116 | else if (n.getNodeType() == Node.TEXT_NODE) 117 | { 118 | indent(level, p); 119 | p.println(n.getNodeValue()); 120 | } 121 | 122 | NodeList child = n.getChildNodes(); 123 | for (int i = 0; i < child.getLength(); i++) 124 | recursiveDumpNice(child.item(i), level+1, p); 125 | 126 | //Closing tag 127 | if (n.getNodeType() == Node.ELEMENT_NODE) 128 | { 129 | indent(level, p); 130 | p.println(""); 131 | } 132 | } 133 | 134 | private void indent(int level, java.io.PrintStream p) 135 | { 136 | String ind = ""; 137 | for (int i = 0; i < level*4; i++) ind = ind + ' '; 138 | p.print(ind); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/css/Output.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Output.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 30. leden 2005, 18:59 19 | */ 20 | 21 | package org.fit.cssbox.css; 22 | 23 | import org.w3c.dom.Node; 24 | 25 | /** 26 | * Abstract class that represents any document output implementation. 27 | * 28 | * @author radek 29 | */ 30 | public abstract class Output 31 | { 32 | protected Node root; 33 | 34 | public Output(Node root) 35 | { 36 | this.root = root; 37 | } 38 | 39 | public abstract void dumpTo(java.io.PrintStream out); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/demo/ComputeStyles.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ComputeStyles.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 13.11.2007, 15:44:42 by burgetr 19 | */ 20 | package org.fit.cssbox.demo; 21 | 22 | import java.io.FileOutputStream; 23 | import java.io.PrintStream; 24 | 25 | import org.fit.cssbox.css.CSSNorm; 26 | import org.fit.cssbox.css.DOMAnalyzer; 27 | import org.fit.cssbox.css.NormalOutput; 28 | import org.fit.cssbox.css.Output; 29 | import org.fit.cssbox.io.DOMSource; 30 | import org.fit.cssbox.io.DefaultDOMSource; 31 | import org.fit.cssbox.io.DefaultDocumentSource; 32 | import org.fit.cssbox.io.DocumentSource; 33 | import org.w3c.dom.Document; 34 | 35 | 36 | /** 37 | * This example computes the effective style of each element and encodes it into the 38 | * style attribute of this element. The modified HTML document is then saved 39 | * to the output file. 40 | * 41 | * @author burgetr 42 | */ 43 | public class ComputeStyles 44 | { 45 | 46 | /** 47 | * @param args 48 | */ 49 | public static void main(String[] args) 50 | { 51 | if (args.length != 2) 52 | { 53 | System.err.println("Usage: ComputeStyles "); 54 | System.exit(0); 55 | } 56 | 57 | try { 58 | //Open the network connection 59 | DocumentSource docSource = new DefaultDocumentSource(args[0]); 60 | 61 | //Parse the input document 62 | DOMSource parser = new DefaultDOMSource(docSource); 63 | Document doc = parser.parse(); 64 | 65 | //Create the CSS analyzer 66 | DOMAnalyzer da = new DOMAnalyzer(doc, docSource.getURL()); 67 | da.attributesToStyles(); //convert the HTML presentation attributes to inline styles 68 | da.addStyleSheet(null, CSSNorm.stdStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the standard style sheet 69 | da.addStyleSheet(null, CSSNorm.userStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the additional style sheet 70 | da.getStyleSheets(); //load the author style sheets 71 | 72 | //Compute the styles 73 | System.err.println("Computing style..."); 74 | da.stylesToDomInherited(); 75 | 76 | //Save the output 77 | PrintStream os = new PrintStream(new FileOutputStream(args[1])); 78 | Output out = new NormalOutput(doc); 79 | out.dumpTo(os); 80 | os.close(); 81 | 82 | docSource.close(); 83 | 84 | System.err.println("Done."); 85 | 86 | } catch (Exception e) { 87 | System.err.println("Error: "+e.getMessage()); 88 | e.printStackTrace(); 89 | } 90 | 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/demo/ImageRenderer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Renderer.java 3 | * Copyright (c) 2005-2009 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 5.2.2009, 12:00:02 by burgetr 19 | */ 20 | package org.fit.cssbox.demo; 21 | 22 | import java.awt.Font; 23 | import java.io.FileOutputStream; 24 | import java.io.IOException; 25 | import java.io.OutputStream; 26 | import java.io.OutputStreamWriter; 27 | import java.io.Writer; 28 | 29 | import javax.imageio.ImageIO; 30 | 31 | import org.fit.cssbox.css.CSSNorm; 32 | import org.fit.cssbox.css.DOMAnalyzer; 33 | import org.fit.cssbox.io.DOMSource; 34 | import org.fit.cssbox.io.DefaultDOMSource; 35 | import org.fit.cssbox.io.DefaultDocumentSource; 36 | import org.fit.cssbox.io.DocumentSource; 37 | import org.fit.cssbox.layout.BrowserCanvas; 38 | import org.fit.cssbox.layout.BrowserConfig; 39 | import org.fit.cssbox.layout.Viewport; 40 | import org.fit.cssbox.render.SVGRenderer; 41 | import org.w3c.dom.Document; 42 | import org.xml.sax.SAXException; 43 | 44 | /** 45 | * This class provides a rendering interface for obtaining the document image 46 | * form an URL. 47 | * 48 | * @author burgetr 49 | */ 50 | public class ImageRenderer 51 | { 52 | public static final short TYPE_PNG = 0; 53 | public static final short TYPE_SVG = 1; 54 | 55 | private boolean loadImages = true; 56 | private boolean loadBackgroundImages = true; 57 | 58 | public void setLoadImages(boolean content, boolean background) 59 | { 60 | loadImages = content; 61 | loadBackgroundImages = background; 62 | } 63 | 64 | /** 65 | * Renders the URL and prints the result to the specified output stream in the specified 66 | * format. 67 | * @param urlstring the source URL 68 | * @param out output stream 69 | * @param type output type, one of the TYPE_XXX constants 70 | * @return true in case of success, false otherwise 71 | * @throws SAXException 72 | */ 73 | public boolean renderURL(String urlstring, OutputStream out, short type) throws IOException, SAXException 74 | { 75 | if (!urlstring.startsWith("http:") && 76 | !urlstring.startsWith("ftp:") && 77 | !urlstring.startsWith("file:")) 78 | urlstring = "http://" + urlstring; 79 | 80 | //Open the network connection 81 | DocumentSource docSource = new DefaultDocumentSource(urlstring); 82 | 83 | //Parse the input document 84 | DOMSource parser = new DefaultDOMSource(docSource); 85 | Document doc = parser.parse(); 86 | 87 | //Create the CSS analyzer 88 | DOMAnalyzer da = new DOMAnalyzer(doc, docSource.getURL()); 89 | da.attributesToStyles(); //convert the HTML presentation attributes to inline styles 90 | da.addStyleSheet(null, CSSNorm.stdStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the standard style sheet 91 | da.addStyleSheet(null, CSSNorm.userStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the additional style sheet 92 | da.addStyleSheet(null, CSSNorm.formsStyleSheet(), DOMAnalyzer.Origin.AGENT); //render form fields using css 93 | da.getStyleSheets(); //load the author style sheets 94 | 95 | if (type == TYPE_PNG) 96 | { 97 | BrowserCanvas contentCanvas = new BrowserCanvas(da.getRoot(), da, docSource.getURL()); 98 | contentCanvas.getConfig().setLoadImages(loadImages); 99 | contentCanvas.getConfig().setLoadBackgroundImages(loadBackgroundImages); 100 | contentCanvas.createLayout(new java.awt.Dimension(1200, 600)); 101 | ImageIO.write(contentCanvas.getImage(), "png", out); 102 | } 103 | else if (type == TYPE_SVG) 104 | { 105 | BrowserCanvas contentCanvas = new BrowserCanvas(da.getRoot(), da, docSource.getURL()); 106 | contentCanvas.getConfig().setLoadImages(loadImages); 107 | contentCanvas.getConfig().setLoadBackgroundImages(loadBackgroundImages); 108 | setDefaultFonts(contentCanvas.getConfig()); 109 | contentCanvas.createLayout(new java.awt.Dimension(1200, 600)); 110 | Writer w = new OutputStreamWriter(out, "utf-8"); 111 | writeSVG(contentCanvas.getViewport(), w); 112 | w.close(); 113 | } 114 | 115 | docSource.close(); 116 | 117 | return true; 118 | } 119 | 120 | /** 121 | * Sets some common fonts as the defaults for generic font families. 122 | */ 123 | protected void setDefaultFonts(BrowserConfig config) 124 | { 125 | config.setDefaultFont(Font.SERIF, "Times New Roman"); 126 | config.setDefaultFont(Font.SANS_SERIF, "Arial"); 127 | config.setDefaultFont(Font.MONOSPACED, "Courier New"); 128 | } 129 | 130 | /** 131 | * Renders the viewport using an SVGRenderer to the given output writer. 132 | * @param vp 133 | * @param out 134 | * @throws IOException 135 | */ 136 | protected void writeSVG(Viewport vp, Writer out) throws IOException 137 | { 138 | int w = vp.getContentWidth(); 139 | int h = vp.getContentHeight(); 140 | 141 | SVGRenderer render = new SVGRenderer(w, h, out); 142 | vp.draw(render); 143 | render.close(); 144 | } 145 | 146 | //================================================================================= 147 | 148 | public static void main(String[] args) 149 | { 150 | if (args.length != 3) 151 | { 152 | System.err.println("Usage: ImageRenderer "); 153 | System.err.println(); 154 | System.err.println("Renders a document at the specified URL and stores the document image"); 155 | System.err.println("to the specified file."); 156 | System.err.println("Supported formats:"); 157 | System.err.println("png: a Portable Network Graphics file (bitmap image)"); 158 | System.err.println("svg: a SVG file (vector image)"); 159 | System.exit(0); 160 | } 161 | 162 | try { 163 | short type = -1; 164 | if (args[2].equalsIgnoreCase("png")) 165 | type = TYPE_PNG; 166 | else if (args[2].equalsIgnoreCase("svg")) 167 | type = TYPE_SVG; 168 | else 169 | { 170 | System.err.println("Error: unknown format"); 171 | System.exit(0); 172 | } 173 | 174 | FileOutputStream os = new FileOutputStream(args[1]); 175 | 176 | ImageRenderer r = new ImageRenderer(); 177 | r.renderURL(args[0], os, type); 178 | 179 | os.close(); 180 | System.err.println("Done."); 181 | } catch (Exception e) { 182 | System.err.println("Error: " + e.getMessage()); 183 | } 184 | 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/demo/SimpleBrowser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SimpleBrowser.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | */ 19 | 20 | package org.fit.cssbox.demo; 21 | 22 | import java.awt.event.MouseEvent; 23 | import java.awt.event.MouseListener; 24 | import java.net.URL; 25 | 26 | import org.fit.cssbox.css.CSSNorm; 27 | import org.fit.cssbox.css.DOMAnalyzer; 28 | import org.fit.cssbox.io.DOMSource; 29 | import org.fit.cssbox.io.DefaultDOMSource; 30 | import org.fit.cssbox.io.DefaultDocumentSource; 31 | import org.fit.cssbox.io.DocumentSource; 32 | import org.fit.cssbox.layout.BrowserCanvas; 33 | import org.w3c.dom.Document; 34 | import org.w3c.dom.Element; 35 | 36 | 37 | /** 38 | * An example of using CSSBox for the HTML page rendering and display. 39 | * It parses the style sheets and creates a box tree describing the 40 | * final layout. As the HTML parser, jTidy is used. 41 | * 42 | * @author burgetr 43 | */ 44 | public class SimpleBrowser extends javax.swing.JFrame 45 | { 46 | private static final long serialVersionUID = -1336331141597077348L; 47 | 48 | /** The swing canvas for displaying the rendered document */ 49 | private javax.swing.JPanel browserCanvas; 50 | 51 | /** Scroll pane for the canvas */ 52 | private javax.swing.JScrollPane documentScroll; 53 | 54 | /** Root DOM Element of the document body */ 55 | private Element docroot; 56 | 57 | /** The CSS analyzer of the DOM tree */ 58 | private DOMAnalyzer decoder; 59 | 60 | 61 | /** 62 | * Creates a new application window and displays the rendered document 63 | * @param root The root DOM element of the document body 64 | * @param baseurl The base URL of the document used for completing the relative paths 65 | * @param decoder The CSS analyzer that provides the effective style of the elements 66 | */ 67 | public SimpleBrowser(Element root, URL baseurl, DOMAnalyzer decoder) 68 | { 69 | docroot = root; 70 | this.decoder = decoder; 71 | initComponents(baseurl); 72 | } 73 | 74 | /** 75 | * Creates and initializes the GUI components 76 | * @param baseurl The base URL of the document used for completing the relative paths 77 | */ 78 | private void initComponents(URL baseurl) 79 | { 80 | documentScroll = new javax.swing.JScrollPane(); 81 | 82 | //Create the browser canvas 83 | browserCanvas = new BrowserCanvas(docroot, decoder, new java.awt.Dimension(1000, 600), baseurl); 84 | 85 | //A simple mouse listener that displays the coordinates clicked 86 | browserCanvas.addMouseListener(new MouseListener() { 87 | public void mouseClicked(MouseEvent e) 88 | { 89 | System.out.println("Click: " + e.getX() + ":" + e.getY()); 90 | } 91 | public void mousePressed(MouseEvent e) { } 92 | public void mouseReleased(MouseEvent e) { } 93 | public void mouseEntered(MouseEvent e) { } 94 | public void mouseExited(MouseEvent e) { } 95 | }); 96 | 97 | getContentPane().setLayout(new java.awt.GridLayout(1, 0)); 98 | 99 | setTitle("CSSBox Browser"); 100 | addWindowListener(new java.awt.event.WindowAdapter() { 101 | public void windowClosing(java.awt.event.WindowEvent evt) { 102 | exitForm(evt); 103 | } 104 | }); 105 | 106 | documentScroll.setViewportView(browserCanvas); 107 | getContentPane().add(documentScroll); 108 | pack(); 109 | } 110 | 111 | /** 112 | * Exit the Application 113 | */ 114 | private void exitForm(java.awt.event.WindowEvent evt) 115 | { 116 | System.exit(0); 117 | } 118 | 119 | /** 120 | * @param args the command line arguments 121 | */ 122 | public static void main(String args[]) 123 | { 124 | if (args.length != 1) 125 | { 126 | System.err.println("Usage: SimpleBrowser "); 127 | System.exit(0); 128 | } 129 | 130 | try { 131 | //Open the network connection 132 | DocumentSource docSource = new DefaultDocumentSource(args[0]); 133 | 134 | //Parse the input document 135 | DOMSource parser = new DefaultDOMSource(docSource); 136 | Document doc = parser.parse(); 137 | 138 | //Create the CSS analyzer 139 | DOMAnalyzer da = new DOMAnalyzer(doc, docSource.getURL()); 140 | da.attributesToStyles(); //convert the HTML presentation attributes to inline styles 141 | da.addStyleSheet(null, CSSNorm.stdStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the standard style sheet 142 | da.addStyleSheet(null, CSSNorm.userStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the additional style sheet 143 | da.addStyleSheet(null, CSSNorm.formsStyleSheet(), DOMAnalyzer.Origin.AGENT); //render form fields using css 144 | da.getStyleSheets(); //load the author style sheets 145 | 146 | //Display the result 147 | SimpleBrowser test = new SimpleBrowser(da.getRoot(), docSource.getURL(), da); 148 | test.setSize(1275, 750); 149 | test.setVisible(true); 150 | 151 | docSource.close(); 152 | 153 | } catch (Exception e) { 154 | System.out.println("Error: "+e.getMessage()); 155 | e.printStackTrace(); 156 | } 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/demo/TextBoxes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TextBoxes.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 13.11.2007, 14:34:04 by burgetr 19 | */ 20 | package org.fit.cssbox.demo; 21 | 22 | import org.fit.cssbox.css.CSSNorm; 23 | import org.fit.cssbox.css.DOMAnalyzer; 24 | import org.fit.cssbox.io.DOMSource; 25 | import org.fit.cssbox.io.DefaultDOMSource; 26 | import org.fit.cssbox.io.DefaultDocumentSource; 27 | import org.fit.cssbox.io.DocumentSource; 28 | import org.fit.cssbox.layout.Box; 29 | import org.fit.cssbox.layout.BrowserCanvas; 30 | import org.fit.cssbox.layout.ElementBox; 31 | import org.fit.cssbox.layout.TextBox; 32 | import org.w3c.dom.Document; 33 | 34 | 35 | /** 36 | * This demo shows how the rendered box tree can be accessed. It renders the document 37 | * and prints the list of text boxes together with their positions on the page. 38 | * 39 | * @author burgetr 40 | */ 41 | public class TextBoxes 42 | { 43 | 44 | /** 45 | * Recursively prints the text boxes from the specified tree 46 | */ 47 | private static void printTextBoxes(Box root) 48 | { 49 | if (root instanceof TextBox) 50 | { 51 | //text boxes are just printed 52 | TextBox text = (TextBox) root; 53 | System.out.println("x=" + text.getAbsoluteBounds().x + " y=" + text.getAbsoluteBounds().y + " text=" + text.getText()); 54 | } 55 | else if (root instanceof ElementBox) 56 | { 57 | //element boxes must be just traversed 58 | ElementBox el = (ElementBox) root; 59 | for (int i = el.getStartChild(); i < el.getEndChild(); i++) 60 | printTextBoxes(el.getSubBox(i)); 61 | } 62 | } 63 | 64 | /** 65 | * main method 66 | */ 67 | public static void main(String[] args) 68 | { 69 | if (args.length != 1) 70 | { 71 | System.err.println("Usage: TextBoxes "); 72 | System.exit(0); 73 | } 74 | 75 | try { 76 | //Open the network connection 77 | DocumentSource docSource = new DefaultDocumentSource(args[0]); 78 | 79 | //Parse the input document 80 | DOMSource parser = new DefaultDOMSource(docSource); 81 | Document doc = parser.parse(); 82 | 83 | //Create the CSS analyzer 84 | DOMAnalyzer da = new DOMAnalyzer(doc, docSource.getURL()); 85 | da.attributesToStyles(); //convert the HTML presentation attributes to inline styles 86 | da.addStyleSheet(null, CSSNorm.stdStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the standard style sheet 87 | da.addStyleSheet(null, CSSNorm.userStyleSheet(), DOMAnalyzer.Origin.AGENT); //use the additional style sheet 88 | da.getStyleSheets(); //load the author style sheets 89 | 90 | //Create the browser canvas 91 | BrowserCanvas browser = new BrowserCanvas(da.getRoot(), da, docSource.getURL()); 92 | //Disable the image loading 93 | browser.getConfig().setLoadImages(false); 94 | browser.getConfig().setLoadBackgroundImages(false); 95 | 96 | //Create the layout for 1000x600 pixels 97 | browser.createLayout(new java.awt.Dimension(1000, 600)); 98 | 99 | //Display the result 100 | printTextBoxes(browser.getViewport()); 101 | 102 | docSource.close(); 103 | 104 | } catch (Exception e) { 105 | System.err.println("Error: "+e.getMessage()); 106 | e.printStackTrace(); 107 | } 108 | 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/io/DOMSource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * DOMSource.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 22.11.2012, 19:01:10 by burgetr 19 | */ 20 | 21 | package org.fit.cssbox.io; 22 | 23 | import java.io.IOException; 24 | 25 | import org.w3c.dom.Document; 26 | import org.xml.sax.SAXException; 27 | 28 | /** 29 | * An abstraction of a parser that is able to obtain a DOM. 30 | * 31 | * @author burgetr 32 | */ 33 | public abstract class DOMSource 34 | { 35 | protected DocumentSource src; 36 | protected String charset; 37 | 38 | public DOMSource(DocumentSource src) 39 | { 40 | this.src = src; 41 | setContentType(src.getContentType()); 42 | } 43 | 44 | public DocumentSource getDocumentSource() 45 | { 46 | return src; 47 | } 48 | 49 | public String getCharset() 50 | { 51 | return charset; 52 | } 53 | 54 | public void setContentType(String type) 55 | { 56 | if (type != null) 57 | { 58 | String t = type.toLowerCase(); 59 | 60 | //extract the charset if specified 61 | int strt = t.indexOf("charset="); 62 | if (strt >= 0) 63 | { 64 | strt += "charset=".length(); 65 | int stop = t.indexOf(';', strt); 66 | if (stop == -1) 67 | stop = t.length(); 68 | charset = t.substring(strt, stop).trim(); 69 | charset = charset.replaceAll("^\"|\"$|^\'|\'$", "").trim(); 70 | } 71 | } 72 | } 73 | 74 | abstract public Document parse() throws SAXException, IOException; 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/io/DefaultDOMSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DefaultDOMSource.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 22.11.2012, 19:44:34 by burgetr 19 | */ 20 | package org.fit.cssbox.io; 21 | 22 | import java.io.IOException; 23 | 24 | import org.apache.xerces.parsers.DOMParser; 25 | import org.cyberneko.html.HTMLConfiguration; 26 | import org.w3c.dom.Document; 27 | import org.xml.sax.SAXException; 28 | 29 | /** 30 | * A default CSSBox DOM parser implementation using the NekoHTML parser. 31 | * 32 | * @author burgetr 33 | */ 34 | public class DefaultDOMSource extends DOMSource 35 | { 36 | 37 | public DefaultDOMSource(DocumentSource src) 38 | { 39 | super(src); 40 | } 41 | 42 | @Override 43 | public Document parse() throws SAXException, IOException 44 | { 45 | DOMParser parser = new DOMParser(new HTMLConfiguration()); 46 | parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower"); 47 | if (charset != null) 48 | parser.setProperty("http://cyberneko.org/html/properties/default-encoding", charset); 49 | parser.parse(new org.xml.sax.InputSource(getDocumentSource().getInputStream())); 50 | return parser.getDocument(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/io/DefaultDocumentSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DefaultDocumentSource.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 23.11.2012, 9:28:33 by burgetr 19 | */ 20 | package org.fit.cssbox.io; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.net.URL; 25 | import java.net.URLConnection; 26 | 27 | import org.fit.net.DataURLHandler; 28 | 29 | /** 30 | * This class implements the document source with the standard {@link java.net.URLConnection} 31 | * with an additional support for the data: URLs. 32 | * 33 | * @author burgetr 34 | */ 35 | public class DefaultDocumentSource extends DocumentSource 36 | { 37 | /** The user-agent string used for HTTP connection */ 38 | private static String USER_AGENT = "Mozilla/5.0 (compatible; BoxBrowserTest/4.x; Linux) CSSBox/4.x (like Gecko)"; 39 | 40 | private URLConnection con; 41 | private InputStream is; 42 | 43 | /** 44 | * Creates a network data source based on the target document URL. 45 | * @param url the document URL 46 | * @throws IOException 47 | */ 48 | public DefaultDocumentSource(URL url) throws IOException 49 | { 50 | super(url); 51 | con = createConnection(url); 52 | is = null; 53 | } 54 | 55 | /** 56 | * Creates a data source based on the URL string. The data: urls are automatically 57 | * recognized and processed. 58 | * @param urlstring The URL string 59 | * @throws IOException 60 | */ 61 | public DefaultDocumentSource(String urlstring) throws IOException 62 | { 63 | super(null, urlstring); 64 | URL url = DataURLHandler.createURL(null, urlstring); 65 | con = createConnection(url); 66 | is = null; 67 | } 68 | 69 | /** 70 | * Creates a data source based on the URL string. The data: urls are automatically 71 | * recognized and processed. 72 | * @param base The base URL to be used for the relative URLs in the urlstring 73 | * @param urlstring The URL string 74 | * @throws IOException 75 | */ 76 | public DefaultDocumentSource(URL base, String urlstring) throws IOException 77 | { 78 | super(base, urlstring); 79 | URL url = DataURLHandler.createURL(base, urlstring); 80 | con = createConnection(url); 81 | is = null; 82 | } 83 | 84 | /** 85 | * Creates and configures the URL connection. 86 | * @param url the target URL 87 | * @return the created connection instance 88 | * @throws IOException 89 | */ 90 | protected URLConnection createConnection(URL url) throws IOException 91 | { 92 | URLConnection con = url.openConnection(); 93 | con.setRequestProperty("User-Agent", USER_AGENT); 94 | return con; 95 | } 96 | 97 | @Override 98 | public URL getURL() 99 | { 100 | return con.getURL(); 101 | } 102 | 103 | @Override 104 | public InputStream getInputStream() throws IOException 105 | { 106 | if (is == null) 107 | is = con.getInputStream(); 108 | return is; 109 | } 110 | 111 | @Override 112 | public String getContentType() 113 | { 114 | return con.getHeaderField("Content-Type"); 115 | } 116 | 117 | /** 118 | * Obtains the current User-agent string used for new connections. 119 | * @return the user-agent string. 120 | */ 121 | public static String getUserAgent() 122 | { 123 | return USER_AGENT; 124 | } 125 | 126 | /** 127 | * Sets the user agent string that will be used for new connections. 128 | * @param userAgent the user-agent string 129 | */ 130 | public static void setUserAgent(String userAgent) 131 | { 132 | USER_AGENT = userAgent; 133 | } 134 | 135 | @Override 136 | public void close() throws IOException 137 | { 138 | if (is != null) 139 | is.close(); 140 | } 141 | 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/io/DocumentSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DocumentSource.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 23.11.2012, 9:18:54 by burgetr 19 | */ 20 | package org.fit.cssbox.io; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.net.URL; 25 | 26 | /** 27 | * This class creates an abstraction of a document source that is able to 28 | * obtain a document based on its URL. 29 | * 30 | * @author burgetr 31 | */ 32 | public abstract class DocumentSource 33 | { 34 | 35 | /** 36 | * Creates a new document source from an URL. 37 | * @param url the document URL 38 | * @throws IOException 39 | */ 40 | public DocumentSource(URL url) throws IOException 41 | { 42 | } 43 | 44 | /** 45 | * Creates a new document source based on a string representation of the URL. 46 | * @param urlstring the URL string 47 | * @throws IOException 48 | */ 49 | public DocumentSource(URL base, String urlstring) throws IOException 50 | { 51 | } 52 | 53 | /** 54 | * Obtains the final URL of the obtained document. This URL may be different 55 | * from the URL used for DocumentSource construction, e.g. when some HTTP redirect 56 | * occurs. 57 | * @return the document URL. 58 | */ 59 | abstract public URL getURL(); 60 | 61 | /** 62 | * Obtains the MIME content type of the target document. 63 | * @return a MIME string. 64 | */ 65 | abstract public String getContentType(); 66 | 67 | /** 68 | * Obtains the input stream for reading the referenced document. 69 | * @return The input stream. 70 | * @throws IOException 71 | */ 72 | abstract public InputStream getInputStream() throws IOException; 73 | 74 | /** 75 | * Closes the document source. 76 | */ 77 | abstract public void close() throws IOException; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/io/StreamDocumentSource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * StreamDocumentSource.java 3 | * 4 | * Created on 19.12.2012, 15:07:56 by burgetr 5 | */ 6 | package org.fit.cssbox.io; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.net.URL; 11 | 12 | import org.fit.cssbox.io.DocumentSource; 13 | 14 | /** 15 | * A dummy implementation of the document source for encapsulating an already created input stream 16 | * and the additional parametres. 17 | * 18 | * @author burgetr 19 | */ 20 | public class StreamDocumentSource extends DocumentSource 21 | { 22 | private URL url; 23 | private String ctype; 24 | private InputStream is; 25 | 26 | /** 27 | * Creates the document source from the input stream. 28 | * @param is the input stream 29 | * @param url the base URL to be used with the data source 30 | * @param contentType stream content type 31 | * @throws IOException 32 | */ 33 | public StreamDocumentSource(InputStream is, URL url, String contentType) throws IOException 34 | { 35 | super(url); 36 | this.url = url; 37 | this.ctype = contentType; 38 | this.is = is; 39 | } 40 | 41 | @Override 42 | public URL getURL() 43 | { 44 | return url; 45 | } 46 | 47 | @Override 48 | public String getContentType() 49 | { 50 | return ctype; 51 | } 52 | 53 | @Override 54 | public InputStream getInputStream() throws IOException 55 | { 56 | return is; 57 | } 58 | 59 | @Override 60 | public void close() throws IOException 61 | { 62 | is.close(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/BackgroundImage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BackgroundImage.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 11.6.2012, 14:47:16 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | import java.awt.Rectangle; 24 | import java.awt.image.BufferedImage; 25 | import java.net.URL; 26 | 27 | import javax.swing.ImageIcon; 28 | 29 | import cz.vutbr.web.css.CSSProperty; 30 | import cz.vutbr.web.css.CSSProperty.BackgroundAttachment; 31 | import cz.vutbr.web.css.CSSProperty.BackgroundPosition; 32 | import cz.vutbr.web.css.CSSProperty.BackgroundRepeat; 33 | import cz.vutbr.web.css.TermLengthOrPercent; 34 | import cz.vutbr.web.css.TermList; 35 | 36 | /** 37 | * An image placed at the element background together with its position and repeating. 38 | * 39 | * @author burgetr 40 | */ 41 | public class BackgroundImage extends ContentImage 42 | { 43 | private CSSProperty.BackgroundPosition position; 44 | private CSSProperty.BackgroundRepeat repeat; 45 | private CSSProperty.BackgroundAttachment attachment; 46 | private TermList positionValues; 47 | 48 | //the coordinates of the image within the element 49 | private int imgx; 50 | private int imgy; 51 | private boolean repeatx; 52 | private boolean repeaty; 53 | 54 | 55 | public BackgroundImage(ElementBox owner, URL url, BackgroundPosition position, TermList positionValues, BackgroundRepeat repeat, BackgroundAttachment attachment) 56 | { 57 | super(owner); 58 | this.loadImages = owner.getViewport().getConfig().getLoadBackgroundImages(); 59 | this.url = url; 60 | this.position = position; 61 | this.positionValues = positionValues; 62 | this.repeat = repeat; 63 | this.attachment = attachment; 64 | if (loadImages) 65 | image = loadImage(caching); 66 | repeatx = (repeat == BackgroundRepeat.REPEAT || repeat == BackgroundRepeat.REPEAT_X); 67 | repeaty = (repeat == BackgroundRepeat.REPEAT || repeat == BackgroundRepeat.REPEAT_Y); 68 | } 69 | 70 | public CSSProperty.BackgroundPosition getPosition() 71 | { 72 | return position; 73 | } 74 | 75 | public CSSProperty.BackgroundRepeat getRepeat() 76 | { 77 | return repeat; 78 | } 79 | 80 | public CSSProperty.BackgroundAttachment getAttachment() 81 | { 82 | return attachment; 83 | } 84 | 85 | //=========================================================================== 86 | 87 | @Override 88 | public void draw(Graphics2D g, int width, int height) 89 | { 90 | Rectangle bounds = getOwner().getAbsoluteBackgroundBounds(); 91 | computeCoordinates(bounds); 92 | g.drawImage(image, bounds.x + imgx, bounds.y + imgy, observer); 93 | } 94 | 95 | @Override 96 | public BufferedImage getBufferedImage() 97 | { 98 | if (image == null || abort) 99 | return null; 100 | 101 | //image = new ImageIcon(image).getImage(); 102 | image = loadImage(caching); 103 | 104 | Rectangle bounds = getOwner().getAbsoluteBackgroundBounds(); 105 | if (bounds.width > 0 && bounds.height > 0) 106 | { 107 | computeCoordinates(bounds); 108 | BufferedImage img = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_ARGB); 109 | Graphics2D g = img.createGraphics(); 110 | 111 | if (repeatx && repeaty) 112 | drawRepeatBoth(g, imgx, imgy, bounds.width, bounds.height); 113 | else if (repeatx) 114 | drawRepeatX(g, imgx, imgy, bounds.width); 115 | else if (repeaty) 116 | drawRepeatY(g, imgx, imgy, bounds.height); 117 | else 118 | g.drawImage(image, imgx, imgy, observer); 119 | 120 | g.dispose(); 121 | 122 | return img; 123 | } 124 | else 125 | return null; 126 | } 127 | 128 | private void drawRepeatX(Graphics2D g, int sx, int sy, int limit) 129 | { 130 | int width = getIntrinsicWidth(); 131 | if (width == 0) width = 1; 132 | for (int x = sx; x < limit; x += width) 133 | g.drawImage(image, x, sy, observer); 134 | for (int x = sx - width; x + width - 1 >= 0; x -= width) 135 | g.drawImage(image, x, sy, observer); 136 | 137 | } 138 | 139 | private void drawRepeatY(Graphics2D g, int sx, int sy, int limit) 140 | { 141 | int height = getIntrinsicHeight(); 142 | if (height == 0) height = 1; 143 | for (int y = sy; y < limit; y += height) 144 | g.drawImage(image, sx, y, observer); 145 | for (int y = sy - height; y + height - 1 >= 0; y -= height) 146 | g.drawImage(image, sx, y, observer); 147 | 148 | } 149 | 150 | private void drawRepeatBoth(Graphics2D g, int sx, int sy, int limitx, int limity) 151 | { 152 | int height = getIntrinsicHeight(); 153 | if (height == 0) height = 1; 154 | for (int y = sy; y < limity; y += height) 155 | drawRepeatX(g, sx, y, limitx); 156 | for (int y = sy - height; y + height - 1 >= 0; y -= height) 157 | drawRepeatX(g, sx, y, limitx); 158 | } 159 | 160 | 161 | //=========================================================================== 162 | 163 | /** 164 | * @return true if the image is repeated in the X direction 165 | */ 166 | public boolean isRepeatX() 167 | { 168 | return repeatx; 169 | } 170 | 171 | /** 172 | * @return true if the image is repeated in the Y direction 173 | */ 174 | public boolean isRepeatY() 175 | { 176 | return repeaty; 177 | } 178 | 179 | /** 180 | * @return the imgx 181 | */ 182 | public int getImgX() 183 | { 184 | return imgx; 185 | } 186 | 187 | /** 188 | * @return the imgy 189 | */ 190 | public int getImgY() 191 | { 192 | return imgy; 193 | } 194 | 195 | /** 196 | * Computes the image coordinates within the padding box of the element. 197 | * After this, the coordinates may be obtained using {@link #getImgX()} and {@link #getImgY()}. 198 | */ 199 | public void computeCoordinates() 200 | { 201 | computeCoordinates(getOwner().getAbsoluteBackgroundBounds()); 202 | } 203 | 204 | protected void computeCoordinates(Rectangle bounds) 205 | { 206 | CSSDecoder dec = new CSSDecoder(getOwner().getVisualContext()); 207 | 208 | //X position 209 | if (position == BackgroundPosition.LEFT) 210 | imgx = 0; 211 | else if (position == BackgroundPosition.RIGHT) 212 | imgx = bounds.width - getIntrinsicWidth(); 213 | else if (position == BackgroundPosition.CENTER) 214 | imgx = (bounds.width - getIntrinsicWidth()) / 2; 215 | else if (position == BackgroundPosition.list_values) 216 | { 217 | imgx = dec.getLength((TermLengthOrPercent) positionValues.get(0), false, 0, 0, bounds.width - getIntrinsicWidth()); 218 | } 219 | else 220 | imgx = 0; 221 | 222 | //Y position 223 | if (position == BackgroundPosition.TOP) 224 | imgy = 0; 225 | else if (position == BackgroundPosition.BOTTOM) 226 | imgy = bounds.height - getIntrinsicHeight(); 227 | else if (position == BackgroundPosition.CENTER) 228 | imgy = (bounds.height - getIntrinsicHeight()) / 2; 229 | else if (position == BackgroundPosition.list_values) 230 | { 231 | int i = positionValues.size() > 1 ? 1 : 0; 232 | imgy = dec.getLength((TermLengthOrPercent) positionValues.get(i), false, 0, 0, bounds.height - getIntrinsicHeight()); 233 | } 234 | else 235 | imgy = 0; 236 | 237 | //System.out.println(url + ": x=" + imgx + " y=" + imgy); 238 | } 239 | 240 | 241 | 242 | 243 | } 244 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/BlockReplacedBox.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BlockReplacedBox.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 27.9.2006, 22:08:12 by radek 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | import java.awt.Rectangle; 24 | import java.awt.Shape; 25 | 26 | import org.w3c.dom.Element; 27 | 28 | /** 29 | * Replaced block box. 30 | * @author radek 31 | */ 32 | public class BlockReplacedBox extends BlockBox implements ReplacedBox 33 | { 34 | protected int boxw; //image width attribute 35 | protected int boxh; //image height attribute 36 | protected ReplacedContent obj; //the contained object 37 | 38 | /** 39 | * Creates a new instance of BlockReplacedBox 40 | */ 41 | public BlockReplacedBox(Element el, Graphics2D g, VisualContext ctx) 42 | { 43 | super(el, g, ctx); 44 | } 45 | 46 | /** 47 | * Creates a new instance of from an inline variant 48 | */ 49 | public BlockReplacedBox(InlineReplacedBox src) 50 | { 51 | super(src); 52 | this.boxw = src.boxw; 53 | this.boxh = src.boxh; 54 | setContentObj(src.obj); 55 | } 56 | 57 | /** 58 | * @return the content object 59 | */ 60 | public ReplacedContent getContentObj() 61 | { 62 | return obj; 63 | } 64 | 65 | /** 66 | * @param obj the obj to set 67 | */ 68 | public void setContentObj(ReplacedContent obj) 69 | { 70 | this.obj = obj; 71 | isempty = (obj == null); 72 | if (!isempty) 73 | obj.setOwner(this); 74 | } 75 | 76 | @Override 77 | public int getMaximalWidth() 78 | { 79 | return boxw + declMargin.left + padding.left + border.left + 80 | declMargin.right + padding.right + border.right; 81 | } 82 | 83 | @Override 84 | public int getMinimalWidth() 85 | { 86 | return boxw + declMargin.left + padding.left + border.left + 87 | declMargin.right + padding.right + border.right; 88 | } 89 | 90 | @Override 91 | public Rectangle getMinimalAbsoluteBounds() 92 | { 93 | return new Rectangle(getAbsoluteContentX(), getAbsoluteContentY(), boxw, boxh); 94 | } 95 | 96 | @Override 97 | public boolean isWhitespace() 98 | { 99 | return false; 100 | } 101 | 102 | @Override 103 | public boolean isReplaced() 104 | { 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean doLayout(int availw, boolean force, boolean linestart) 110 | { 111 | //Skip if not displayed 112 | if (!displayed) 113 | { 114 | content.setSize(0, 0); 115 | bounds.setSize(0, 0); 116 | return true; 117 | } 118 | 119 | setAvailableWidth(availw); 120 | int wlimit = getAvailableContentWidth(); 121 | if (getWidth() <= wlimit) 122 | return true; 123 | else 124 | return force; 125 | } 126 | 127 | @Override 128 | protected void loadSizes(boolean update) 129 | { 130 | super.loadSizes(update); 131 | Rectangle objsize = CSSDecoder.computeReplacedObjectSize(obj, this); 132 | content.width = boxw = objsize.width; 133 | content.height = boxh = objsize.height; 134 | bounds.setSize(totalWidth(), totalHeight()); 135 | preferredWidth = getWidth(); 136 | wset = true; 137 | hset = true; 138 | } 139 | 140 | @Override 141 | public boolean hasFixedHeight() 142 | { 143 | return true; 144 | } 145 | 146 | @Override 147 | public boolean hasFixedWidth() 148 | { 149 | return true; 150 | } 151 | 152 | @Override 153 | protected boolean separatedFromTop(ElementBox box) 154 | { 155 | return true; 156 | } 157 | 158 | @Override 159 | protected boolean separatedFromBottom(ElementBox box) 160 | { 161 | return true; 162 | } 163 | 164 | public void drawContent(Graphics2D g) 165 | { 166 | if (obj != null) 167 | { 168 | Shape oldclip = g.getClip(); 169 | g.setClip(applyClip(oldclip, getClippedContentBounds())); 170 | obj.draw(g, boxw, boxh); 171 | g.setClip(oldclip); 172 | } 173 | } 174 | 175 | @Override 176 | public void draw(DrawStage turn) 177 | { 178 | if (isDisplayed() && isDeclaredVisible()) 179 | { 180 | if (!this.formsStackingContext()) 181 | { 182 | switch (turn) 183 | { 184 | case DRAW_NONINLINE: 185 | if (floating == FLOAT_NONE) 186 | { 187 | getViewport().getRenderer().renderElementBackground(this); 188 | } 189 | break; 190 | case DRAW_FLOAT: 191 | if (floating != FLOAT_NONE) 192 | { 193 | getViewport().getRenderer().renderElementBackground(this); 194 | getViewport().getRenderer().startElementContents(this); 195 | getViewport().getRenderer().renderReplacedContent(this); 196 | getViewport().getRenderer().finishElementContents(this); 197 | } 198 | break; 199 | case DRAW_INLINE: 200 | if (floating == FLOAT_NONE) 201 | { 202 | getViewport().getRenderer().startElementContents(this); 203 | getViewport().getRenderer().renderReplacedContent(this); 204 | getViewport().getRenderer().finishElementContents(this); 205 | } 206 | } 207 | } 208 | } 209 | } 210 | 211 | @Override 212 | public void drawStackingContext(boolean include) 213 | { 214 | if (isDisplayed() && isDeclaredVisible()) 215 | { 216 | //1.the background and borders of the element forming the stacking context. 217 | if (this.isBlock()) 218 | getViewport().getRenderer().renderElementBackground(this); 219 | 220 | getViewport().getRenderer().startElementContents(this); 221 | //2.the child stacking contexts with negative stack levels (most negative first). 222 | //3.the in-flow, non-inline-level, non-positioned descendants. 223 | //4.the non-positioned floats. 224 | //5.the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks. 225 | getViewport().getRenderer().renderReplacedContent(this); 226 | //6.the child stacking contexts with stack level 0 and the positioned descendants with stack level 0. 227 | //7.the child stacking contexts with positive stack levels (least positive first). 228 | getViewport().getRenderer().finishElementContents(this); 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/BlockTableBox.java: -------------------------------------------------------------------------------- 1 | /** 2 | * BlockTableBox.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 8.10.2009, 16:33:31 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | import java.util.Iterator; 24 | 25 | import cz.vutbr.web.css.CSSFactory; 26 | import cz.vutbr.web.css.CSSProperty; 27 | import cz.vutbr.web.css.TermLength; 28 | import cz.vutbr.web.css.TermLengthOrPercent; 29 | 30 | import org.w3c.dom.Element; 31 | 32 | /** 33 | * This class represents the anonymous box created for a block-level table. 34 | * @author burgetr 35 | */ 36 | public class BlockTableBox extends BlockBox 37 | { 38 | private TableBox table; 39 | private TableCaptionBox caption; 40 | private boolean captionbottom; //set to true, when caption should be in the bottom. Otherwise, caption is at the top. 41 | 42 | public BlockTableBox(Element n, Graphics2D g, VisualContext ctx) 43 | { 44 | super(n, g, ctx); 45 | isblock = true; 46 | } 47 | 48 | /** 49 | * Create a new table from an inline box 50 | */ 51 | public BlockTableBox(InlineBox src) 52 | { 53 | super(src); 54 | isblock = true; 55 | } 56 | 57 | /** 58 | * @return the caption 59 | */ 60 | public TableCaptionBox getCaption() 61 | { 62 | return caption; 63 | } 64 | 65 | /** 66 | * @param caption the caption to set 67 | */ 68 | public void setCaption(TableCaptionBox caption) 69 | { 70 | this.caption = caption; 71 | } 72 | 73 | /** 74 | * @return the table 75 | */ 76 | public TableBox getTable() 77 | { 78 | return table; 79 | } 80 | 81 | /** 82 | * @param table the table to set 83 | */ 84 | public void setTable(TableBox table) 85 | { 86 | this.table = table; 87 | } 88 | 89 | //====================================================================================================== 90 | 91 | @Override 92 | public void initBox() 93 | { 94 | organizeContent(); //organize the child elements according to their display property 95 | loadCaptionStyle(); 96 | } 97 | 98 | @Override 99 | public boolean canIncreaseWidth() 100 | { 101 | return true; 102 | } 103 | 104 | @Override 105 | public boolean doLayout(int availw, boolean force, boolean linestart) 106 | { 107 | setAvailableWidth(availw); 108 | int x1 = fleft.getWidth(floatY) - floatXl; 109 | int x2 = fright.getWidth(floatY) - floatXr; 110 | if (x1 < 0) x1 = 0; 111 | if (x2 < 0) x2 = 0; 112 | int wlimit = getAvailableContentWidth() - x1 - x2; 113 | int tabwidth = 0; 114 | int tabheight = 0; 115 | int capheight = 0; 116 | int capwidth = 0; 117 | 118 | //format the table 119 | BlockLayoutStatus stat = new BlockLayoutStatus(); 120 | table.setAvailableWidth(wlimit); 121 | table.updateSizes(); 122 | layoutBlockInFlow(table, wlimit, stat); 123 | tabwidth = stat.maxw; 124 | tabheight = stat.y; 125 | 126 | //format the caption 127 | if (caption != null) 128 | { 129 | stat.y = 0; 130 | caption.setAvailableWidth(stat.maxw); 131 | caption.updateSizes(); 132 | layoutBlockInFlow(caption, stat.maxw, stat); 133 | capwidth = stat.maxw; 134 | capheight = stat.y; 135 | if (captionbottom) //place the caption below or above 136 | { 137 | table.setPosition(x1, 0); 138 | caption.setPosition(x1, tabheight); 139 | } 140 | else 141 | { 142 | caption.setPosition(x1, 0); 143 | table.setPosition(x1, capheight); 144 | } 145 | } 146 | else 147 | table.setPosition(x1, 0); 148 | 149 | setContentWidth(Math.max(tabwidth, capwidth)); 150 | setContentHeight(tabheight + capheight); 151 | widthComputed = true; 152 | updateSizes(); 153 | setSize(totalWidth(), totalHeight()); 154 | return true; 155 | } 156 | 157 | @Override 158 | public int getMaximalWidth() 159 | { 160 | if (caption == null) 161 | return table.getMaximalWidth(); 162 | else 163 | return Math.max(table.getMaximalWidth(), caption.getMaximalWidth()); 164 | } 165 | 166 | @Override 167 | public int getMinimalWidth() 168 | { 169 | if (caption == null) 170 | return table.getMinimalWidth(); 171 | else 172 | return Math.max(table.getMinimalWidth(), caption.getMinimalWidth()); 173 | } 174 | 175 | @Override 176 | protected int getMaximalContentWidth() 177 | { 178 | if (caption == null) 179 | return table.getMaximalContentWidth(); 180 | else 181 | return Math.max(table.getMaximalContentWidth(), caption.getMaximalContentWidth()); 182 | } 183 | 184 | @Override 185 | protected int getMinimalContentWidth() 186 | { 187 | if (caption == null) 188 | return table.getMinimalContentWidth(); 189 | else 190 | return Math.max(table.getMinimalContentWidth(), caption.getMinimalContentWidth()); 191 | } 192 | 193 | @Override 194 | protected void loadBackground() 195 | { 196 | //anonymous table box has never a background 197 | bgcolor = null; 198 | } 199 | 200 | @Override 201 | protected void loadBorders(CSSDecoder dec, int contw) 202 | { 203 | //anonymous table box has never a border 204 | border = new LengthSet(); 205 | } 206 | 207 | @Override 208 | protected void loadPadding(CSSDecoder dec, int contw) 209 | { 210 | //anonymous table box has never a padding 211 | padding = new LengthSet(); 212 | } 213 | 214 | @Override 215 | protected void computeWidths(TermLengthOrPercent width, boolean auto, boolean exact, BlockBox cblock, boolean update) 216 | { 217 | //anonymous table box has always an 'auto' width in the beginning. After the layout, the width is updated according 218 | //the resulting table (and caption) width 219 | if (!widthComputed) 220 | super.computeWidths(null, true, exact, cblock, update); 221 | else 222 | super.computeWidths(CSSFactory.getTermFactory().createLength((float) content.width, TermLength.Unit.px), false, exact, cblock, update); 223 | } 224 | 225 | 226 | //====================================================================================================== 227 | 228 | protected void loadCaptionStyle() 229 | { 230 | CSSProperty.CaptionSide side = style.getProperty("caption-side"); 231 | captionbottom = (side == CSSProperty.CaptionSide.BOTTOM); 232 | } 233 | 234 | /** 235 | * Goes through the list of child boxes and organizes them into captions, header, 236 | * footer, etc. 237 | */ 238 | private void organizeContent() 239 | { 240 | table = new TableBox(el, g, ctx); 241 | table.adoptParent(this); 242 | table.setStyle(style); 243 | 244 | for (Iterator it = nested.iterator(); it.hasNext(); ) 245 | { 246 | Box box = it.next(); 247 | if (box instanceof TableCaptionBox) 248 | { 249 | caption = (TableCaptionBox) box; 250 | } 251 | else //other elements belong to the table itself 252 | { 253 | table.addSubBox(box); 254 | box.setContainingBlock(table); 255 | box.setParent(table); 256 | it.remove(); 257 | endChild--; 258 | } 259 | } 260 | 261 | addSubBox(table); 262 | } 263 | 264 | } 265 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/BrowserCanvas.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BrowserCanvas.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 13. z��� 2005, 15:44 19 | */ 20 | 21 | package org.fit.cssbox.layout; 22 | 23 | import java.awt.*; 24 | import java.awt.image.*; 25 | import java.net.URL; 26 | 27 | import javax.swing.*; 28 | 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | import org.w3c.dom.*; 32 | 33 | import org.fit.cssbox.css.DOMAnalyzer; 34 | import org.fit.cssbox.render.GraphicsRenderer; 35 | 36 | /** 37 | * This class provides an abstraction of a browser rendering area and the main layout engine 38 | * interface. Afrer the layout, a document image is created by drawing all the boxes and it 39 | * is drawn on the component. 40 | * 41 | * @author burgetr 42 | */ 43 | public class BrowserCanvas extends JPanel 44 | { 45 | private static final long serialVersionUID = -8715215920271505397L; 46 | private static Logger log = LoggerFactory.getLogger(BrowserCanvas.class); 47 | 48 | protected Element root; 49 | protected DOMAnalyzer decoder; 50 | protected URL baseurl; 51 | protected Viewport viewport; 52 | 53 | protected BufferedImage img; 54 | 55 | protected BrowserConfig config; 56 | protected boolean createImage; 57 | protected boolean autoSizeUpdate; 58 | 59 | /** 60 | * Creates a new instance of the browser engine for a document. After creating the engine, 61 | * the layout itself may be computed by calling {@link #createLayout(Dimension)}. 62 | * @param root the <body> element of the document to be rendered 63 | * @param decoder the CSS decoder used to compute the style 64 | * @param baseurl the document base URL 65 | */ 66 | public BrowserCanvas(org.w3c.dom.Element root, DOMAnalyzer decoder, URL baseurl) 67 | { 68 | this.root = root; 69 | this.decoder = decoder; 70 | this.baseurl = baseurl; 71 | this.config = new BrowserConfig(); 72 | this.createImage = true; 73 | this.autoSizeUpdate = true; 74 | } 75 | 76 | /** 77 | * Creates a new instance of the browser engine for a document and creates the layout. 78 | * 79 | * @param root the <body> element of the document to be rendered 80 | * @param decoder the CSS decoder used to compute the style 81 | * @param dim the viewport dimensions 82 | * @param baseurl the document base URL 83 | */ 84 | public BrowserCanvas(org.w3c.dom.Element root, 85 | DOMAnalyzer decoder, 86 | Dimension dim, URL baseurl) 87 | { 88 | this(root, decoder, baseurl); 89 | createLayout(dim); 90 | } 91 | 92 | /** 93 | * Obtains the current browser configuration. 94 | * @return current configuration. 95 | */ 96 | public BrowserConfig getConfig() 97 | { 98 | return config; 99 | } 100 | 101 | /** 102 | * Sets the browser configuration used for rendering. 103 | * @param config the new configuration. 104 | */ 105 | public void setConfig(BrowserConfig config) 106 | { 107 | this.config = config; 108 | } 109 | 110 | /** 111 | * After creating the layout, the root box of the document can be accessed through this method. 112 | * @return the root box of the rendered document. Normally, it corresponds to the <html> element 113 | */ 114 | public ElementBox getRootBox() 115 | { 116 | if (viewport == null) 117 | return null; 118 | else 119 | return viewport.getRootBox(); 120 | } 121 | 122 | /** 123 | * After creating the layout, the viewport box can be accessed through this method. 124 | * @return the viewport box. This box provides a container of all the rendered boxes. 125 | */ 126 | public Viewport getViewport() 127 | { 128 | return viewport; 129 | } 130 | 131 | /** 132 | * Creates the document layout according to the viewport size. If the size of the resulting 133 | * page is greater than the specified one (e.g. there is an explicit width or height specified 134 | * for the resulting page), the viewport size is updated automatically. 135 | * @param dim the viewport size 136 | */ 137 | public void createLayout(Dimension dim) 138 | { 139 | if (createImage) 140 | img = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB); 141 | Graphics2D ig = img.createGraphics(); 142 | 143 | log.trace("Creating boxes"); 144 | BoxFactory factory = new BoxFactory(decoder, baseurl); 145 | factory.setConfig(config); 146 | factory.reset(); 147 | VisualContext ctx = new VisualContext(null, factory); 148 | viewport = factory.createViewportTree(root, ig, ctx, dim.width, dim.height); 149 | log.trace("We have " + factory.next_order + " boxes"); 150 | viewport.initSubtree(); 151 | 152 | log.trace("Layout for "+dim.width+"px"); 153 | viewport.doLayout(dim.width, true, true); 154 | log.trace("Resulting size: " + viewport.getWidth() + "x" + viewport.getHeight() + " (" + viewport + ")"); 155 | 156 | if (autoSizeUpdate) 157 | { 158 | log.trace("Updating viewport size"); 159 | viewport.updateBounds(dim); 160 | log.trace("Resulting size: " + viewport.getWidth() + "x" + viewport.getHeight() + " (" + viewport + ")"); 161 | } 162 | 163 | if (createImage && (viewport.getWidth() > dim.width || viewport.getHeight() > dim.height)) 164 | { 165 | img = new BufferedImage(Math.max(viewport.getWidth(), dim.width), 166 | Math.max(viewport.getHeight(), dim.height), 167 | BufferedImage.TYPE_INT_RGB); 168 | ig = img.createGraphics(); 169 | } 170 | 171 | log.trace("Positioning for "+viewport.getWidth()+"x"+viewport.getHeight()+"px"); 172 | viewport.absolutePositions(); 173 | 174 | log.trace("Drawing"); 175 | clearCanvas(); 176 | GraphicsRenderer r = new GraphicsRenderer(ig); 177 | viewport.draw(r); 178 | r.close(); 179 | setPreferredSize(new Dimension(img.getWidth(), img.getHeight())); 180 | revalidate(); 181 | } 182 | 183 | public void paintComponent(Graphics g) 184 | { 185 | super.paintComponent(g); 186 | g.drawImage(img, 0, 0, null); 187 | } 188 | 189 | /** 190 | * Fills the whole canvas with the white background. 191 | */ 192 | public void clearCanvas() 193 | { 194 | Graphics2D ig = img.createGraphics(); 195 | viewport.drawBackground(ig); 196 | } 197 | 198 | /** 199 | * Redraws all the rendered boxes. 200 | */ 201 | public void redrawBoxes() 202 | { 203 | Graphics2D ig = img.createGraphics(); 204 | clearCanvas(); 205 | viewport.draw(new GraphicsRenderer(ig)); 206 | revalidate(); 207 | } 208 | 209 | /** 210 | * @return the graphics context for drawing in the page image 211 | */ 212 | public Graphics2D getImageGraphics() 213 | { 214 | return img.createGraphics(); 215 | } 216 | 217 | /** 218 | * @return image containing the rendered page 219 | */ 220 | public BufferedImage getImage() 221 | { 222 | return img; 223 | } 224 | 225 | /** 226 | * Sets a custom image that is used for rendering. Setting the custom image prevents BrowserCanvas 227 | * from creating the image automatically. This can be used for rendering to an image of a specific 228 | * size or format. 229 | * @param image The new image to be used for rendering. 230 | */ 231 | public void setImage(BufferedImage image) 232 | { 233 | img = image; 234 | createImage = false; 235 | } 236 | 237 | /** 238 | * Enables or disables the automatic viewport size update according to its contents. This is enabled by default. 239 | * @param b true for enable, false for disable. 240 | */ 241 | public void setAutoSizeUpdate(boolean b) 242 | { 243 | autoSizeUpdate = b; 244 | } 245 | 246 | /** 247 | * Checks whether the automatic viewport size update is enabled. 248 | * @return true when enabled 249 | */ 250 | public boolean getAutoSizeUpdate() 251 | { 252 | return autoSizeUpdate; 253 | } 254 | 255 | } 256 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/BrowserConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BrowserConfig.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 18.6.2012, 9:40:57 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Font; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | import org.fit.cssbox.io.DOMSource; 27 | import org.fit.cssbox.io.DefaultDOMSource; 28 | import org.fit.cssbox.io.DefaultDocumentSource; 29 | import org.fit.cssbox.io.DocumentSource; 30 | 31 | /** 32 | * A rendering engine configuration. 33 | * 34 | * @author burgetr 35 | */ 36 | public class BrowserConfig 37 | { 38 | /** Should we load the external images? */ 39 | private boolean loadImages; 40 | 41 | /** Should we load the CSS background images? */ 42 | private boolean loadBackgroundImages; 43 | 44 | /** Image loading timeout [ms] */ 45 | private int imageLoadTimeout; 46 | 47 | /** Should we interpret the HTML tags? */ 48 | private boolean useHTML; 49 | 50 | /** Registered DocumentSource implementation */ 51 | private Class documentSourceClass; 52 | 53 | /** Registered DOMSource implementation */ 54 | private Class domSourceClass; 55 | 56 | /** Default font families */ 57 | private Map defaultFonts; 58 | 59 | /** 60 | * Creates a new config with default values of the options. 61 | */ 62 | public BrowserConfig() 63 | { 64 | loadImages = true; 65 | loadBackgroundImages = true; 66 | imageLoadTimeout = 500; 67 | useHTML = true; 68 | documentSourceClass = DefaultDocumentSource.class; 69 | domSourceClass = DefaultDOMSource.class; 70 | initDefaultFonts(); 71 | } 72 | 73 | public boolean getLoadImages() 74 | { 75 | return loadImages; 76 | } 77 | 78 | /** 79 | * Sets whether to load the referenced content images automatically. The default value is true. 80 | * @param loadImages 81 | */ 82 | public void setLoadImages(boolean loadImages) 83 | { 84 | this.loadImages = loadImages; 85 | } 86 | 87 | public boolean getLoadBackgroundImages() 88 | { 89 | return loadBackgroundImages; 90 | } 91 | 92 | /** 93 | * Sets whether to load the CSS background images automatically. The default value is true. 94 | * @param loadBackgroundImages 95 | */ 96 | public void setLoadBackgroundImages(boolean loadBackgroundImages) 97 | { 98 | this.loadBackgroundImages = loadBackgroundImages; 99 | } 100 | 101 | public int getImageLoadTimeout() 102 | { 103 | return imageLoadTimeout; 104 | } 105 | 106 | /** 107 | * Configures the timeout for loading images. The default value is 500ms. 108 | * @param imageLoadTimeout The timeout for loading images in miliseconds. 109 | */ 110 | public void setImageLoadTimeout(int imageLoadTimeout) 111 | { 112 | this.imageLoadTimeout = imageLoadTimeout; 113 | } 114 | 115 | public boolean getUseHTML() 116 | { 117 | return useHTML; 118 | } 119 | 120 | /** 121 | * Sets whether the engine should use the HTML extensions or not. Currently, the HTML 122 | * extensions include the following: 123 | *
    124 | *
  • Creating replaced boxes for <img> elements 125 | *
  • Using the <body> element background for the whole canvas according to the HTML specification 126 | *
127 | * @param useHTML false if the extensions should be switched off (default is on) 128 | */ 129 | public void setUseHTML(boolean useHTML) 130 | { 131 | this.useHTML = useHTML; 132 | } 133 | 134 | /** 135 | * Sets the class used by CSSBox for obtaining documents based on their URLs. 136 | * @param documentSourceClass the new document source class 137 | */ 138 | public void registerDocumentSource(Class documentSourceClass) 139 | { 140 | this.documentSourceClass = documentSourceClass; 141 | } 142 | 143 | /** 144 | * Obtains the class used by CSSBox for obtaining documents based on their URLs. 145 | * @return the used class 146 | */ 147 | public Class getDocumentSourceClass() 148 | { 149 | return documentSourceClass; 150 | } 151 | 152 | /** 153 | * Sets the class used by CSSBox for the DOM tree from documents. 154 | * @param domSourceClass the new DOM source class 155 | */ 156 | public void registerDOMSource(Class domSourceClass) 157 | { 158 | this.domSourceClass = domSourceClass; 159 | } 160 | 161 | /** 162 | * Obtains the class used by CSSBox for the DOM tree from documents. 163 | * @return the used class 164 | */ 165 | public Class getDOMSourceClass() 166 | { 167 | return domSourceClass; 168 | } 169 | 170 | /** 171 | * Sets a default physical font to be used for a logical name. 172 | * @param logical the logical font name 173 | * @param physical the physical font to be used 174 | */ 175 | public void setDefaultFont(String logical, String physical) 176 | { 177 | defaultFonts.put(logical, physical); 178 | } 179 | 180 | /** 181 | * Obtains the physical font name used for a logical name. 182 | * @param logical the logical name 183 | * @return the physicel font name or null if no default is defined for the logical name. 184 | */ 185 | public String getDefaultFont(String logical) 186 | { 187 | return defaultFonts.get(logical); 188 | } 189 | 190 | /** 191 | * Initializes the default fonts. Current implementation just defines the same physical names for basic 192 | * AWT logical fonts. 193 | */ 194 | protected void initDefaultFonts() 195 | { 196 | defaultFonts = new HashMap(3); 197 | defaultFonts.put(Font.SERIF, Font.SERIF); 198 | defaultFonts.put(Font.SANS_SERIF, Font.SANS_SERIF); 199 | defaultFonts.put(Font.MONOSPACED, Font.MONOSPACED); 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/CSSDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * CSSDecoder.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 7. zari 2005, 15:39 19 | */ 20 | 21 | package org.fit.cssbox.layout; 22 | 23 | import java.awt.Rectangle; 24 | 25 | import org.fit.cssbox.css.HTMLNorm; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | import org.w3c.dom.Element; 29 | 30 | import cz.vutbr.web.css.*; 31 | 32 | /** 33 | * This class implements converting the CSS specifications to Java data types. 34 | * 35 | * @author burgetr 36 | */ 37 | public class CSSDecoder 38 | { 39 | protected static Logger log = LoggerFactory.getLogger(CSSDecoder.class); 40 | 41 | private VisualContext context; 42 | 43 | /** 44 | * Creates a new VisualDecoder in the specified context. The context is 45 | * used for the unit conversion (e.g. the em units etc.) 46 | * @param c the visual contect to be assigned 47 | */ 48 | public CSSDecoder(VisualContext c) 49 | { 50 | context = c; 51 | } 52 | 53 | /** 54 | * Returns the visual context of this decoder. 55 | * @return the assigned visual context 56 | */ 57 | public VisualContext getContext() 58 | { 59 | return context; 60 | } 61 | 62 | /** 63 | * Changes the visual context assigned to this decoder. 64 | * @param c The new visual context to be assigned 65 | */ 66 | public void setContext(VisualContext c) 67 | { 68 | context = c; 69 | } 70 | 71 | /** 72 | * Returns the length in pixels from a CSS definition. null values 73 | * of the lengths are interpreted as zero. 74 | * @param value The length or percentage value to be converted 75 | * @param auto True, if the property is set to auto 76 | * @param defval The length value to be used when the first one is null 77 | * @param autoval The value to be used when "auto" is specified 78 | * @param whole the length to be returned as 100% (in case of percentage values) 79 | */ 80 | public int getLength(TermLengthOrPercent value, boolean auto, TermLengthOrPercent defval, TermLengthOrPercent autoval, int whole) 81 | { 82 | TermLengthOrPercent val = value; 83 | if (value == null) val = defval; 84 | if (auto) val = autoval; 85 | if (val != null) 86 | return (int) context.pxLength(val, whole); 87 | else 88 | return 0; 89 | } 90 | 91 | /** 92 | * Returns the length in pixels from a CSS definition 93 | * @param value The length or percentage value to be converted 94 | * @param auto True, if the property is set to auto 95 | * @param defval The length value to be used when the first one is null 96 | * @param autoval The value to be used when "auto" is specified 97 | * @param whole the length to be returned as 100% (in case of percentage values) 98 | */ 99 | public int getLength(TermLengthOrPercent value, boolean auto, int defval, int autoval, int whole) 100 | { 101 | if (auto) 102 | return autoval; 103 | else if (value == null) 104 | return defval; 105 | else 106 | return (int) context.pxLength(value, whole); 107 | } 108 | 109 | /** 110 | * Computes the width and height of a replaced object based on the following properties: 111 | *
    112 | *
  • Intrinsic width and height
  • 113 | *
  • The width and height attributes
  • 114 | *
  • Effective style
  • 115 | *
116 | * @param obj The replaced content object 117 | * @param box The element box whose size should be computed 118 | * @return A rectangle with the width and height set accordingly 119 | */ 120 | public static Rectangle computeReplacedObjectSize(ReplacedContent obj, ElementBox box) 121 | { 122 | int boxw; //resulting size 123 | int boxh; 124 | 125 | int intw; //intrinsic sizes 126 | int inth; 127 | float intr; 128 | if (obj != null) 129 | { 130 | intw = obj.getIntrinsicWidth(); 131 | inth = obj.getIntrinsicHeight(); 132 | if (intw == 0 || inth == 0) 133 | { 134 | log.warn("Obtained a zero intrinsic width or height for " + obj.toString()); 135 | intw = inth = 1; //a fallback for avoiding zeros in ratios 136 | } 137 | intr = (float) intw / inth; 138 | boxw = intw; 139 | boxh = inth; 140 | } 141 | else 142 | { 143 | boxw = intw = 20; //some reasonable default values 144 | boxh = inth = 20; 145 | intr = 1.0f; 146 | } 147 | 148 | //total widths used for percentages 149 | int twidth = box.getContainingBlock().getContentWidth(); 150 | int theight = box.getViewport().getContentHeight(); 151 | 152 | //try to use the attributes 153 | Element el = box.getElement(); 154 | int atrw = -1; 155 | int atrh = -1; 156 | try { 157 | if (!el.getAttribute("width").equals("")) 158 | atrw = HTMLNorm.computeAttributeLength(el.getAttribute("width"), twidth); 159 | } catch (NumberFormatException e) { 160 | log.info("Invalid width value: " + el.getAttribute("width")); 161 | } 162 | try { 163 | if (!el.getAttribute("height").equals("")) 164 | atrh = HTMLNorm.computeAttributeLength(el.getAttribute("height"), theight); 165 | } catch (NumberFormatException e) { 166 | log.info("Invalid height value: " + el.getAttribute("width")); 167 | } 168 | //apply intrinsic ration when necessary 169 | if (atrw == -1 && atrh == -1) 170 | { 171 | boxw = intw; 172 | boxh = inth; 173 | } 174 | else if (atrw == -1) 175 | { 176 | boxw = Math.round(intr * atrh); 177 | boxh = atrh; 178 | } 179 | else if (atrh == -1) 180 | { 181 | boxw = atrw; 182 | boxh = Math.round(atrw / intr); 183 | } 184 | else 185 | { 186 | boxw = atrw; 187 | boxh = atrh; 188 | intr = (float) boxw / boxh; //new intrsinsic ratio is set explicitly 189 | } 190 | 191 | //compute dimensions from styles (styles should override the attributes) 192 | CSSDecoder dec = new CSSDecoder(box.getVisualContext()); 193 | CSSProperty.Width width = box.getStyle().getProperty("width"); 194 | if (width == CSSProperty.Width.AUTO) width = null; //auto and null are equal for width 195 | CSSProperty.Height height = box.getStyle().getProperty("height"); 196 | if (height == CSSProperty.Height.AUTO) height = null; //auto and null are equal for height 197 | if (width == null && height != null) 198 | { 199 | //compute boxh, boxw is intrinsic 200 | int autoh = Math.round(boxw / intr); 201 | boxh = dec.getLength(box.getLengthValue("height"), height == CSSProperty.Height.AUTO, boxh, autoh, theight); 202 | boxw = Math.round(intr * boxh); 203 | } 204 | else if (width != null && height == null) 205 | { 206 | //compute boxw, boxh is intrinsic 207 | int autow = Math.round(intr * boxh); 208 | boxw = dec.getLength(box.getLengthValue("width"), width == CSSProperty.Width.AUTO, boxw, autow, twidth); 209 | boxh = Math.round(boxw / intr); 210 | } 211 | else 212 | { 213 | boxw = dec.getLength(box.getLengthValue("width"), width == CSSProperty.Width.AUTO, boxw, intw, twidth); 214 | boxh = dec.getLength(box.getLengthValue("height"), height == CSSProperty.Height.AUTO, boxh, inth, theight); 215 | } 216 | 217 | return new Rectangle(boxw, boxh); 218 | } 219 | 220 | 221 | } 222 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/FloatList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * FloatList.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 27. zari 2005, 23:00 19 | */ 20 | 21 | package org.fit.cssbox.layout; 22 | 23 | import java.util.*; 24 | 25 | /** 26 | * A list of floating boxes 27 | * 28 | * @author radek 29 | */ 30 | public class FloatList 31 | { 32 | private BlockBox owner; 33 | private Vector floats; 34 | //private int maxY; 35 | //private int lastY; //Y coordinate of the last box. New boxes shouldn't be placed above this limit 36 | private BlockBox bottomBox = null; //Bottom-most box. 37 | private BlockBox lastBox = null; //last box inserted. New boxes shouldn't be placed above this box. 38 | 39 | /** 40 | * Creates a list of floating boxes for some owner block. 41 | * @param ownerBox the owner block box 42 | */ 43 | public FloatList(BlockBox ownerBox) 44 | { 45 | owner = ownerBox; 46 | floats = new Vector(); 47 | } 48 | 49 | /** 50 | * @return the owning block box of the float list 51 | */ 52 | public BlockBox getOwner() 53 | { 54 | return owner; 55 | } 56 | 57 | /** 58 | * Adds a new floating box to the list 59 | * @param box Floating block box to be added 60 | */ 61 | public void add(BlockBox box) 62 | { 63 | box.setOwnerFloatList(this); 64 | floats.add(box); 65 | if (box.getBounds().y + box.getBounds().height > getMaxY()) 66 | bottomBox = box; 67 | if (box.getBounds().y > getLastY()) 68 | lastBox = box; 69 | } 70 | 71 | /** 72 | * @return the number of boxes in the list 73 | */ 74 | public int size() 75 | { 76 | return floats.size(); 77 | } 78 | 79 | /** 80 | * Finds an n-th box in the list 81 | * @param index the position of the box in the list 82 | * @return the box on the index position 83 | */ 84 | public BlockBox getBox(int index) 85 | { 86 | return floats.elementAt(index); 87 | } 88 | 89 | /** 90 | * Returns the the Y coordinate of the lowest bottom edge 91 | * of the boxes. 92 | * @return the maximal Y coordinate 93 | */ 94 | public int getMaxY() 95 | { 96 | if (bottomBox == null) 97 | return 0; 98 | else 99 | return bottomBox.getBounds().y + bottomBox.getBounds().height; 100 | } 101 | 102 | /** 103 | * Returns the Y coordinate of the last box. New boxes shouldn't be placed above this limit. 104 | * @return Y coordinate 105 | */ 106 | public int getLastY() 107 | { 108 | if (lastBox == null) 109 | return 0; 110 | else 111 | return lastBox.getBounds().y; 112 | } 113 | 114 | /** 115 | * Gets the total width of the floating boxes in some point. 116 | * @param y the Y coordinate of the point 117 | * @return the total width of the floating boxes on that Y coordinate 118 | */ 119 | public int getWidth(int y) 120 | { 121 | int maxx = 0; 122 | for (int i = 0; i < size(); i++) 123 | { 124 | Box box = getBox(i); 125 | if (box.getBounds().y <= y && 126 | box.getBounds().y + box.getBounds().height > y) 127 | { 128 | int wx = box.getBounds().x + box.getBounds().width; 129 | if (wx > maxx) maxx = wx; 130 | } 131 | } 132 | return maxx; 133 | } 134 | 135 | /** 136 | * Gets the first Y coordinate where the floats are narrower than in the specified Y 137 | * @param y the starting y coordinate 138 | * @return the next Y coordinate where the total width of the floating boxes is narrower 139 | * than at the starting coordinate. When there is no such Y coordinate, -1 is returned. 140 | */ 141 | public int getNextY(int y) 142 | { 143 | int maxx = 0; 144 | int nexty = -1; 145 | for (int i = 0; i < size(); i++) //find the bottom of the rightmost box at this Y coordinate 146 | { 147 | Box box = getBox(i); 148 | if (box.getBounds().y <= y && 149 | box.getBounds().y + box.getBounds().height > y) 150 | { 151 | int wx = box.getBounds().x + box.getBounds().width; 152 | if (wx > maxx) 153 | { 154 | maxx = wx; 155 | nexty = box.getBounds().y + box.getBounds().height; 156 | } 157 | } 158 | } 159 | return nexty; 160 | } 161 | 162 | /** 163 | * Goes through all the boxes and computes the Y coordinate of the bottom edge 164 | * of the lowest box. Only the boxes with the 'owner' containing block are taken 165 | * into account. 166 | * @param owner the owning block 167 | * @return the maximal Y coordinate 168 | */ 169 | public int getMaxYForOwner(BlockBox owner) 170 | { 171 | int maxy = 0; 172 | for (int i = 0; i < size(); i++) 173 | { 174 | Box box = getBox(i); 175 | if (box.getContainingBlock() == owner) 176 | { 177 | int ny = box.bounds.y + box.bounds.height; //TODO: -1 here? 178 | if (ny > maxy) maxy = ny; 179 | } 180 | } 181 | return maxy; 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/HTMLBoxFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * HTMLBoxFactory.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 23.11.2012, 15:52:00 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | import java.io.IOException; 24 | import java.net.MalformedURLException; 25 | import java.net.URL; 26 | import java.util.HashSet; 27 | import java.util.Set; 28 | 29 | import cz.vutbr.web.css.NodeData; 30 | 31 | import org.fit.cssbox.io.DOMSource; 32 | import org.fit.cssbox.io.DefaultDOMSource; 33 | import org.fit.cssbox.io.DocumentSource; 34 | import org.slf4j.Logger; 35 | import org.slf4j.LoggerFactory; 36 | import org.w3c.dom.Document; 37 | import org.w3c.dom.Element; 38 | import org.xml.sax.SAXException; 39 | 40 | /** 41 | * 42 | * @author burgetr 43 | */ 44 | public class HTMLBoxFactory 45 | { 46 | private static Logger log = LoggerFactory.getLogger(HTMLBoxFactory.class); 47 | 48 | private BoxFactory factory; 49 | private Set supported; 50 | 51 | public HTMLBoxFactory(BoxFactory parent) 52 | { 53 | this.factory = parent; 54 | supported = new HashSet(2); 55 | supported.add("object"); 56 | supported.add("img"); 57 | } 58 | 59 | public boolean isTagSupported(Element e) 60 | { 61 | if (e.getNodeName() != null && supported.contains(e.getNodeName().toLowerCase())) //completely supported tags 62 | return true; 63 | else //special cases 64 | { 65 | //empty anchor elements must be preserved 66 | if (e.getNodeName().toLowerCase().equals("a") && e.hasAttribute("name") && e.getTextContent().trim().length() == 0) 67 | return true; 68 | else 69 | return false; 70 | } 71 | } 72 | 73 | /** 74 | * Creates the box according to the HTML element. 75 | * @param parent 76 | * @param e 77 | * @param viewport 78 | * @param style 79 | * @return The newly created box or null when the element is not supported 80 | * or cannot be created. 81 | */ 82 | public ElementBox createBox(ElementBox parent, Element e, Viewport viewport, NodeData style) 83 | { 84 | String name = e.getNodeName().toLowerCase(); 85 | if (name.equals("object")) 86 | return createSubtreeObject(parent, e, viewport, style); 87 | else if (name.equals("img")) 88 | return createSubtreeImg(parent, e, viewport, style); 89 | else if (name.equals("a") && e.hasAttribute("name") && e.getTextContent().trim().length() == 0) 90 | { 91 | //make the named anchors sticky 92 | ElementBox eb = factory.createElementInstance(parent, e, style); 93 | eb.setSticky(true); 94 | return eb; 95 | } 96 | else 97 | return null; 98 | } 99 | 100 | protected ElementBox createSubtreeImg(ElementBox parent, Element e, Viewport viewport, NodeData style) 101 | { 102 | InlineReplacedBox rbox = new InlineReplacedBox(e, (Graphics2D) parent.getGraphics().create(), parent.getVisualContext().create()); 103 | rbox.setViewport(viewport); 104 | rbox.setStyle(style); 105 | 106 | String src = e.getAttribute("src"); 107 | rbox.setContentObj(new ReplacedImage(rbox, rbox.getVisualContext(), factory.getBaseURL(), src)); 108 | 109 | if (rbox.isBlock()) 110 | return new BlockReplacedBox(rbox); 111 | else 112 | return rbox; 113 | } 114 | 115 | protected ElementBox createSubtreeObject(ElementBox parent, Element e, Viewport viewport, NodeData style) 116 | { 117 | //create the replaced box 118 | InlineReplacedBox rbox = new InlineReplacedBox(e, (Graphics2D) parent.getGraphics().create(), parent.getVisualContext().create()); 119 | rbox.setViewport(viewport); 120 | rbox.setStyle(style); 121 | 122 | //try to create the content object based on the mime type 123 | try 124 | { 125 | String mime = e.getAttribute("type").toLowerCase(); 126 | String cb = e.getAttribute("codebase"); 127 | String dataurl = e.getAttribute("data"); 128 | URL base = new URL(factory.getBaseURL(), cb); 129 | 130 | if (!dataurl.trim().isEmpty()) 131 | { 132 | DocumentSource src = factory.createDocumentSource(base, dataurl); 133 | if (mime.isEmpty()) 134 | { 135 | mime = src.getContentType(); 136 | if (mime == null || mime.isEmpty()) 137 | mime = "text/html"; 138 | } 139 | log.debug("ctype=" + mime); 140 | 141 | ReplacedContent content = null; 142 | if (mime.startsWith("image/")) 143 | { 144 | content = new ReplacedImage(rbox, rbox.getVisualContext(), base, dataurl); 145 | } 146 | else if (mime.equals("text/html")) 147 | { 148 | log.info("Parsing: " + src.getURL()); 149 | DOMSource parser = new DefaultDOMSource(src); 150 | Document doc = parser.parse(); 151 | String encoding = parser.getCharset(); 152 | content = new ReplacedText(rbox, doc, src.getURL(), encoding); 153 | } 154 | rbox.setContentObj(content); 155 | } 156 | } catch (MalformedURLException e1) { 157 | //something failed, no content object is created => the we should use the object element contents 158 | } catch (SAXException e1) { 159 | //parsing failed 160 | } catch (IOException e1) { 161 | //document reading failed 162 | } 163 | 164 | if (rbox.getContentObj() != null) //the content object has been sucessfuly created 165 | { 166 | //convert the type 167 | if (rbox.getDisplay() == ElementBox.DISPLAY_BLOCK) 168 | return new BlockReplacedBox(rbox); 169 | else //inline boxes are not allowed -- we must create a block formatting context 170 | return new InlineBlockReplacedBox(rbox); 171 | } 172 | else //no content object - fallback to a normal box (the default object behavior) 173 | { 174 | return null; 175 | } 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/Inline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Inline.java 3 | * Copyright (c) 2005-2010 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 21.11.2010, 19:07:41 by radek 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | /** 23 | * This interface defines common methods of objects that are treated 24 | * in inline context - inline elements and text boxes 25 | * @author radek 26 | */ 27 | public interface Inline 28 | { 29 | 30 | /** 31 | * Returns the declared line height. 32 | * @return The declared line height in pixels. 33 | */ 34 | public int getLineHeight(); 35 | 36 | 37 | /** 38 | * Returns the maximal declared line height of this box and its children. 39 | * @return Maximal declared line height in pixels. 40 | */ 41 | public int getMaxLineHeight(); 42 | 43 | /** 44 | * Obtains the distance from the line box top to the baseline of this box. 45 | * This corresponds to the total required space above the baseline of this box in the parent line box. 46 | * @return the y offset of the baseline in the parent line box 47 | */ 48 | public int getBaselineOffset(); 49 | 50 | /** 51 | * Obtains the required height of the parent line box below the baseline. 52 | * @return the total required space below the baseline in pixels 53 | */ 54 | public int getBelowBaseline(); 55 | 56 | /** 57 | * Obtains the total line box height obtained for this box and its 58 | * subboxes during the layout. It consists of two parts: baselineOffset + belowBaseline. 59 | * @return the total required height of the line in pixels 60 | */ 61 | public int getTotalLineHeight(); 62 | 63 | public int getHalfLead(); 64 | 65 | /** 66 | * Obtains the expected maximal length of the first line of this inline box. 67 | * This is useful when the line breaks are preserved. Otherwise, the length of the whole text is returned. 68 | * @return the length of the first line of the contents in pixels 69 | */ 70 | public int getFirstLineLength(); 71 | 72 | /** 73 | * Obtains the expected maximal length of the last line of this inline box. 74 | * This is useful when the line breaks are preserved. Otherwise, the length of the whole text is returned. 75 | * @return the length of the last line of the contents in pixels 76 | */ 77 | public int getLastLineLength(); 78 | 79 | /** 80 | * Checks whether the inline box contains a line break. This may be only true when the line breaks are preserved 81 | * according to the whitespace style. 82 | * @return true when there is at least one preserved line break inside 83 | */ 84 | public boolean containsLineBreak(); 85 | 86 | /** 87 | * Indicates whether the layout of this box content has been finished by a line break. 88 | * @return true if the layout of this box has finished by a line break 89 | */ 90 | public boolean finishedByLineBreak(); 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/InlineBlockReplacedBox.java: -------------------------------------------------------------------------------- 1 | /* 2 | * InlineBlockReplacedBox.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 26.11.2012, 23:25:09 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | import java.awt.Rectangle; 24 | import java.awt.Shape; 25 | 26 | import org.w3c.dom.Element; 27 | 28 | /** 29 | * An inline-block replaced box. 30 | * @author burgetr 31 | */ 32 | public class InlineBlockReplacedBox extends InlineBlockBox implements ReplacedBox 33 | { 34 | protected int boxw; //image width attribute 35 | protected int boxh; //image height attribute 36 | protected ReplacedContent obj; //the contained object 37 | 38 | /** 39 | * Creates a new instance of InlineBlockReplacedBox 40 | */ 41 | public InlineBlockReplacedBox(Element el, Graphics2D g, VisualContext ctx) 42 | { 43 | super(el, g, ctx); 44 | } 45 | 46 | /** 47 | * Creates a new instance of from an inline variant 48 | */ 49 | public InlineBlockReplacedBox(InlineReplacedBox src) 50 | { 51 | super(src); 52 | this.boxw = src.boxw; 53 | this.boxh = src.boxh; 54 | setContentObj(src.obj); 55 | } 56 | 57 | /** 58 | * @return the content object 59 | */ 60 | public ReplacedContent getContentObj() 61 | { 62 | return obj; 63 | } 64 | 65 | /** 66 | * @param obj the obj to set 67 | */ 68 | public void setContentObj(ReplacedContent obj) 69 | { 70 | this.obj = obj; 71 | isempty = (obj == null); 72 | if (!isempty) 73 | obj.setOwner(this); 74 | } 75 | 76 | @Override 77 | public int getMaximalWidth() 78 | { 79 | return boxw + declMargin.left + padding.left + border.left + 80 | declMargin.right + padding.right + border.right; 81 | } 82 | 83 | @Override 84 | public int getMinimalWidth() 85 | { 86 | return boxw + declMargin.left + padding.left + border.left + 87 | declMargin.right + padding.right + border.right; 88 | } 89 | 90 | @Override 91 | public Rectangle getMinimalAbsoluteBounds() 92 | { 93 | return new Rectangle(getAbsoluteContentX(), getAbsoluteContentY(), boxw, boxh); 94 | } 95 | 96 | @Override 97 | public boolean isWhitespace() 98 | { 99 | return false; 100 | } 101 | 102 | @Override 103 | public boolean isReplaced() 104 | { 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean canSplitAfter() 110 | { 111 | return true; 112 | } 113 | 114 | @Override 115 | public boolean canSplitBefore() 116 | { 117 | return true; 118 | } 119 | 120 | @Override 121 | public boolean canSplitInside() 122 | { 123 | return false; 124 | } 125 | 126 | @Override 127 | public int getBaselineOffset() 128 | { 129 | return boxh; 130 | } 131 | 132 | @Override 133 | public int getBelowBaseline() 134 | { 135 | return 0; 136 | } 137 | 138 | @Override 139 | public int getTotalLineHeight() 140 | { 141 | return boxh; 142 | } 143 | 144 | @Override 145 | public int getMaxLineHeight() 146 | { 147 | return boxh; 148 | } 149 | 150 | @Override 151 | public boolean doLayout(int availw, boolean force, boolean linestart) 152 | { 153 | //Skip if not displayed 154 | if (!displayed) 155 | { 156 | content.setSize(0, 0); 157 | bounds.setSize(0, 0); 158 | return true; 159 | } 160 | 161 | if (obj != null) 162 | obj.doLayout(); 163 | 164 | setAvailableWidth(availw); 165 | int wlimit = getAvailableContentWidth(); 166 | if (getWidth() <= wlimit) 167 | return true; 168 | else 169 | return force; 170 | } 171 | 172 | @Override 173 | public void absolutePositions() 174 | { 175 | super.absolutePositions(); 176 | if (obj != null) 177 | obj.absolutePositions(); 178 | } 179 | 180 | @Override 181 | protected void loadSizes(boolean update) 182 | { 183 | super.loadSizes(update); 184 | Rectangle objsize = CSSDecoder.computeReplacedObjectSize(obj, this); 185 | content.width = boxw = objsize.width; 186 | content.height = boxh = objsize.height; 187 | bounds.setSize(totalWidth(), totalHeight()); 188 | preferredWidth = getWidth(); 189 | wset = true; 190 | hset = true; 191 | } 192 | 193 | @Override 194 | public boolean hasFixedHeight() 195 | { 196 | return true; 197 | } 198 | 199 | @Override 200 | public boolean hasFixedWidth() 201 | { 202 | return true; 203 | } 204 | 205 | @Override 206 | protected boolean separatedFromTop(ElementBox box) 207 | { 208 | return true; 209 | } 210 | 211 | @Override 212 | protected boolean separatedFromBottom(ElementBox box) 213 | { 214 | return true; 215 | } 216 | 217 | public void drawContent(Graphics2D g) 218 | { 219 | if (obj != null) 220 | { 221 | Shape oldclip = g.getClip(); 222 | g.setClip(applyClip(oldclip, getClippedContentBounds())); 223 | obj.draw(g, boxw, boxh); 224 | g.setClip(oldclip); 225 | } 226 | } 227 | 228 | @Override 229 | public void draw(DrawStage turn) 230 | { 231 | if (displayed && isVisible()) 232 | { 233 | if (!this.formsStackingContext()) 234 | { 235 | switch (turn) 236 | { 237 | case DRAW_NONINLINE: 238 | case DRAW_FLOAT: 239 | //there should be no block-level or floating children here -- we do nothing 240 | break; 241 | case DRAW_INLINE: 242 | getViewport().getRenderer().renderElementBackground(this); 243 | getViewport().getRenderer().startElementContents(this); 244 | getViewport().getRenderer().renderReplacedContent(this); 245 | getViewport().getRenderer().finishElementContents(this); 246 | break; 247 | } 248 | } 249 | } 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/InlineElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * InlineElement.java 3 | * Copyright (c) 2005-2011 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 19.10.2011, 11:25:26 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import cz.vutbr.web.css.CSSProperty; 23 | 24 | /** 25 | * This interface defines the properties common for all the inline-level element boxes 26 | * 27 | * @author burgetr 28 | */ 29 | public interface InlineElement extends Inline 30 | { 31 | 32 | /** 33 | * Obtains the vertical alignment of the element as specified in the style. 34 | * @return a vertical alignment value 35 | */ 36 | public CSSProperty.VerticalAlign getVerticalAlign(); 37 | 38 | /** 39 | * Assigns the line box assigned to this inline box and all the inline sub-boxes. 40 | * @param linebox The assigned linebox. 41 | */ 42 | public void setLineBox(LineBox linebox); 43 | 44 | /** 45 | * Returns the line box used for positioning this element. 46 | */ 47 | public LineBox getLineBox(); 48 | 49 | /** 50 | * Obtains the offset of the content edge from the line box top 51 | * @return the difference between the content edge and the top of the line box in pixels. Positive numbers mean the content box is inside the line box. 52 | */ 53 | public int getLineboxOffset(); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/InlineReplacedBox.java: -------------------------------------------------------------------------------- 1 | /** 2 | * InlineReplacedBox.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 27.9.2006, 21:08:14 by radek 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | import java.awt.Rectangle; 24 | import java.awt.Shape; 25 | 26 | import org.w3c.dom.Element; 27 | 28 | /** 29 | * Inline replaced box. 30 | * @author radek 31 | */ 32 | public class InlineReplacedBox extends InlineBox implements ReplacedBox 33 | { 34 | protected int boxw; //image width attribute 35 | protected int boxh; //image height attribute 36 | protected ReplacedContent obj; //the contained object 37 | 38 | /** 39 | * Creates a new instance of ImgBox 40 | */ 41 | public InlineReplacedBox(Element el, Graphics2D g, VisualContext ctx) 42 | { 43 | super(el, g, ctx); 44 | lineHeight = boxh; 45 | } 46 | 47 | /** 48 | * @return the content object 49 | */ 50 | public ReplacedContent getContentObj() 51 | { 52 | return obj; 53 | } 54 | 55 | /** 56 | * @param obj the obj to set 57 | */ 58 | public void setContentObj(ReplacedContent obj) 59 | { 60 | this.obj = obj; 61 | isempty = (obj == null); 62 | if (!isempty) 63 | obj.setOwner(this); 64 | } 65 | 66 | @Override 67 | public int getMaximalWidth() 68 | { 69 | return boxw + margin.left + padding.left + border.left + 70 | margin.right + padding.right + border.right; 71 | } 72 | 73 | @Override 74 | public int getMinimalWidth() 75 | { 76 | return boxw + margin.left + padding.left + border.left + 77 | margin.right + padding.right + border.right; 78 | } 79 | 80 | @Override 81 | public Rectangle getMinimalAbsoluteBounds() 82 | { 83 | return new Rectangle(getAbsoluteContentX(), getAbsoluteContentY(), boxw, boxh); 84 | } 85 | 86 | @Override 87 | public boolean isWhitespace() 88 | { 89 | return false; 90 | } 91 | 92 | @Override 93 | public boolean isReplaced() 94 | { 95 | return true; 96 | } 97 | 98 | @Override 99 | public boolean canSplitAfter() 100 | { 101 | return true; 102 | } 103 | 104 | @Override 105 | public boolean canSplitBefore() 106 | { 107 | return true; 108 | } 109 | 110 | @Override 111 | public boolean canSplitInside() 112 | { 113 | return false; 114 | } 115 | 116 | @Override 117 | public int getBaselineOffset() 118 | { 119 | return boxh; 120 | } 121 | 122 | @Override 123 | public int getBelowBaseline() 124 | { 125 | return 0; 126 | } 127 | 128 | @Override 129 | public int getTotalLineHeight() 130 | { 131 | return boxh; 132 | } 133 | 134 | /*@Override 135 | public int getLineboxOffset() 136 | { 137 | return boxh - ctx.getBaselineOffset(); 138 | }*/ 139 | 140 | @Override 141 | public int getMaxLineHeight() 142 | { 143 | return boxh; 144 | } 145 | 146 | @Override 147 | public boolean doLayout(int availw, boolean force, boolean linestart) 148 | { 149 | //Skip if not displayed 150 | if (!displayed) 151 | { 152 | content.setSize(0, 0); 153 | bounds.setSize(0, 0); 154 | return true; 155 | } 156 | 157 | setAvailableWidth(availw); 158 | int wlimit = getAvailableContentWidth(); 159 | if (getWidth() <= wlimit) 160 | return true; 161 | else 162 | return force; 163 | } 164 | 165 | @Override 166 | protected void loadSizes() 167 | { 168 | super.loadSizes(); 169 | loadSizeInfo(); 170 | } 171 | 172 | @Override 173 | public void updateSizes() 174 | { 175 | loadSizeInfo(); 176 | } 177 | 178 | private void loadSizeInfo() 179 | { 180 | Rectangle objsize = CSSDecoder.computeReplacedObjectSize(obj, this); 181 | content.width = boxw = objsize.width; 182 | content.height = boxh = objsize.height; 183 | bounds.setSize(totalWidth(), totalHeight()); 184 | } 185 | 186 | public void drawContent(Graphics2D g) 187 | { 188 | if (obj != null) 189 | { 190 | Shape oldclip = g.getClip(); 191 | g.setClip(applyClip(oldclip, getClippedContentBounds())); 192 | obj.draw(g, boxw, boxh); 193 | g.setClip(oldclip); 194 | } 195 | } 196 | 197 | @Override 198 | public void draw(DrawStage turn) 199 | { 200 | ctx.updateGraphics(g); 201 | if (displayed && isVisible()) 202 | { 203 | if (!this.formsStackingContext()) 204 | { 205 | switch (turn) 206 | { 207 | case DRAW_NONINLINE: 208 | case DRAW_FLOAT: 209 | //there should be no block-level or floating children here -- we do nothing 210 | break; 211 | case DRAW_INLINE: 212 | getViewport().getRenderer().renderElementBackground(this); 213 | getViewport().getRenderer().startElementContents(this); 214 | getViewport().getRenderer().renderReplacedContent(this); 215 | getViewport().getRenderer().finishElementContents(this); 216 | break; 217 | } 218 | } 219 | } 220 | } 221 | 222 | } 223 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/LengthSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LengthSet.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 7. zari 2005, 20:06 19 | */ 20 | 21 | package org.fit.cssbox.layout; 22 | 23 | /** 24 | * This class represents a set of four lengths - top, right bottom and left. It 25 | * is used for representing the margin, padding and border width. 26 | * 27 | * @author radek 28 | */ 29 | public class LengthSet 30 | { 31 | /** top length */ 32 | public int top = 0; 33 | 34 | /** right length */ 35 | public int right = 0; 36 | 37 | /** bottom length */ 38 | public int bottom = 0; 39 | 40 | /** left length */ 41 | public int left = 0; 42 | 43 | /** 44 | * Creates a new length set with all the lengths initialized to zero. 45 | */ 46 | public LengthSet() 47 | { 48 | } 49 | 50 | /** 51 | * Creates a new length set with the specified lengths. 52 | * @param t top length 53 | * @param r right length 54 | * @param b bottom length 55 | * @param l left length 56 | */ 57 | public LengthSet(int t, int r, int b, int l) 58 | { 59 | top = t; 60 | right = r; 61 | bottom = b; 62 | left = l; 63 | } 64 | 65 | /** 66 | * Creates a new length set from an existing one. 67 | * @param src the source length set 68 | */ 69 | public LengthSet(LengthSet src) 70 | { 71 | top = src.top; 72 | right = src.right; 73 | bottom = src.bottom; 74 | left = src.left; 75 | } 76 | 77 | /** 78 | * Copies all the values from an existing set. 79 | * @param src the source length set 80 | */ 81 | public void copy(LengthSet src) 82 | { 83 | top = src.top; 84 | right = src.right; 85 | bottom = src.bottom; 86 | left = src.left; 87 | } 88 | 89 | /** 90 | * Returns a string representation of the length set 91 | * @return A string in the [top, right, bottom, left] format 92 | */ 93 | public String toString() 94 | { 95 | return "[" + top + ", " + right + ", " + bottom + ", " + left + "]"; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/ListItemBox.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ListItemBox.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 26.9.2006, 21:25:38 by radek 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.FontMetrics; 23 | import java.awt.Graphics2D; 24 | import java.awt.Image; 25 | import java.awt.Shape; 26 | import java.awt.geom.Rectangle2D; 27 | 28 | import org.w3c.dom.Element; 29 | 30 | import cz.vutbr.web.css.*; 31 | import cz.vutbr.web.css.CSSProperty.ListStyleType; 32 | 33 | /** 34 | * This class represents a list-item box. This box behaves the same way 35 | * as a block box with some modifications. 36 | * @author radek 37 | * @author mantlikf 38 | */ 39 | public class ListItemBox extends BlockBox 40 | { 41 | private static final String[] RCODE = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; 42 | private static final int[] BVAL = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; 43 | 44 | /** List style type */ 45 | private CSSProperty.ListStyleType styleType; 46 | 47 | /** Item number in the sequence */ 48 | private int itemNumber; 49 | 50 | /** Item image */ 51 | private ReplacedImage image; 52 | 53 | /** 54 | * Create a new list item 55 | */ 56 | public ListItemBox(Element n, Graphics2D g, VisualContext ctx) 57 | { 58 | super(n, g, ctx); 59 | isblock = true; 60 | } 61 | 62 | @Override 63 | public void initBox() 64 | { 65 | super.initBox(); 66 | itemNumber = findItemNumber(); 67 | initFirstLine(this); //consider the list marker for the first line 68 | } 69 | 70 | /** 71 | * Create a new list item from an inline box 72 | */ 73 | public ListItemBox(InlineBox src) 74 | { 75 | super(src); 76 | isblock = true; 77 | } 78 | 79 | @Override 80 | public void setStyle(NodeData s) 81 | { 82 | super.setStyle(s); 83 | styleType = style.getProperty("list-style-type"); 84 | if (styleType == null) 85 | styleType = ListStyleType.DISC; 86 | } 87 | 88 | @Override 89 | public void draw(DrawStage turn) 90 | { 91 | if (displayed && isDeclaredVisible()) 92 | { 93 | if (turn == DrawStage.DRAW_INLINE && floating == FLOAT_NONE && position == POS_STATIC) 94 | drawMarker(g); 95 | 96 | super.draw(turn); 97 | } 98 | } 99 | 100 | /** 101 | * Checks whether the list item has a visible bullet. 102 | * @return true when the bullet type is set to other value than none. 103 | */ 104 | public boolean hasVisibleBullet() 105 | { 106 | return styleType != CSSProperty.ListStyleType.NONE; 107 | } 108 | 109 | /** 110 | * Return item number in ordered list. 111 | * 112 | * @return item number 113 | */ 114 | public int getItemNumber() 115 | { 116 | return itemNumber; 117 | } 118 | 119 | /** 120 | * Get ordered list item marker text depending on list-style-type property. 121 | * 122 | * @return item text or empty string for unordered list 123 | */ 124 | public String getMarkerText() 125 | { 126 | String text; 127 | if (styleType == CSSProperty.ListStyleType.UPPER_ALPHA) 128 | text = "" + ((char) (64 + (itemNumber % 24))); 129 | else if (styleType == CSSProperty.ListStyleType.LOWER_ALPHA) 130 | text = "" + ((char) (96 + (itemNumber % 24))); 131 | else if (styleType == CSSProperty.ListStyleType.UPPER_ROMAN) 132 | text = "" + binaryToRoman(itemNumber); 133 | else if (styleType == CSSProperty.ListStyleType.LOWER_ROMAN) 134 | text = "" + binaryToRoman(itemNumber).toLowerCase(); 135 | else 136 | text = String.valueOf(itemNumber); // default decimal 137 | return text + ". "; 138 | } 139 | 140 | /** 141 | * Finds the item number. Currently this correspond to the number of list-item boxes before this box 142 | * within the parent box. 143 | */ 144 | private int findItemNumber() 145 | { 146 | ElementBox parent = getParent(); 147 | int cnt = 0; 148 | for (int i = parent.getStartChild(); i < parent.getEndChild(); i++) 149 | { 150 | Box child = parent.getSubBox(i); 151 | if (child instanceof ListItemBox) 152 | cnt++; 153 | if (child == this) 154 | return cnt; 155 | } 156 | return 1; 157 | } 158 | 159 | /** 160 | * Draw the list item symbol, number or image depending on list-style-type 161 | */ 162 | public void drawMarker(Graphics2D g) 163 | { 164 | Shape oldclip = g.getClip(); 165 | if (clipblock != null) 166 | g.setClip(applyClip(oldclip, clipblock.getClippedContentBounds())); 167 | 168 | if (image != null) 169 | drawImage(g); 170 | else 171 | drawBullet(g); 172 | 173 | g.setClip(oldclip); 174 | } 175 | 176 | /** 177 | * Draws a bullet or text marker 178 | */ 179 | protected void drawBullet(Graphics2D g) 180 | { 181 | ctx.updateGraphics(g); 182 | int x = (int) Math.round(getAbsoluteContentX() - 1.2 * ctx.getEm()); 183 | int y = (int) Math.round(getAbsoluteContentY() + 0.4 * ctx.getEm()); 184 | int r = (int) Math.round(0.6 * ctx.getEm()); 185 | if (styleType == CSSProperty.ListStyleType.CIRCLE) 186 | g.drawOval(x, y, r, r); 187 | else if (styleType == CSSProperty.ListStyleType.SQUARE) 188 | g.fillRect(x, y, r, r); 189 | //else if (type == CSSProperty.ListStyleType.BOX) //not documented, recognized by Konqueror 190 | // g.drawRect(x, y, r, r); 191 | else if (styleType == CSSProperty.ListStyleType.DISC) 192 | g.fillOval(x, y, r, r); 193 | else if (styleType != CSSProperty.ListStyleType.NONE) 194 | drawText(g, getMarkerText()); 195 | } 196 | 197 | /** 198 | * Draws an image marker 199 | */ 200 | protected void drawImage(Graphics2D g) 201 | { 202 | int x = (int) Math.round(getAbsoluteContentX() - 1.2 * ctx.getEm()); 203 | int y = (int) Math.round(getAbsoluteContentY() + 0.4 * ctx.getEm()); 204 | Image img = image.getImage(); 205 | if (img != null) 206 | { 207 | int w = img.getWidth(image); 208 | int h = img.getHeight(image); 209 | x = x - w / 2; 210 | y = y + h / 2; 211 | g.drawImage(img, x, y, image); 212 | } 213 | } 214 | 215 | /** 216 | * Draws a text marker 217 | */ 218 | protected void drawText(Graphics2D g, String text) 219 | { 220 | // top left corner 221 | int x = getAbsoluteContentX(); 222 | int y = getAbsoluteContentY(); 223 | 224 | //Align Y with baseline 225 | FontMetrics fm = g.getFontMetrics(); 226 | Rectangle2D rect = fm.getStringBounds(text, g); 227 | int ofs = getFirstInlineBoxBaseline(); 228 | if (ofs == -1) 229 | ofs = ctx.getBaselineOffset(); //use the font baseline 230 | 231 | // Draw the string 232 | g.drawString(text, 233 | x + ((int) rect.getX()) - ((int) Math.round(rect.getWidth())), 234 | y + ofs); 235 | } 236 | 237 | /** 238 | * Conversion int to Roman numbers 239 | * from http://www.roseindia.net/java/java-tips/45examples/misc/roman/roman.shtml 240 | * 241 | * @param binary 242 | * @return 243 | */ 244 | private static String binaryToRoman(int binary) 245 | { 246 | if (binary <= 0 || binary >= 4000) 247 | throw new NumberFormatException("Value outside roman numeral range."); 248 | String roman = ""; // Roman notation will be accumualated here. 249 | 250 | // Loop from biggest value to smallest, successively subtracting, 251 | // from the binary value while adding to the roman representation. 252 | for (int i = 0; i < RCODE.length; i++) 253 | { 254 | while (binary >= BVAL[i]) 255 | { 256 | binary -= BVAL[i]; 257 | roman += RCODE[i]; 258 | } 259 | } 260 | return roman; 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/ReplacedBox.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ReplacedBox.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 6.2.2009, 16:48:52 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | 24 | /** 25 | * Common interface for both the inline and block replaced boxes 26 | * 27 | * @author burgetr 28 | */ 29 | public interface ReplacedBox 30 | { 31 | 32 | /** 33 | * @return the content object 34 | */ 35 | public ReplacedContent getContentObj(); 36 | 37 | /** 38 | * @param obj the obj to set 39 | */ 40 | public void setContentObj(ReplacedContent obj); 41 | 42 | /** 43 | * Draws the box replaced content. 44 | * @param g 45 | */ 46 | public void drawContent(Graphics2D g); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/ReplacedContent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ReplacedContent.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 27.9.2006, 21:15:03 by radek 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | 24 | /** 25 | * A class that represents the contents of a replace box 26 | * 27 | * @author radek 28 | */ 29 | public abstract class ReplacedContent 30 | { 31 | /** The owner box */ 32 | protected ElementBox owner; 33 | 34 | /** Defined width (CSS syntax, e.g. "120px" or "auto") */ 35 | protected String def_width; 36 | 37 | /** Defined height (CSS syntax, e.g. "120px" or "auto") */ 38 | protected String def_height; 39 | 40 | //============================================================ 41 | 42 | public ReplacedContent(ElementBox owner) 43 | { 44 | this.owner = owner; 45 | } 46 | 47 | /** 48 | * @return the owner 49 | */ 50 | public ElementBox getOwner() 51 | { 52 | return owner; 53 | } 54 | 55 | /** 56 | * @param owner the owner to set 57 | */ 58 | public void setOwner(ElementBox owner) 59 | { 60 | this.owner = owner; 61 | } 62 | 63 | /** 64 | * Loads the size definitions from appropriate node attributes or CSS properties 65 | */ 66 | public void loadSizeDefs() 67 | { 68 | //default behaviour - set 'auto' only 69 | def_width = "auto"; 70 | def_height = "auto"; 71 | } 72 | 73 | /** 74 | * Compute the content layout in the owner area 75 | */ 76 | public void doLayout() 77 | { 78 | //the default behaviour is to do remove the child nodes from the owner object if any 79 | //because the box is replaced by the content 80 | owner.removeAllSubBoxes(); 81 | } 82 | 83 | /** 84 | * Computes the absolute positions in the content if necessary. 85 | */ 86 | public void absolutePositions() 87 | { 88 | //the default is to do nothing 89 | } 90 | 91 | /** 92 | * Draw the contents of the element. 93 | * @param g graphics context 94 | * @param width the required width of the result 95 | * @param height the required height of the result 96 | */ 97 | abstract public void draw(Graphics2D g, int width, int height); 98 | 99 | /** 100 | * @return the intrinsic width of the contents 101 | */ 102 | abstract public int getIntrinsicWidth(); 103 | 104 | /** 105 | * @return the intrinsic height of the contents 106 | */ 107 | abstract public int getIntrinsicHeight(); 108 | 109 | /** 110 | * @return the intrinsic width/height ratio. If the object has no ratio, 0 is returned 111 | */ 112 | abstract public float getIntrinsicRatio(); 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/ReplacedImage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ReplacedImage.java 3 | * Copyright (c) 2005-2011 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 4. prosinec 2005, 21:01 19 | */ 20 | 21 | package org.fit.cssbox.layout; 22 | 23 | import java.awt.BasicStroke; 24 | import java.awt.Graphics2D; 25 | import java.awt.Rectangle; 26 | import java.net.MalformedURLException; 27 | import java.net.URL; 28 | 29 | import org.fit.net.DataURLHandler; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | /** 34 | * This class represents an image as the contents of a replaced element. 35 | * 36 | * @author radek 37 | * @author petsof 38 | */ 39 | public class ReplacedImage extends ContentImage 40 | { 41 | private static Logger log = LoggerFactory.getLogger(ReplacedImage.class); 42 | 43 | /** Default image width of 20 px, used when there are no image data */ 44 | protected final int DEFAULT_IMAGE_WIDTH = 20; 45 | /** Default image height of 20 px, used when there are no image data */ 46 | protected final int DEFAULT_IMAGE_HEIGHT = 20; 47 | 48 | protected URL base; 49 | protected VisualContext ctx; //visual context 50 | 51 | /** 52 | * Creates a new instance of ReplacedImage. 53 | * 54 | * @param owner 55 | * the owning Box. 56 | * @param ctx 57 | * the visual context applied during rendering. 58 | * @param baseurl 59 | * the base url used for loading images from. 60 | * @param src 61 | * the source URL 62 | * 63 | * @see ElementBox 64 | * @see VisualContext 65 | * @see URL 66 | */ 67 | public ReplacedImage(ElementBox owner, VisualContext ctx, URL baseurl, String src) 68 | { 69 | super(owner); 70 | this.ctx = ctx; 71 | this.loadImages = owner.getViewport().getConfig().getLoadImages(); 72 | this.base = baseurl; 73 | 74 | try { 75 | url = DataURLHandler.createURL(base, src); 76 | if (loadImages) 77 | { 78 | // get image object (may not have picture data) 79 | image = loadImage(caching); 80 | } 81 | } catch (MalformedURLException e) { 82 | log.error("URL: " + e.getMessage()); 83 | image = null; 84 | url = null; 85 | } catch (IllegalArgumentException e) { 86 | log.error("Format error: " + e.getMessage()); 87 | image = null; 88 | } 89 | 90 | } 91 | 92 | @Override 93 | public void draw(Graphics2D g, int width, int height) 94 | { 95 | Rectangle bounds = getOwner().getAbsoluteContentBounds(); 96 | 97 | if (image != null) 98 | { 99 | // *_SOME_ transparent animated gifs*, 100 | // may not erase previous frame of animation 101 | // well, repainting with a parent's graphics is not working... 102 | // seems to be java-related, repaint-animated-gif problem. 103 | 104 | // workaround: 105 | // owner has already set clipping, so we can render parent's 106 | // background 107 | // owner.getVisualContext().getParentContext().updateGraphics(g); 108 | // owner.getParent().drawBackground(g); 109 | 110 | // now update our configuration 111 | ctx.updateGraphics(g); 112 | 113 | // draw image 114 | g.drawImage(image, bounds.x, bounds.y, width, height, observer); 115 | } 116 | else 117 | { 118 | ctx.updateGraphics(g); 119 | g.setStroke(new BasicStroke(1)); 120 | g.drawRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1); 121 | } 122 | 123 | } 124 | 125 | @Override 126 | public String toString() 127 | { 128 | return "ReplacedImage [url=" + url + "]"; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/ReplacedText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ReplacedText.java 3 | * Copyright (c) 2005-2012 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 28.11.2012, 13:00:49 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Dimension; 23 | import java.awt.Graphics2D; 24 | import java.net.URL; 25 | 26 | import org.fit.cssbox.css.CSSNorm; 27 | import org.fit.cssbox.css.DOMAnalyzer; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | import org.w3c.dom.Document; 31 | 32 | /** 33 | * The replaced content represented by a text (HTML or XML) document. 34 | * 35 | * @author burgetr 36 | */ 37 | public class ReplacedText extends ReplacedContent 38 | { 39 | private static Logger log = LoggerFactory.getLogger(ReplacedText.class); 40 | 41 | private Document doc; 42 | private URL base; 43 | private String encoding; 44 | private DOMAnalyzer decoder; 45 | private Viewport viewport; 46 | 47 | /** The last dimension used for layout or null when no layout has been created */ 48 | private Dimension currentDimension; 49 | 50 | /** The final dimension used for layout or null when no layout has been created */ 51 | private Dimension layoutDimension; 52 | 53 | public ReplacedText(ElementBox owner, Document doc, URL base, String encoding) 54 | { 55 | super(owner); 56 | this.doc = doc; 57 | this.base = base; 58 | this.encoding = encoding; 59 | currentDimension = null; 60 | layoutDimension = null; 61 | createDecoder(); 62 | } 63 | 64 | /** 65 | * Obtains the viewport of the contents. 66 | * @return the viewport 67 | */ 68 | public Viewport getContentViewport() 69 | { 70 | return viewport; 71 | } 72 | 73 | @Override 74 | public void draw(Graphics2D g, int width, int height) 75 | { 76 | viewport.draw(owner.getViewport().getRenderer()); 77 | } 78 | 79 | @Override 80 | public int getIntrinsicWidth() 81 | { 82 | checkLayout(); 83 | return viewport.getWidth(); 84 | } 85 | 86 | @Override 87 | public int getIntrinsicHeight() 88 | { 89 | checkLayout(); 90 | return viewport.getHeight(); 91 | } 92 | 93 | @Override 94 | public float getIntrinsicRatio() 95 | { 96 | return (float) getIntrinsicWidth() / (float) getIntrinsicHeight(); 97 | } 98 | 99 | @Override 100 | public void doLayout() 101 | { 102 | layoutDimension = new Dimension(owner.getContent()); //use owner content size for dimension 103 | checkLayout(); 104 | } 105 | 106 | @Override 107 | public void absolutePositions() 108 | { 109 | viewport.absolutePositions(); 110 | } 111 | 112 | //========================================================================== 113 | 114 | private void createDecoder() 115 | { 116 | decoder = new DOMAnalyzer(doc, base); 117 | if (encoding == null) 118 | encoding = decoder.getCharacterEncoding(); 119 | decoder.setDefaultEncoding(encoding); 120 | decoder.attributesToStyles(); 121 | decoder.addStyleSheet(null, CSSNorm.stdStyleSheet(), DOMAnalyzer.Origin.AGENT); 122 | decoder.addStyleSheet(null, CSSNorm.userStyleSheet(), DOMAnalyzer.Origin.AGENT); 123 | decoder.getStyleSheets(); 124 | } 125 | 126 | /** 127 | * Obtains the dimension that should be used for the layout. 128 | * @return the dimension 129 | */ 130 | private Dimension getLayoutDimension() 131 | { 132 | Dimension dim; 133 | if (layoutDimension != null) 134 | { 135 | dim = new Dimension(layoutDimension); 136 | if (dim.width <= 0) dim.width = 10; //use some minimum size when the size is not known 137 | if (dim.height <= 0) dim.height = 10; 138 | } 139 | else 140 | dim = new Dimension(10, 10); 141 | return dim; 142 | } 143 | 144 | /** 145 | * Checks whether the layout is computed and recomputes it when necessary. 146 | */ 147 | private void checkLayout() 148 | { 149 | Dimension dim = getLayoutDimension(); 150 | if (currentDimension == null || !currentDimension.equals(dim)) //the dimension has changed 151 | { 152 | createLayout(dim); 153 | //containing box for the new viewport 154 | BlockBox cblock = (owner instanceof BlockBox) ? (BlockBox) owner : owner.getContainingBlock(); 155 | viewport.setContainingBlock(cblock); 156 | viewport.clipByBlock(cblock); 157 | 158 | owner.removeAllSubBoxes(); 159 | owner.addSubBox(viewport); 160 | currentDimension = new Dimension(dim); 161 | } 162 | } 163 | 164 | private void createLayout(Dimension dim) 165 | { 166 | VisualContext ctx = new VisualContext(null, getOwner().getViewport().getFactory()); 167 | 168 | log.trace("Creating boxes"); 169 | BoxFactory factory = new BoxFactory(decoder, base); 170 | factory.setConfig(owner.getViewport().getConfig()); 171 | factory.reset(); 172 | viewport = factory.createViewportTree(decoder.getRoot(), owner.getGraphics(), ctx, dim.width, dim.height); 173 | log.trace("We have " + factory.next_order + " boxes"); 174 | viewport.initSubtree(); 175 | 176 | log.trace("Layout for "+dim.width+"px"); 177 | viewport.doLayout(dim.width, true, true); 178 | log.trace("Resulting size: " + viewport.getWidth() + "x" + viewport.getHeight() + " (" + viewport + ")"); 179 | 180 | log.trace("Positioning for "+viewport.getWidth()+"x"+viewport.getHeight()+"px"); 181 | viewport.absolutePositions(); 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/StackingContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * StackingContext.java 3 | * Copyright (c) 2005-2013 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 15.2.2013, 14:25:24 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.util.Arrays; 23 | import java.util.HashMap; 24 | import java.util.Set; 25 | import java.util.Vector; 26 | 27 | /** 28 | * A stacking context. It gathers the information about child stacking contexts and their z-indices. 29 | * 30 | * @author burgetr 31 | */ 32 | public class StackingContext extends HashMap> 33 | { 34 | private static final long serialVersionUID = -2945581861967274084L; 35 | 36 | /** The box that creates this stacking context */ 37 | private ElementBox elementBox; 38 | 39 | 40 | public StackingContext(ElementBox element) 41 | { 42 | super(); 43 | this.elementBox = element; 44 | } 45 | 46 | public ElementBox getElementBox() 47 | { 48 | return elementBox; 49 | } 50 | 51 | public Integer[] getZIndices() 52 | { 53 | Set zindices = keySet(); 54 | Integer[] clevels = zindices.toArray(new Integer[0]); 55 | Arrays.sort(clevels); 56 | return clevels; 57 | } 58 | 59 | public Vector getElementsForZIndex(int zindex) 60 | { 61 | return get(zindex); 62 | } 63 | 64 | public void registerChildContext(ElementBox element) 65 | { 66 | int zindex = element.hasZIndex() ? element.getZIndex() : 0; //put 'auto' z-indices into level 0 67 | Vector list = get(zindex); 68 | if (list == null) 69 | { 70 | list = new Vector(); 71 | put(zindex, list); 72 | } 73 | list.add(element); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/TableCaptionBox.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TableCaptionBox.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 29.9.2006, 14:12:05 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.Graphics2D; 23 | 24 | import cz.vutbr.web.css.CSSProperty; 25 | import cz.vutbr.web.css.TermLengthOrPercent; 26 | 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import org.w3c.dom.Element; 30 | 31 | /** 32 | * A box that contains the table caption. 33 | * @author burgetr 34 | */ 35 | public class TableCaptionBox extends BlockBox 36 | { 37 | private static Logger log = LoggerFactory.getLogger(TableCaptionBox.class); 38 | 39 | /** 40 | * Create a new table caption 41 | */ 42 | public TableCaptionBox(Element n, Graphics2D g, VisualContext ctx) 43 | { 44 | super(n, g, ctx); 45 | isblock = true; 46 | } 47 | 48 | /** 49 | * Create a new table caption from an inline box 50 | */ 51 | public TableCaptionBox(InlineBox src) 52 | { 53 | super(src); 54 | isblock = true; 55 | } 56 | 57 | 58 | //In contrast to a normal block box, a different content block width is used and availwidth is used for determining the free space 59 | protected void computeWidthsInFlow(TermLengthOrPercent width, boolean auto, boolean exact, int contw, boolean update) 60 | { 61 | CSSDecoder dec = new CSSDecoder(ctx); 62 | 63 | if (width == null) auto = true; //no value behaves as 'auto' 64 | 65 | //According to CSS spec. 17.4, we should take the size of the original containing box, not the anonymous box 66 | if (cblock == null && cblock.getContainingBlock() != null) 67 | { log.debug(toString() + " has no cblock"); return; } 68 | contw = cblock.getContainingBlock().getContentWidth(); 69 | 70 | boolean mleftauto = style.getProperty("margin-left") == CSSProperty.Margin.AUTO; 71 | TermLengthOrPercent mleft = getLengthValue("margin-left"); 72 | boolean mrightauto = style.getProperty("margin-right") == CSSProperty.Margin.AUTO; 73 | TermLengthOrPercent mright = getLengthValue("margin-right"); 74 | preferredWidth = -1; 75 | 76 | if (!widthComputed) update = false; 77 | 78 | if (auto) 79 | { 80 | if (exact) wset = false; 81 | margin.left = dec.getLength(mleft, mleftauto, 0, 0, contw); 82 | margin.right = dec.getLength(mright, mrightauto, 0, 0, contw); 83 | declMargin.left = margin.left; 84 | declMargin.right = margin.right; 85 | /* For the first time, we always try to use the maximal width even for the 86 | * boxes out of the flow. When updating, only the in-flow boxes are adjusted. */ 87 | if (!update || isInFlow()) 88 | { 89 | content.width = contw - margin.left - border.left - padding.left 90 | - padding.right - border.right - margin.right; 91 | if (content.width < 0) content.width = 0; 92 | } 93 | preferredWidth = -1; //we don't prefer anything (auto width) 94 | } 95 | else 96 | { 97 | if (exact) 98 | { 99 | wset = true; 100 | wrelative = width.isPercentage(); 101 | } 102 | content.width = dec.getLength(width, auto, 0, 0, contw); 103 | margin.left = dec.getLength(mleft, mleftauto, 0, 0, contw); 104 | margin.right = dec.getLength(mright, mrightauto, 0, 0, contw); 105 | declMargin.left = margin.left; 106 | declMargin.right = margin.right; 107 | 108 | //We will prefer some width if the value is not percentage 109 | boolean prefer = !width.isPercentage(); 110 | //We will include the margins in the preferred width if they're not percentages 111 | int prefml = (mleft == null) || mleft.isPercentage() || mleftauto ? 0 : margin.left; 112 | int prefmr = (mright == null) || mright.isPercentage() || mrightauto ? 0 : margin.right; 113 | //Compute the preferred width 114 | if (prefer) 115 | preferredWidth = prefml + border.left + padding.left + content.width + 116 | padding.right + border.right + prefmr; 117 | 118 | //Compute the margins if we're in flow and we know the width 119 | if (isInFlow() && prefer) 120 | { 121 | if (mleftauto && mrightauto) 122 | { 123 | int rest = contw - content.width - border.left - padding.left 124 | - padding.right - border.right; 125 | if (rest < 0) rest = 0; 126 | margin.left = (rest + 1) / 2; 127 | margin.right = rest / 2; 128 | } 129 | else if (mleftauto) 130 | { 131 | margin.left = contw - content.width - border.left - padding.left 132 | - padding.right - border.right - margin.right; 133 | //if (margin.left < 0) margin.left = 0; //"treated as zero" 134 | } 135 | else if (mrightauto) 136 | { 137 | margin.right = contw - content.width - border.left - padding.left 138 | - padding.right - border.right - margin.left; 139 | //if (margin.right < 0) margin.right = 0; //"treated as zero" 140 | } 141 | else //everything specified, ignore right margin 142 | { 143 | margin.right = contw - content.width - border.left - padding.left 144 | - padding.right - border.right - margin.left; 145 | //if (margin.right < 0) margin.right = 0; //"treated as zero" 146 | } 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/layout/TableColumnGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * TableColumnGroup.java 3 | * Copyright (c) 2005-2007 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 3.10.2006, 10:51:03 by burgetr 19 | */ 20 | package org.fit.cssbox.layout; 21 | 22 | import java.awt.*; 23 | import java.util.*; 24 | 25 | import org.w3c.dom.Element; 26 | 27 | 28 | /** 29 | * @author burgetr 30 | * 31 | */ 32 | public class TableColumnGroup extends TableColumn 33 | { 34 | private Vector columns; 35 | 36 | //=============================================================================== 37 | 38 | /** 39 | * Create a new table column 40 | */ 41 | public TableColumnGroup(Element n, Graphics2D g, VisualContext ctx) 42 | { 43 | super(n, g, ctx); 44 | } 45 | 46 | /** 47 | * Create a new table cell from an inline box 48 | */ 49 | public TableColumnGroup(InlineBox src) 50 | { 51 | super(src); 52 | } 53 | 54 | public int getSpan() 55 | { 56 | if (columns == null) organizeColumns(); 57 | return columns.size(); 58 | } 59 | 60 | public TableColumn getColumn(int index) 61 | { 62 | if (columns == null) organizeColumns(); 63 | return columns.elementAt(index); 64 | } 65 | 66 | //==================================================================================== 67 | 68 | private void organizeColumns() 69 | { 70 | columns = new Vector(); 71 | for (int bi = 0; bi < nested.size(); bi++) 72 | { 73 | Box box = nested.elementAt(bi); 74 | if (box instanceof TableColumn) 75 | { 76 | TableColumn col = (TableColumn) box; 77 | if (col.getSpecifiedWidth().equals("")) 78 | col.setSpecifiedWidth(colwidth); //when column width is not set, use the group width 79 | for (int i = 0; i < col.getSpan(); i++) 80 | { 81 | if (i == 0) 82 | columns.add(col); 83 | else 84 | columns.add(col.copyBox()); 85 | } 86 | } 87 | } 88 | //when there are no elements, use the span attribute 89 | if (columns.isEmpty()) 90 | { 91 | TableColumn col = new TableColumn(TableColumn.createAnonymousColumn(getParent().getElement().getOwnerDocument()), g, ctx); 92 | col.setSpecifiedWidth(colwidth); 93 | for (int i = 0; i < span; i++) 94 | columns.add(col.copyBox()); 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/misc/Base64Coder.java: -------------------------------------------------------------------------------- 1 | package org.fit.cssbox.misc; 2 | 3 | /** 4 | * A Base64 Encoder/Decoder. 5 | * 6 | *

7 | * This class is used to encode and decode data in Base64 format as described in RFC 1521. 8 | * 9 | *

10 | * This is "Open Source" software and released under the GNU/LGPL license.
11 | * It is provided "as is" without warranty of any kind.
12 | * Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland.
13 | * Home page: www.source-code.biz
14 | * 15 | *

16 | * Version history:
17 | * 2003-07-22 Christian d'Heureuse (chdh): Module created.
18 | * 2005-08-11 chdh: Lincense changed from GPL to LGPL.
19 | * 2006-11-21 chdh:
20 | *   Method encode(String) renamed to encodeString(String).
21 | *   Method decode(String) renamed to decodeString(String).
22 | *   New method encode(byte[],int) added.
23 | *   New method decode(String) added.
24 | */ 25 | 26 | public class Base64Coder { 27 | 28 | // Mapping table from 6-bit nibbles to Base64 characters. 29 | private static char[] map1 = new char[64]; 30 | static { 31 | int i=0; 32 | for (char c='A'; c<='Z'; c++) map1[i++] = c; 33 | for (char c='a'; c<='z'; c++) map1[i++] = c; 34 | for (char c='0'; c<='9'; c++) map1[i++] = c; 35 | map1[i++] = '+'; map1[i++] = '/'; } 36 | 37 | // Mapping table from Base64 characters to 6-bit nibbles. 38 | private static byte[] map2 = new byte[128]; 39 | static { 40 | for (int i=0; iin. 66 | * @return A character array with the Base64 encoded data. 67 | */ 68 | public static char[] encode (byte[] in, int iLen) { 69 | int oDataLen = (iLen*4+2)/3; // output length without padding 70 | int oLen = ((iLen+2)/3)*4; // output length including padding 71 | char[] out = new char[oLen]; 72 | int ip = 0; 73 | int op = 0; 74 | while (ip < iLen) { 75 | int i0 = in[ip++] & 0xff; 76 | int i1 = ip < iLen ? in[ip++] & 0xff : 0; 77 | int i2 = ip < iLen ? in[ip++] & 0xff : 0; 78 | int o0 = i0 >>> 2; 79 | int o1 = ((i0 & 3) << 4) | (i1 >>> 4); 80 | int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); 81 | int o3 = i2 & 0x3F; 82 | out[op++] = map1[o0]; 83 | out[op++] = map1[o1]; 84 | out[op] = op < oDataLen ? map1[o2] : '='; op++; 85 | out[op] = op < oDataLen ? map1[o3] : '='; op++; } 86 | return out; } 87 | 88 | /** 89 | * Decodes a string from Base64 format. 90 | * @param s a Base64 String to be decoded. 91 | * @return A String containing the decoded data. 92 | * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 93 | */ 94 | public static String decodeString (String s) { 95 | return new String(decode(s)); } 96 | 97 | /** 98 | * Decodes a byte array from Base64 format. 99 | * @param s a Base64 String to be decoded. 100 | * @return An array containing the decoded data bytes. 101 | * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 102 | */ 103 | public static byte[] decode (String s) { 104 | return decode(s.toCharArray()); } 105 | 106 | /** 107 | * Decodes a byte array from Base64 format. 108 | * No blanks or line breaks are allowed within the Base64 encoded data. 109 | * @param in a character array containing the Base64 encoded data. 110 | * @return An array containing the decoded data bytes. 111 | * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 112 | */ 113 | public static byte[] decode (char[] in) { 114 | int iLen = in.length; 115 | if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); 116 | while (iLen > 0 && in[iLen-1] == '=') iLen--; 117 | int oLen = (iLen*3) / 4; 118 | byte[] out = new byte[oLen]; 119 | int ip = 0; 120 | int op = 0; 121 | while (ip < iLen) { 122 | int i0 = in[ip++]; 123 | int i1 = in[ip++]; 124 | int i2 = ip < iLen ? in[ip++] : 'A'; 125 | int i3 = ip < iLen ? in[ip++] : 'A'; 126 | if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) 127 | throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); 128 | int b0 = map2[i0]; 129 | int b1 = map2[i1]; 130 | int b2 = map2[i2]; 131 | int b3 = map2[i3]; 132 | if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) 133 | throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); 134 | int o0 = ( b0 <<2) | (b1>>>4); 135 | int o1 = ((b1 & 0xf)<<4) | (b2>>>2); 136 | int o2 = ((b2 & 3)<<6) | b3; 137 | out[op++] = (byte)o0; 138 | if (op. 17 | * 18 | * Created on 9.11.2010, 17:31:58 by burgetr 19 | */ 20 | package org.fit.cssbox.misc; 21 | 22 | import java.awt.*; 23 | import java.awt.geom.GeneralPath; 24 | import java.awt.geom.Line2D; 25 | 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import cz.vutbr.web.css.CSSProperty; 30 | 31 | /** 32 | * Stroke for drawing the CSS borders. 33 | * 34 | * @author burgetr 35 | */ 36 | public class CSSStroke implements Stroke 37 | { 38 | private static Logger log = LoggerFactory.getLogger(CSSStroke.class); 39 | 40 | private int width; 41 | private CSSProperty.BorderStyle style; 42 | private boolean reverse; 43 | 44 | /** 45 | * Creates a new CSS stroke. 46 | * @param width Border width 47 | * @param style Border css style 48 | * @param reverse Should be true for right and bottom border - used for reversing the shape of 'double' style border. 49 | */ 50 | public CSSStroke(int width, CSSProperty.BorderStyle style, boolean reverse) 51 | { 52 | this.width = width; 53 | this.style = style; 54 | this.reverse = reverse; 55 | } 56 | 57 | public Shape createStrokedShape(Shape s) 58 | { 59 | if (s instanceof Line2D) 60 | { 61 | Line2D l = (Line2D) s; 62 | int x1 = (int) l.getX1(); 63 | int y1 = (int) l.getY1(); 64 | int x2 = (int) l.getX2(); 65 | int y2 = (int) l.getY2(); 66 | if (y1 == y2 && x2 > x1) 67 | return sideShape(x1, y1, x2 - x1 + 1 , width, false); 68 | else if (x1 == x2 && y2 > y1) 69 | return sideShape(x1, y1, y2 - y1 + 1, width, true); 70 | else 71 | return basicStrokeShape(s); 72 | } 73 | else 74 | return basicStrokeShape(s); 75 | } 76 | 77 | private GeneralPath sideShape(int x, int y, int len, int width, boolean vert) 78 | { 79 | GeneralPath ret; 80 | if (!vert) 81 | { 82 | if (style == CSSProperty.BorderStyle.DASHED || style == CSSProperty.BorderStyle.DOTTED) 83 | { 84 | int r = (style == CSSProperty.BorderStyle.DASHED) ? 3 : 1; 85 | ret = null; 86 | int i = 0; 87 | while (i < len) 88 | { 89 | int l = width * r; 90 | if (i + l >= len) l = len - i; 91 | ret = append(ret, new Rectangle(x + i, y, l, width)); 92 | i += width * (r + 1); 93 | } 94 | } 95 | else if (style == CSSProperty.BorderStyle.DOUBLE && width >= 3) 96 | { 97 | int w = (width + 2) / 3; 98 | int space = width - 2 * w; 99 | if (!reverse) 100 | { 101 | ret = new GeneralPath(new Rectangle(x, y, len, w)); 102 | ret.append(new Rectangle(x + w + space, y + w + space, len - 2 * (w + space), w), false); 103 | } 104 | else 105 | { 106 | ret = new GeneralPath(new Rectangle(x + w + space, y, len - 2 * (w + space), w)); 107 | ret.append(new Rectangle(x, y + w + space, len, w), false); 108 | } 109 | } 110 | else 111 | ret = new GeneralPath(new Rectangle(x, y, len, width)); 112 | } 113 | else 114 | { 115 | if (style == CSSProperty.BorderStyle.DASHED || style == CSSProperty.BorderStyle.DOTTED) 116 | { 117 | int r = (style == CSSProperty.BorderStyle.DASHED) ? 3 : 1; 118 | ret = null; 119 | int i = 0; 120 | while (i < len) 121 | { 122 | int l = width * r; 123 | if (i + l >= len) l = len - i; 124 | ret = append(ret, new Rectangle(x, y + i, width, l)); 125 | i += width * (r + 1); 126 | } 127 | } 128 | else if (style == CSSProperty.BorderStyle.DOUBLE && width >= 3) 129 | { 130 | int w = (width + 2) / 3; 131 | int space = width - 2 * w; 132 | if (!reverse) 133 | { 134 | ret = new GeneralPath(new Rectangle(x, y, w, len)); 135 | ret.append(new Rectangle(x + w + space, y + w + space, w, len - 2 * (w + space)), false); 136 | } 137 | else 138 | { 139 | ret = new GeneralPath(new Rectangle(x, y + w + space, w, len - 2 * (w + space))); 140 | ret.append(new Rectangle(x + w + space, y, w, len), false); 141 | } 142 | } 143 | else 144 | ret = new GeneralPath(new Rectangle(x, y, width, len)); 145 | } 146 | 147 | return ret; 148 | } 149 | 150 | private GeneralPath append(GeneralPath src, Shape s) 151 | { 152 | if (src == null) 153 | return new GeneralPath(s); 154 | else 155 | { 156 | src.append(s, false); 157 | return src; 158 | } 159 | } 160 | 161 | private Shape basicStrokeShape(Shape s) 162 | { 163 | log.debug("Warning: CSSStroke: fallback to BasicStroke"); 164 | BasicStroke bas = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, width); 165 | return bas.createStrokedShape(s); 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/render/BoxRenderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BoxRenderer.java 3 | * Copyright (c) 2005-2013 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 8.3.2013, 11:23:34 by burgetr 19 | */ 20 | package org.fit.cssbox.render; 21 | 22 | import org.fit.cssbox.layout.ElementBox; 23 | import org.fit.cssbox.layout.ReplacedBox; 24 | import org.fit.cssbox.layout.TextBox; 25 | 26 | /** 27 | * A generic renderer that is able to render box contents and background based on 28 | * the box type. 29 | * 30 | * @author burgetr 31 | */ 32 | public interface BoxRenderer 33 | { 34 | /** 35 | * Initializes the rendering of an element. This is called before any contents of the element 36 | * or child boxes are rendered. Note that the {@link BoxRenderer#renderElementBackground} method 37 | * may be called before this method. 38 | * @param elem the element 39 | */ 40 | public void startElementContents(ElementBox elem); 41 | 42 | /** 43 | * Finishes the rendering of an element. This is called after all contents of the element 44 | * and the child boxes are rendered. 45 | * @param elem the element 46 | */ 47 | public void finishElementContents(ElementBox elem); 48 | 49 | /** 50 | * Renders the background and borders of the given element box according to its style. 51 | * @param elem 52 | */ 53 | public void renderElementBackground(ElementBox elem); 54 | 55 | /** 56 | * Renders the text represented by a text box according to its computed style. 57 | * @param text 58 | */ 59 | public void renderTextContent(TextBox text); 60 | 61 | /** 62 | * Renders the contents of a replaced box. 63 | * @param box 64 | */ 65 | public void renderReplacedContent(ReplacedBox box); 66 | 67 | /** 68 | * Finishes and the output. 69 | */ 70 | public void close(); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/fit/cssbox/render/GraphicsRenderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GraphicsRenderer.java 3 | * Copyright (c) 2005-2013 Radek Burget 4 | * 5 | * CSSBox is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * CSSBox is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with CSSBox. If not, see . 17 | * 18 | * Created on 8.3.2013, 11:41:50 by burgetr 19 | */ 20 | package org.fit.cssbox.render; 21 | 22 | import java.awt.Graphics2D; 23 | 24 | import org.fit.cssbox.layout.ElementBox; 25 | import org.fit.cssbox.layout.ReplacedBox; 26 | import org.fit.cssbox.layout.TextBox; 27 | 28 | /** 29 | * This renderers displays the boxes graphically using the given Graphics2D context. 30 | * 31 | * @author burgetr 32 | */ 33 | public class GraphicsRenderer implements BoxRenderer 34 | { 35 | /** the used graphic context */ 36 | protected Graphics2D g; 37 | 38 | /** 39 | * Constructs a renderer using the given graphics contexts. 40 | * @param g The graphics context used for painting the boxes. 41 | */ 42 | public GraphicsRenderer(Graphics2D g) 43 | { 44 | this.g = g; 45 | } 46 | 47 | //==================================================================================================== 48 | 49 | public void startElementContents(ElementBox elem) 50 | { 51 | } 52 | 53 | public void finishElementContents(ElementBox elem) 54 | { 55 | } 56 | 57 | public void renderElementBackground(ElementBox elem) 58 | { 59 | elem.drawBackground(g); 60 | } 61 | 62 | public void renderTextContent(TextBox text) 63 | { 64 | text.drawContent(g); 65 | } 66 | 67 | public void renderReplacedContent(ReplacedBox box) 68 | { 69 | box.drawContent(g); 70 | } 71 | 72 | public void close() 73 | { 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | %-4relative %-5level %-25logger{1} - %msg%n 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | /tmp/jstyleparser.log 28 | 29 | /tmp/jstyleparser.%i.log.zip 30 | 1 31 | 3 32 | 33 | 35 | 1024kB 36 | 37 | 38 | %-4relative %-5level %logger{35} - %msg%n 39 | 40 | 41 | 42 | 43 | 44 | %-4relative %-5level %logger{35} - %msg%n 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | --------------------------------------------------------------------------------