Changeset 701


Ignore:
Timestamp:
01/16/14 10:27:29 (10 years ago)
Author:
ngw8
Message:

Switched to recursive function for parsing DOM when adding to the page, allowing background colours to be inherited/passed down to child elements. Unfortunately this doesn't look great in most situations, so will probably have to go with parsing divs as rectangles.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/io/WebParser.java

    r695 r701  
    66import java.io.File;
    77import java.io.IOException;
     8import java.lang.reflect.InvocationTargetException;
    89import java.net.HttpURLConnection;
    910import java.net.MalformedURLException;
     
    2324import org.expeditee.items.Text;
    2425import org.expeditee.reflection.JavaFX;
     26import org.w3c.dom.Element;
    2527import org.w3c.dom.Node;
    2628import org.w3c.dom.html.HTMLBodyElement;
     
    221223
    222224                                                        // Will never reach 100% here, as the processing is not quite finished - progress is set to 100% at the end of
    223                                                         // the loop below
     225                                                        // the addPageToFrame loop below
    224226                                                        progressBar.set((100 * (j)) / nodesLength);
    225227                                                }
     
    240242                                                                + "}"
    241243                                                                );
    242                                                
    243                                                 // Creating a TreeWalker that is used to loop over all the nodes within the document
    244                                                 JavaFX.WebEngineExecuteScript.invoke(webEngine, "var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL);");
    245 
    246                                                 Node currentNode;
    247 
    248                                                 // Looping through all the nodes in the document
    249                                                 while ((currentNode = (Node) JavaFX.WebEngineExecuteScript.invoke(webEngine, "walker.nextNode()")) != null) {
    250 
    251                                                         if (currentNode.getNodeType() == Node.TEXT_NODE || currentNode.getNodeType() == Node.ELEMENT_NODE) {
    252                                                                
    253                                                                 Object style;
    254                                                                 Object bounds;
    255 
    256                                                                 if (currentNode.getNodeType() == Node.TEXT_NODE) {
    257                                                                         // CSS style for the element
    258                                                                         style = JavaFX.JSObjectCall.invoke(window, "getComputedStyle", new Object[] { currentNode.getParentNode() });
    259 
    260                                                                         // Getting a rectangle that represents the area and position of the element
    261                                                                         bounds = JavaFX.JSObjectCall.invoke(currentNode.getParentNode(), "getBoundingClientRect", new Object[] {});
    262                                                                 } else {
    263                                                                         style = JavaFX.JSObjectCall.invoke(window, "getComputedStyle", new Object[] { currentNode });
    264 
    265                                                                         bounds = JavaFX.JSObjectCall.invoke(currentNode, "getBoundingClientRect", new Object[] {});
    266                                                                 }
    267                                                                
    268                                                                 // Bounding rectangle position is relative to the current view, so scroll position must be added to x/y
    269                                                                 // TODO: This doesn't check if an element or any of its parent elements have position:fixed set - the only
    270                                                                 // way to check seems to be to walking through the element's parents until the document root is reached
    271                                                                 float x = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "left").toString())
    272                                                                                 + Float.valueOf(JavaFX.WebEngineExecuteScript.invoke(webEngine, "window.pageXOffset").toString());
    273                                                                 float y = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "top").toString())
    274                                                                                 + Float.valueOf(JavaFX.WebEngineExecuteScript.invoke(webEngine, "window.pageYOffset").toString());
    275 
    276                                                                 float width = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "width").toString());
    277                                                                 float height = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "height").toString());
    278 
    279                                                                 // Checking if the element is actually visible on the page
    280                                                                 if (WebParser.elementVisible(x, y, width, height, style)) {
    281        
    282                                                                         // Filtering the node type, starting with text nodes
    283                                                                         if (currentNode.getNodeType() == Node.TEXT_NODE) {
    284                                                                                 String fontSize = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-size" }));
    285 
    286                                                                                 // Trimming off the units (always px) from the font size
    287                                                                                 fontSize = fontSize.substring(0, fontSize.length() - 2);
    288                                                                                
    289                                                                                 // Always returns in format "rgb(x,x,x)" or "rgba(x,x,x,x)"
    290                                                                                 String color = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "color" });
    291                                                                                
    292                                                                                 // Always returns in format "rgb(x,x,x)" or "rgba(x,x,x,x)"
    293                                                                                 String bgColor = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-color" });
    294                                                                                
    295                                                                                 String align = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "text-align" });
    296                                                                                
    297                                                                                 // Returns comma-separated list of typefaces
    298                                                                                 String typeface = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-family" });
    299 
    300                                                                                 String[] typefaces = typeface.split(", |,");
    301                                                                                
    302                                                                                 String weight = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-weight" });
    303                                                                                
    304                                                                                 String fontStyle = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-style" });
    305 
    306                                                                                 // Returns "normal" or a value in pixels (e.g. "10px")
    307                                                                                 String letterSpacing = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "letter-spacing" });
    308 
    309                                                                                 // Returns a value in pixels (e.g. "10px")
    310                                                                                 String lineHeight = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "line-height" });
    311 
    312                                                                                 String textTransform = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "text-transform" });
    313 
    314                                                                                 String linkUrl = (String) JavaFX.JSObjectGetMember.invoke(currentNode.getParentNode(), "href");
    315 
    316                                                                                 Boolean fontFound = false;
    317                                                                                 Font font = new Font(null);
    318 
    319                                                                                 // Looping through all font-families listed in the element's CSS until one that is installed is
    320                                                                                 // found, or the end of the list is reached, in which case the default font is used
    321                                                                                 for (int j = 0; j < typefaces.length && !fontFound; j++) {
    322                                                                                         if (typefaces[j].toLowerCase().equals("sans-serif")) {
    323                                                                                                 typefaces[j] = "Arial Unicode MS";
    324                                                                                         } else if (typefaces[j].toLowerCase().equals("serif")) {
    325                                                                                                 typefaces[j] = "Times New Roman";
    326                                                                                         } else if ((typefaces[j].toLowerCase().equals("arial"))) {
    327                                                                                                 // Have to use Arial Unicode, otherwise unicode characters display incorrectly
    328                                                                                                 typefaces[j] = "Arial Unicode MS";
    329                                                                                         }
    330                                                                                        
    331                                                                                         // Regex will remove any inverted commas surrounding multi-word typeface names
    332                                                                                         font = new Font(typefaces[j].replaceAll("^'|'$", ""), Font.PLAIN, 12);
    333                                                                                        
    334                                                                                         // If the font isn't found, Java just uses Font.DIALOG, so this check checks whether the font was found
    335                                                                                         if (!(font.getFamily().toLowerCase().equals(Font.DIALOG.toLowerCase()))) {
    336                                                                                                 fontFound = true;
    337                                                                                         }
    338                                                                                 }
    339 
    340                                                                                 if (font.getFamily().toLowerCase().equals(Font.DIALOG.toLowerCase())) {
    341                                                                                         font = new Font("Times New Roman", Font.PLAIN, 12);
    342                                                                                 }
    343 
    344                                                                                 String fontStyleComplete = "";
    345 
    346                                                                                 int weightInt = 0;
    347 
    348                                                                                 try {
    349                                                                                         weightInt = Integer.parseInt(weight);
    350                                                                                 } catch (NumberFormatException nfe) {
    351                                                                                         // Use default value as set above
    352                                                                                 }
    353 
    354                                                                                 // checking if font is bold - i.e. 'bold', 'bolder' or weight over 500
    355                                                                                 if (weight.toLowerCase().startsWith("bold") || weightInt > 500) {
    356                                                                                         fontStyleComplete = fontStyleComplete.concat("bold");
    357                                                                                 }
    358 
    359                                                                                 if (fontStyle.toLowerCase().equals("italic") || fontStyle.toLowerCase().equals("oblique")) {
    360                                                                                         fontStyleComplete = fontStyleComplete.concat("italic");
    361                                                                                 }
    362 
    363                                                                                 float fontSizeFloat = 12;
    364 
    365                                                                                 try {
    366                                                                                         fontSizeFloat = Float.valueOf(fontSize);
    367                                                                                 } catch (NumberFormatException nfe) {
    368                                                                                         // Use default value as set above
    369                                                                                 }
    370 
    371                                                                                 float letterSpacingFloat = -0.008f;
    372 
    373                                                                                 try {
    374                                                                                         letterSpacingFloat = (Integer.parseInt(letterSpacing.substring(0, letterSpacing.length() - 2)) / (fontSizeFloat));
    375                                                                                 } catch (NumberFormatException nfe) {
    376                                                                                         // Use default value as set above
    377                                                                                 }
    378 
    379                                                                                 float lineHeightInt = -1;
    380                                                                                
    381                                                                                 try {
    382                                                                                         lineHeightInt = (Float.parseFloat(lineHeight.substring(0, lineHeight.length() - 2)));
    383                                                                                 } catch (NumberFormatException nfe) {
    384                                                                                         // Use default value as set above
    385                                                                                 }
    386 
    387                                                                                 Text t;
    388 
    389                                                                                 String textContent = currentNode.getTextContent().replaceAll("[^\\S\\n]+", " ");
    390                                                                                 textContent = textContent.replaceAll("^(\\s)(\\n|\\r)", "");
    391 
    392                                                                                 if (textTransform.equals("uppercase")) {
    393                                                                                         textContent = textContent.toUpperCase();
    394                                                                                 } else if (textTransform.equals("lowercase")) {
    395                                                                                         textContent = textContent.toUpperCase();
    396                                                                                 }
    397 
    398                                                                                 t = frame.addText(Math.round(x), Math.round(y), textContent, null);
    399 
    400                                                                                 t.setColor(rgbStringToColor(color));
    401                                                                                 t.setBackgroundColor(rgbStringToColor(bgColor));
    402                                                                                 t.setFont(font);
    403                                                                                 t.setSize(fontSizeFloat);
    404                                                                                 t.setFontStyle(fontStyleComplete);
    405                                                                                 t.setLetterSpacing(letterSpacingFloat);
    406 
    407                                                                                 // Removing any spacing between lines allowing t.getLineHeight() to be used to get the actual height
    408                                                                                 // of just the characters (i.e. distance from ascenders to descenders)
    409                                                                                 t.setSpacing(0);
    410 
    411                                                                                 t.setSpacing(lineHeightInt - t.getLineHeight());
    412 
    413                                                                                 if (align.equals("left")) {
    414                                                                                         t.setJustification(Justification.left);
    415                                                                                 } else if (align.equals("right")) {
    416                                                                                         t.setJustification(Justification.right);
    417                                                                                 } else if (align.equals("center")) {
    418                                                                                         t.setJustification(Justification.center);
    419                                                                                 } else if (align.equals("justify")) {
    420                                                                                         t.setJustification(Justification.full);
    421                                                                                 }
    422 
    423                                                                                 // Font size is added to the item width to give a little breathing room
    424                                                                                 t.setWidth(Math.round(width + (t.getSize())));
    425 
    426                                                                                 if (!linkUrl.equals("undefined")) {
    427                                                                                         t.setAction("gotourl " + linkUrl);
    428                                                                                         t.setActionMark(false);
    429                                                                                 }
    430 
    431                                                                         } else if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
    432 
    433                                                                                 // background image, returns in format "url(protocol://absolute/path/to/img.extension)" for images,
    434                                                                                 // may also return gradients, data, etc. (not handled yet). Only need to add bg image on
    435                                                                                 // 'ELEMENT_NODE' (and not 'TEXT_NODE' otherwise there would be double-ups
    436                                                                                 String bgImage = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-image" });
    437                                                                                
    438                                                                                 String linkUrl = (String) JavaFX.JSObjectGetMember.invoke(currentNode, "href");
    439 
    440                                                                                 if (bgImage.startsWith("url(")) {
    441 
    442                                                                                         bgImage = bgImage.substring(4, bgImage.length() - 1);
    443 
    444                                                                                         String bgSize = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-size" })).toLowerCase();
    445                                                                                         String bgRepeat = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-repeat" })).toLowerCase();
    446 
    447                                                                                         // Returns "[x]px [y]px", "[x]% [y]%", "[x]px [y]%" or "[x]% [y]px"
    448                                                                                         String bgPosition = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-position" })).toLowerCase();
    449 
    450                                                                                         String[] bgOffsetCoords = bgPosition.split(" ");
    451 
    452                                                                                         int bgOffsetX = 0, bgOffsetY = 0;
    453 
    454                                                                                         float originXPercent = 0, originYPercent = 0;
    455 
    456                                                                                         int cropStartX, cropStartY, cropEndX, cropEndY;
    457 
    458                                                                                         // Converting the x and y offset values to integers (and from % to px if needed)
    459                                                                                         if (bgOffsetCoords[0].endsWith("%")) {
    460                                                                                                 bgOffsetX = (int) ((Integer.valueOf(bgOffsetCoords[0].substring(0, bgOffsetCoords[0].length() - 1)) / 100.0) * width);
    461                                                                                                 originXPercent = (Integer.valueOf(bgOffsetCoords[0].substring(0, bgOffsetCoords[0].length() - 1))) / 100f;
    462                                                                                         } else if (bgOffsetCoords[0].endsWith("px")) {
    463                                                                                                 bgOffsetX = (int) (Integer.valueOf(bgOffsetCoords[0].substring(0, bgOffsetCoords[0].length() - 2)));
    464                                                                                         }
    465 
    466                                                                                         if (bgOffsetCoords[1].endsWith("%")) {
    467                                                                                                 bgOffsetY = (int) ((Integer.valueOf(bgOffsetCoords[1].substring(0, bgOffsetCoords[1].length() - 1)) / 100.0) * height);
    468                                                                                                 originYPercent = (Integer.valueOf(bgOffsetCoords[1].substring(0, bgOffsetCoords[1].length() - 1))) / 100f;
    469                                                                                         } else if (bgOffsetCoords[1].endsWith("px")) {
    470                                                                                                 bgOffsetY = (int) (Integer.valueOf(bgOffsetCoords[1].substring(0, bgOffsetCoords[1].length() - 2)));
    471                                                                                         }
    472 
    473                                                                                         // Converting from an offset to crop coords
    474                                                                                         cropStartX = -1 * bgOffsetX;
    475                                                                                         cropEndX = (int) (cropStartX + width);
    476 
    477                                                                                         cropStartY = -1 * bgOffsetY;
    478                                                                                         cropEndY = (int) (cropStartY + height);
    479 
    480                                                                                         int bgWidth = -1;
    481 
    482                                                                                         if (bgSize.equals("cover")) {
    483                                                                                                 bgWidth = (int) width;
    484                                                                                         } else if (bgSize.equals("contain")) {
    485                                                                                                 // TODO: actually compute the appropriate width
    486                                                                                                 bgWidth = (int) width;
    487                                                                                         } else if (bgSize.equals("auto")) {
    488                                                                                                 bgWidth = -1;
    489                                                                                         } else {
    490                                                                                                 bgSize = bgSize.split(" ")[0];
    491 
    492                                                                                                 if (bgSize.endsWith("%")) {
    493                                                                                                         bgWidth = (int) ((Integer.parseInt(bgSize.replaceAll("\\D", "")) / 100.0) * width);
    494                                                                                                 } else if (bgSize.endsWith("px")) {
    495                                                                                                         bgWidth = Integer.parseInt(bgSize.replaceAll("\\D", ""));
    496                                                                                                 }
    497                                                                                         }
    498 
    499                                                                                         try {
    500                                                                                                 WebParser.addImageFromUrl(bgImage, linkUrl, frame, x, y, bgWidth, cropStartX, cropStartY, cropEndX, cropEndY, bgRepeat, originXPercent, originYPercent);
    501                                                                                         } catch (MalformedURLException mue) {
    502                                                                                                 // probably a 'data:' url, not supported yet
    503                                                                                                 mue.printStackTrace();
    504                                                                                         }
    505                                                                                 }
    506 
    507                                                                                 String imgSrc;
    508 
    509                                                                                 if (currentNode.getNodeName().toLowerCase().equals("img") && (imgSrc = JavaFX.JSObjectGetMember.invoke(currentNode, "src").toString()) != null) {
    510                                                                                         try {
    511                                                                                                 WebParser.addImageFromUrl(imgSrc, linkUrl, frame, x, y, (int) width, null, null, null, null, null, 0, 0);
    512                                                                                         } catch (MalformedURLException mue) {
    513                                                                                                 // probably a 'data:' url, not supported yet
    514                                                                                                 mue.printStackTrace();
    515                                                                                         }
    516                                                                                 }
    517                                                                         }
    518                                                                 }
    519                                                         }
    520                                                 }
    521                                                
     244
     245                                                WebParser.addPageToFrame(doc, null, window, webEngine, frame);
     246
    522247                                                progressBar.set(100);
    523248
     
    542267         */
    543268        private static Color rgbStringToColor(String rgbString) {
     269
     270                if (rgbString == null) {
     271                        return null;
     272                }
     273
    544274                // Splitting the string into 'rgb' and 'x, x, x'
    545275                String[] tmpStrings = rgbString.split("\\(|\\)");
     
    561291                } else {
    562292                        return null;
     293                }
     294        }
     295       
     296        /**
     297         * @param rootElement
     298         *            Element that will be converted (including all sub-elements)
     299         * @param backgroundColor
     300         *            String to be used as the background color of this element when added. In the format "rgb(x,x,x)" or "rgba(x,x,x,x)"
     301         * @param window
     302         *            'window' from Javascript
     303         * @param webEngine
     304         *            Web engine that the page is loaded in
     305         * @param frame
     306         *            Expeditee frame to add the converted page to
     307         * @throws IllegalArgumentException
     308         * @throws IllegalAccessException
     309         */
     310        private static void addPageToFrame(Node rootElement, Color parentBgColor, Object window, Object webEngine, Frame frame) throws InvocationTargetException, IllegalAccessException,
     311                        IllegalArgumentException {
     312               
     313                Node currentNode = rootElement;
     314
     315                Color bgColor = null;
     316
     317                if (currentNode.getNodeType() == Node.TEXT_NODE || currentNode.getNodeType() == Node.ELEMENT_NODE) {
     318                       
     319                        Object style;
     320                        Object bounds;
     321
     322                        if (currentNode.getNodeType() == Node.TEXT_NODE) {
     323                                // CSS style for the element
     324                                style = JavaFX.JSObjectCall.invoke(window, "getComputedStyle", new Object[] { currentNode.getParentNode() });
     325
     326                                // Getting a rectangle that represents the area and position of the element
     327                                bounds = JavaFX.JSObjectCall.invoke(currentNode.getParentNode(), "getBoundingClientRect", new Object[] {});
     328                        } else {
     329                                style = JavaFX.JSObjectCall.invoke(window, "getComputedStyle", new Object[] { currentNode });
     330
     331                                bounds = JavaFX.JSObjectCall.invoke(currentNode, "getBoundingClientRect", new Object[] {});
     332                        }
     333                       
     334                        // Bounding rectangle position is relative to the current view, so scroll position must be added to x/y
     335                        // TODO: This doesn't check if an element or any of its parent elements have position:fixed set - the only
     336                        // way to check seems to be to walking through the element's parents until the document root is reached
     337                        float x = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "left").toString())
     338                                        + Float.valueOf(JavaFX.WebEngineExecuteScript.invoke(webEngine, "window.pageXOffset").toString());
     339                        float y = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "top").toString())
     340                                        + Float.valueOf(JavaFX.WebEngineExecuteScript.invoke(webEngine, "window.pageYOffset").toString());
     341
     342                        float width = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "width").toString());
     343                        float height = Float.valueOf(JavaFX.JSObjectGetMember.invoke(bounds, "height").toString());
     344
     345                        // Have to get the bg color even if the element isn't visible, so it can be cascaded down to child elements
     346                        // Always returns in format "rgb(x,x,x)" or "rgba(x,x,x,x)"
     347                        String bgColorString = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-color" });
     348
     349                        bgColor = rgbStringToColor(bgColorString);
     350
     351                        bgColor = (bgColor != null ? bgColor : parentBgColor);
     352                       
     353
     354                        // Checking if the element is actually visible on the page
     355                        if (WebParser.elementVisible(x, y, width, height, style)) {
     356
     357                                // Filtering the node type, starting with text nodes
     358                                if (currentNode.getNodeType() == Node.TEXT_NODE) {
     359                                        String fontSize = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-size" }));
     360
     361                                        // Trimming off the units (always px) from the font size
     362                                        fontSize = fontSize.substring(0, fontSize.length() - 2);
     363                                       
     364                                        // Always returns in format "rgb(x,x,x)" or "rgba(x,x,x,x)"
     365                                        String color = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "color" });
     366                                       
     367                                        String align = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "text-align" });
     368                                       
     369                                        // Returns comma-separated list of typefaces
     370                                        String typeface = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-family" });
     371
     372                                        String[] typefaces = typeface.split(", |,");
     373                                       
     374                                        String weight = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-weight" });
     375                                       
     376                                        String fontStyle = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "font-style" });
     377
     378                                        // Returns "normal" or a value in pixels (e.g. "10px")
     379                                        String letterSpacing = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "letter-spacing" });
     380
     381                                        // Returns a value in pixels (e.g. "10px")
     382                                        String lineHeight = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "line-height" });
     383
     384                                        String textTransform = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "text-transform" });
     385
     386                                        String linkUrl = (String) JavaFX.JSObjectGetMember.invoke(currentNode.getParentNode(), "href");
     387
     388                                        Boolean fontFound = false;
     389                                        Font font = new Font(null);
     390
     391                                        // Looping through all font-families listed in the element's CSS until one that is installed is
     392                                        // found, or the end of the list is reached, in which case the default font is used
     393                                        for (int j = 0; j < typefaces.length && !fontFound; j++) {
     394                                                if (typefaces[j].toLowerCase().equals("sans-serif")) {
     395                                                        typefaces[j] = "Arial Unicode MS";
     396                                                } else if (typefaces[j].toLowerCase().equals("serif")) {
     397                                                        typefaces[j] = "Times New Roman";
     398                                                } else if ((typefaces[j].toLowerCase().equals("arial"))) {
     399                                                        // Have to use Arial Unicode, otherwise unicode characters display incorrectly
     400                                                        typefaces[j] = "Arial Unicode MS";
     401                                                }
     402                                               
     403                                                // Regex will remove any inverted commas surrounding multi-word typeface names
     404                                                font = new Font(typefaces[j].replaceAll("^'|'$", ""), Font.PLAIN, 12);
     405                                               
     406                                                // If the font isn't found, Java just uses Font.DIALOG, so this check checks whether the font was found
     407                                                if (!(font.getFamily().toLowerCase().equals(Font.DIALOG.toLowerCase()))) {
     408                                                        fontFound = true;
     409                                                }
     410                                        }
     411
     412                                        if (font.getFamily().toLowerCase().equals(Font.DIALOG.toLowerCase())) {
     413                                                font = new Font("Times New Roman", Font.PLAIN, 12);
     414                                        }
     415
     416                                        String fontStyleComplete = "";
     417
     418                                        int weightInt = 0;
     419
     420                                        try {
     421                                                weightInt = Integer.parseInt(weight);
     422                                        } catch (NumberFormatException nfe) {
     423                                                // Use default value as set above
     424                                        }
     425
     426                                        // checking if font is bold - i.e. 'bold', 'bolder' or weight over 500
     427                                        if (weight.toLowerCase().startsWith("bold") || weightInt > 500) {
     428                                                fontStyleComplete = fontStyleComplete.concat("bold");
     429                                        }
     430
     431                                        if (fontStyle.toLowerCase().equals("italic") || fontStyle.toLowerCase().equals("oblique")) {
     432                                                fontStyleComplete = fontStyleComplete.concat("italic");
     433                                        }
     434
     435                                        float fontSizeFloat = 12;
     436
     437                                        try {
     438                                                fontSizeFloat = Float.valueOf(fontSize);
     439                                        } catch (NumberFormatException nfe) {
     440                                                // Use default value as set above
     441                                        }
     442
     443                                        float letterSpacingFloat = -0.008f;
     444
     445                                        try {
     446                                                letterSpacingFloat = (Integer.parseInt(letterSpacing.substring(0, letterSpacing.length() - 2)) / (fontSizeFloat));
     447                                        } catch (NumberFormatException nfe) {
     448                                                // Use default value as set above
     449                                        }
     450
     451                                        float lineHeightInt = -1;
     452                                       
     453                                        try {
     454                                                lineHeightInt = (Float.parseFloat(lineHeight.substring(0, lineHeight.length() - 2)));
     455                                        } catch (NumberFormatException nfe) {
     456                                                // Use default value as set above
     457                                        }
     458
     459                                        Text t;
     460
     461                                        String textContent = currentNode.getTextContent().replaceAll("[^\\S\\n]+", " ");
     462                                        textContent = textContent.replaceAll("^(\\s)(\\n|\\r)", "");
     463
     464                                        if (textTransform.equals("uppercase")) {
     465                                                textContent = textContent.toUpperCase();
     466                                        } else if (textTransform.equals("lowercase")) {
     467                                                textContent = textContent.toUpperCase();
     468                                        }
     469
     470                                        t = frame.addText(Math.round(x), Math.round(y), textContent, null);
     471
     472                                        t.setColor(rgbStringToColor(color));
     473                                        t.setBackgroundColor(bgColor);
     474                                        t.setFont(font);
     475                                        t.setSize(fontSizeFloat);
     476                                        t.setFontStyle(fontStyleComplete);
     477                                        t.setLetterSpacing(letterSpacingFloat);
     478
     479                                        // Removing any spacing between lines allowing t.getLineHeight() to be used to get the actual height
     480                                        // of just the characters (i.e. distance from ascenders to descenders)
     481                                        t.setSpacing(0);
     482
     483                                        t.setSpacing(lineHeightInt - t.getLineHeight());
     484
     485                                        if (align.equals("left")) {
     486                                                t.setJustification(Justification.left);
     487                                        } else if (align.equals("right")) {
     488                                                t.setJustification(Justification.right);
     489                                        } else if (align.equals("center")) {
     490                                                t.setJustification(Justification.center);
     491                                        } else if (align.equals("justify")) {
     492                                                t.setJustification(Justification.full);
     493                                        }
     494
     495                                        // Font size is added to the item width to give a little breathing room
     496                                        t.setWidth(Math.round(width + (t.getSize())));
     497
     498                                        if (!linkUrl.equals("undefined")) {
     499                                                t.setAction("gotourl " + linkUrl);
     500                                                t.setActionMark(false);
     501                                        }
     502
     503                                } else if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
     504
     505                                        // background image, returns in format "url(protocol://absolute/path/to/img.extension)" for images,
     506                                        // may also return gradients, data, etc. (not handled yet). Only need to add bg image on
     507                                        // 'ELEMENT_NODE' (and not 'TEXT_NODE' otherwise there would be double-ups
     508                                        String bgImage = (String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-image" });
     509                                       
     510                                        String linkUrl = (String) JavaFX.JSObjectGetMember.invoke(currentNode, "href");
     511
     512                                        if (bgImage.startsWith("url(")) {
     513
     514                                                bgImage = bgImage.substring(4, bgImage.length() - 1);
     515
     516                                                String bgSize = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-size" })).toLowerCase();
     517                                                String bgRepeat = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-repeat" })).toLowerCase();
     518
     519                                                // Returns "[x]px [y]px", "[x]% [y]%", "[x]px [y]%" or "[x]% [y]px"
     520                                                String bgPosition = ((String) JavaFX.JSObjectCall.invoke(style, "getPropertyValue", new Object[] { "background-position" })).toLowerCase();
     521
     522                                                String[] bgOffsetCoords = bgPosition.split(" ");
     523
     524                                                int bgOffsetX = 0, bgOffsetY = 0;
     525
     526                                                float originXPercent = 0, originYPercent = 0;
     527
     528                                                int cropStartX, cropStartY, cropEndX, cropEndY;
     529
     530                                                // Converting the x and y offset values to integers (and from % to px if needed)
     531                                                if (bgOffsetCoords[0].endsWith("%")) {
     532                                                        bgOffsetX = (int) ((Integer.valueOf(bgOffsetCoords[0].substring(0, bgOffsetCoords[0].length() - 1)) / 100.0) * width);
     533                                                        originXPercent = (Integer.valueOf(bgOffsetCoords[0].substring(0, bgOffsetCoords[0].length() - 1))) / 100f;
     534                                                } else if (bgOffsetCoords[0].endsWith("px")) {
     535                                                        bgOffsetX = (int) (Integer.valueOf(bgOffsetCoords[0].substring(0, bgOffsetCoords[0].length() - 2)));
     536                                                }
     537
     538                                                if (bgOffsetCoords[1].endsWith("%")) {
     539                                                        bgOffsetY = (int) ((Integer.valueOf(bgOffsetCoords[1].substring(0, bgOffsetCoords[1].length() - 1)) / 100.0) * height);
     540                                                        originYPercent = (Integer.valueOf(bgOffsetCoords[1].substring(0, bgOffsetCoords[1].length() - 1))) / 100f;
     541                                                } else if (bgOffsetCoords[1].endsWith("px")) {
     542                                                        bgOffsetY = (int) (Integer.valueOf(bgOffsetCoords[1].substring(0, bgOffsetCoords[1].length() - 2)));
     543                                                }
     544
     545                                                // Converting from an offset to crop coords
     546                                                cropStartX = -1 * bgOffsetX;
     547                                                cropEndX = (int) (cropStartX + width);
     548
     549                                                cropStartY = -1 * bgOffsetY;
     550                                                cropEndY = (int) (cropStartY + height);
     551
     552                                                int bgWidth = -1;
     553
     554                                                if (bgSize.equals("cover")) {
     555                                                        bgWidth = (int) width;
     556                                                } else if (bgSize.equals("contain")) {
     557                                                        // TODO: actually compute the appropriate width
     558                                                        bgWidth = (int) width;
     559                                                } else if (bgSize.equals("auto")) {
     560                                                        bgWidth = -1;
     561                                                } else {
     562                                                        bgSize = bgSize.split(" ")[0];
     563
     564                                                        if (bgSize.endsWith("%")) {
     565                                                                bgWidth = (int) ((Integer.parseInt(bgSize.replaceAll("\\D", "")) / 100.0) * width);
     566                                                        } else if (bgSize.endsWith("px")) {
     567                                                                bgWidth = Integer.parseInt(bgSize.replaceAll("\\D", ""));
     568                                                        }
     569                                                }
     570
     571                                                try {
     572                                                        WebParser.addImageFromUrl(bgImage, linkUrl, frame, x, y, bgWidth, cropStartX, cropStartY, cropEndX, cropEndY, bgRepeat, originXPercent, originYPercent);
     573                                                } catch (MalformedURLException mue) {
     574                                                        // probably a 'data:' url, not supported yet
     575                                                        mue.printStackTrace();
     576                                                } catch (IOException e) {
     577                                                        // TODO Auto-generated catch block
     578                                                        e.printStackTrace();
     579                                                }
     580                                        }
     581
     582                                        String imgSrc;
     583
     584                                        if (currentNode.getNodeName().toLowerCase().equals("img") && (imgSrc = JavaFX.JSObjectGetMember.invoke(currentNode, "src").toString()) != null) {
     585                                                try {
     586                                                        WebParser.addImageFromUrl(imgSrc, linkUrl, frame, x, y, (int) width, null, null, null, null, null, 0, 0);
     587                                                } catch (MalformedURLException mue) {
     588                                                        // probably a 'data:' url, not supported yet
     589                                                        mue.printStackTrace();
     590                                                } catch (IOException e) {
     591                                                        // TODO Auto-generated catch block
     592                                                        e.printStackTrace();
     593                                                }
     594                                        }
     595                                }
     596                        }
     597
     598                        Node childNode = currentNode.getFirstChild();
     599
     600                        while (childNode != null) {
     601                                addPageToFrame(childNode, bgColor, window, webEngine, frame);
     602                                childNode = childNode.getNextSibling();
     603                        }
    563604                }
    564605        }
Note: See TracChangeset for help on using the changeset viewer.