Source Code Cross Referenced for XhtmlCssEngine.java in  » IDE-Netbeans » visualweb.api.designer » org » netbeans » modules » visualweb » designer » cssengine » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » visualweb.api.designer » org.netbeans.modules.visualweb.designer.cssengine 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.netbeans.modules.visualweb.designer.cssengine;
0042:
0043:        import org.netbeans.modules.visualweb.api.designer.cssengine.StyleRefreshable;
0044:        import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
0045:        import org.netbeans.modules.visualweb.spi.designer.cssengine.CssUserAgentInfo;
0046:        import java.io.*;
0047:        import java.net.URL;
0048:        import java.util.ArrayList;
0049:        import java.util.HashMap;
0050:        import java.util.Iterator;
0051:        import java.util.LinkedHashMap;
0052:        import java.util.Map;
0053:
0054:        import org.apache.batik.css.engine.CSSContext;
0055:        import org.apache.batik.css.engine.CSSEngine;
0056:        import org.apache.batik.css.engine.CSSEngineUserAgent;
0057:        import org.apache.batik.css.engine.CSSStylableElement;
0058:        import org.apache.batik.css.engine.StyleDeclaration;
0059:        import org.apache.batik.css.engine.StyleMap;
0060:        import org.apache.batik.css.engine.StyleSheet;
0061:        import org.apache.batik.css.engine.value.*;
0062:        import org.apache.batik.css.engine.value.ShorthandManager;
0063:        import org.apache.batik.css.engine.value.ValueManager;
0064:        import org.apache.batik.css.engine.value.css2.ClipManager;
0065:        import org.apache.batik.css.engine.value.css2.DirectionManager;
0066:        import org.apache.batik.css.engine.value.css2.DisplayManager;
0067:        import org.apache.batik.css.engine.value.css2.FontFamilyManager;
0068:        import org.apache.batik.css.engine.value.css2.FontSizeAdjustManager;
0069:        import org.apache.batik.css.engine.value.css2.FontSizeManager;
0070:        import org.apache.batik.css.engine.value.css2.FontStretchManager;
0071:        import org.apache.batik.css.engine.value.css2.FontStyleManager;
0072:        import org.apache.batik.css.engine.value.css2.FontVariantManager;
0073:        import org.apache.batik.css.engine.value.css2.FontWeightManager;
0074:        import org.apache.batik.css.engine.value.css2.OverflowManager;
0075:        import org.apache.batik.css.engine.value.css2.TextDecorationManager;
0076:        import org.apache.batik.css.engine.value.css2.UnicodeBidiManager;
0077:        import org.apache.batik.css.engine.value.css2.VisibilityManager;
0078:        import org.apache.batik.css.engine.value.svg.ColorManager;
0079:        import org.apache.batik.css.parser.ExtendedParser;
0080:        import org.apache.batik.css.parser.ExtendedParserWrapper;
0081:        import org.apache.batik.css.parser.Parser;
0082:        import org.openide.ErrorManager;
0083:        import org.openide.util.NbBundle;
0084:        import org.w3c.css.sac.CSSParseException;
0085:        import org.w3c.css.sac.ErrorHandler;
0086:        import org.w3c.css.sac.InputSource;
0087:        import org.w3c.css.sac.SACMediaList;
0088:        import org.w3c.dom.Attr;
0089:        import org.w3c.dom.DOMException;
0090:        import org.w3c.dom.Document;
0091:        import org.w3c.dom.DocumentFragment;
0092:        import org.w3c.dom.Element;
0093:        import org.w3c.dom.Node;
0094:
0095:        import org.netbeans.modules.visualweb.designer.html.HtmlAttribute;
0096:        import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0097:        import org.w3c.dom.css.CSSPrimitiveValue;
0098:
0099:        /**
0100:         * This class plugs in CSS support for XHTML
0101:         *
0102:         * @author Tor Norbye
0103:         * @author Carl Quinn
0104:         */
0105:        class XhtmlCssEngine extends CSSEngine {
0106:            private static StyleSheet defaultRules = null;
0107:
0108:            /**
0109:             * The value managers for XHTML - KEEP IN SYNC WITH PROPERTY INDICES IN XhtmlCss.java
0110:             */
0111:            public static final ValueManager[] XHTML_VALUE_MANAGERS = {
0112:
0113:                    // Try to keep the order alphabetical, because in
0114:                    // StyleMap.toStyleString I put the user's properties back out
0115:                    // in the below order (e.g. when manipulating a style string
0116:                    // indirectly such as by dragging a component, the styles
0117:                    // get reordered to the below order.)
0118:                    new BackgroundColorManager(),
0119:                    new BackgroundImageManager(),
0120:
0121:                    // If you add this:
0122:                    // new BackgroundAttachmentManager(),
0123:                    // then update the BackgroundShorthandManager too
0124:                    new BackgroundPositionManager(),
0125:                    new BackgroundRepeatManager(),
0126:                    new BorderCollapseManager(),
0127:                    new BorderColorManager(
0128:                            CssConstants.CSS_BORDER_LEFT_COLOR_PROPERTY),
0129:                    new BorderColorManager(
0130:                            CssConstants.CSS_BORDER_RIGHT_COLOR_PROPERTY),
0131:                    new BorderColorManager(
0132:                            CssConstants.CSS_BORDER_TOP_COLOR_PROPERTY),
0133:                    new BorderColorManager(
0134:                            CssConstants.CSS_BORDER_BOTTOM_COLOR_PROPERTY),
0135:                    new BorderStyleManager(
0136:                            CssConstants.CSS_BORDER_LEFT_STYLE_PROPERTY),
0137:                    new BorderStyleManager(
0138:                            CssConstants.CSS_BORDER_RIGHT_STYLE_PROPERTY),
0139:                    new BorderStyleManager(
0140:                            CssConstants.CSS_BORDER_TOP_STYLE_PROPERTY),
0141:                    new BorderStyleManager(
0142:                            CssConstants.CSS_BORDER_BOTTOM_STYLE_PROPERTY),
0143:                    new BorderWidthManager(
0144:                            CssConstants.CSS_BORDER_LEFT_WIDTH_PROPERTY),
0145:                    new BorderWidthManager(
0146:                            CssConstants.CSS_BORDER_RIGHT_WIDTH_PROPERTY),
0147:                    new BorderWidthManager(
0148:                            CssConstants.CSS_BORDER_TOP_WIDTH_PROPERTY),
0149:                    new BorderWidthManager(
0150:                            CssConstants.CSS_BORDER_BOTTOM_WIDTH_PROPERTY),
0151:                    new CaptionSideManager(),
0152:                    new ClearManager(),
0153:                    new ClipManager(),
0154:                    new ColorManager(),
0155:                    new DirectionManager(),
0156:                    new DisplayManager(),
0157:                    new FloatManager(),
0158:                    new FontFamilyManager(),
0159:                    new FontSizeManager(),
0160:                    new FontSizeAdjustManager(),
0161:                    new FontStretchManager(),
0162:                    new FontStyleManager(),
0163:                    new FontVariantManager(),
0164:                    new FontWeightManager(),
0165:                    new HeightManager(),
0166:                    new LineHeightManager(),
0167:                    new ListStyleImageManager(),
0168:                    new ListStyleTypeManager(),
0169:
0170:                    // ListStylePositionManager: if you insert this, adjust
0171:                    // ListStyleShorthandManager to reference it too
0172:                    new MarginManager(CssConstants.CSS_MARGIN_LEFT_PROPERTY),
0173:                    new MarginManager(CssConstants.CSS_MARGIN_RIGHT_PROPERTY),
0174:                    new MarginManager(CssConstants.CSS_MARGIN_TOP_PROPERTY),
0175:                    new MarginManager(CssConstants.CSS_MARGIN_BOTTOM_PROPERTY),
0176:                    new OffsetManager(CssConstants.CSS_LEFT_PROPERTY,
0177:                            OffsetManager.HORIZONTAL_ORIENTATION),
0178:                    new OffsetManager(CssConstants.CSS_RIGHT_PROPERTY,
0179:                            OffsetManager.HORIZONTAL_ORIENTATION),
0180:                    new OffsetManager(CssConstants.CSS_TOP_PROPERTY,
0181:                            OffsetManager.VERTICAL_ORIENTATION),
0182:                    new OffsetManager(CssConstants.CSS_BOTTOM_PROPERTY,
0183:                            OffsetManager.VERTICAL_ORIENTATION),
0184:                    new OverflowManager(),
0185:                    new PaddingManager(CssConstants.CSS_PADDING_LEFT_PROPERTY),
0186:                    new PaddingManager(CssConstants.CSS_PADDING_RIGHT_PROPERTY),
0187:                    new PaddingManager(CssConstants.CSS_PADDING_TOP_PROPERTY),
0188:                    new PaddingManager(CssConstants.CSS_PADDING_BOTTOM_PROPERTY),
0189:                    new PositionManager(), new TableLayoutManager(),
0190:                    new TextAlignManager(), new TextDecorationManager(),
0191:                    new TextIndentManager(), new TextTransformManager(),
0192:                    new UnicodeBidiManager(), new VerticalAlignmentManager(),
0193:                    new VisibilityManager(), new WhitespaceManager(),
0194:                    new WidthManager(), new ZIndexManager(),
0195:                    new RaveLayoutManager(), new RaveLinkColorManager() };
0196:
0197:            /**
0198:             * The shorthand managers for XHTML.
0199:             */
0200:            public static final ShorthandManager[] XHTML_SHORTHAND_MANAGERS = {
0201:                    new BackgroundShorthandManager(),
0202:                    new BorderShorthandManager(),
0203:                    new BorderColorShorthandManager(),
0204:                    new BorderStyleShorthandManager(),
0205:                    new BorderWidthShorthandManager(),
0206:                    new BorderSideShorthandManager(
0207:                            CssConstants.CSS_BORDER_LEFT_PROPERTY,
0208:                            CssConstants.CSS_BORDER_LEFT_WIDTH_PROPERTY,
0209:                            CssConstants.CSS_BORDER_LEFT_STYLE_PROPERTY,
0210:                            CssConstants.CSS_BORDER_LEFT_COLOR_PROPERTY),
0211:                    new BorderSideShorthandManager(
0212:                            CssConstants.CSS_BORDER_RIGHT_PROPERTY,
0213:                            CssConstants.CSS_BORDER_RIGHT_WIDTH_PROPERTY,
0214:                            CssConstants.CSS_BORDER_RIGHT_STYLE_PROPERTY,
0215:                            CssConstants.CSS_BORDER_RIGHT_COLOR_PROPERTY),
0216:                    new BorderSideShorthandManager(
0217:                            CssConstants.CSS_BORDER_TOP_PROPERTY,
0218:                            CssConstants.CSS_BORDER_TOP_WIDTH_PROPERTY,
0219:                            CssConstants.CSS_BORDER_TOP_STYLE_PROPERTY,
0220:                            CssConstants.CSS_BORDER_TOP_COLOR_PROPERTY),
0221:                    new BorderSideShorthandManager(
0222:                            CssConstants.CSS_BORDER_BOTTOM_PROPERTY,
0223:                            CssConstants.CSS_BORDER_BOTTOM_WIDTH_PROPERTY,
0224:                            CssConstants.CSS_BORDER_BOTTOM_STYLE_PROPERTY,
0225:                            CssConstants.CSS_BORDER_BOTTOM_COLOR_PROPERTY),
0226:                    new FontShorthandManager(),
0227:                    new ListStyleShorthandManager(),
0228:                    new MarginShorthandManager(), new PaddingShorthandManager() };
0229:
0230:            /** Shared instance of an index map into the value manager names */
0231:            static org.apache.batik.css.engine.StringIntMap valueManagerIndex;
0232:
0233:            /** Shared instance of an index map into the shorthand manager names */
0234:            static org.apache.batik.css.engine.StringIntMap shorthandManagerIndex;
0235:
0236:            static {
0237:                int len = XHTML_VALUE_MANAGERS.length;
0238:                valueManagerIndex = new org.apache.batik.css.engine.StringIntMap(
0239:                        len);
0240:
0241:                for (int i = len - 1; i >= 0; --i) {
0242:                    String pn = XHTML_VALUE_MANAGERS[i].getPropertyName();
0243:                    valueManagerIndex.put(pn, i);
0244:                }
0245:
0246:                len = XHTML_SHORTHAND_MANAGERS.length;
0247:                shorthandManagerIndex = new org.apache.batik.css.engine.StringIntMap(
0248:                        len);
0249:
0250:                for (int i = len - 1; i >= 0; --i) {
0251:                    String pn = XHTML_SHORTHAND_MANAGERS[i].getPropertyName();
0252:                    shorthandManagerIndex.put(pn, i);
0253:                }
0254:            }
0255:
0256:            // Map for quick lookup of attribute aliases
0257:            protected static final StringIntMap attributes = new StringIntMap(
0258:                    20);
0259:
0260:            static {
0261:                attributes.put(HtmlAttribute.LINK, HtmlAttribute.LINK_ID);
0262:                attributes.put(HtmlAttribute.ALIGN, HtmlAttribute.ALIGN_ID);
0263:                attributes.put(HtmlAttribute.VALIGN, HtmlAttribute.VALIGN_ID);
0264:                attributes.put(HtmlAttribute.BGCOLOR, HtmlAttribute.BGCOLOR_ID);
0265:                attributes.put(HtmlAttribute.CLEAR, HtmlAttribute.CLEAR_ID);
0266:                attributes.put(HtmlAttribute.BACKGROUND,
0267:                        HtmlAttribute.BACKGROUND_ID);
0268:                attributes.put(HtmlAttribute.TEXT, HtmlAttribute.TEXT_ID);
0269:                attributes.put(HtmlAttribute.WIDTH, HtmlAttribute.WIDTH_ID);
0270:                attributes.put(HtmlAttribute.HEIGHT, HtmlAttribute.HEIGHT_ID);
0271:                attributes.put(HtmlAttribute.NOWRAP, HtmlAttribute.NOWRAP_ID);
0272:                attributes.put(HtmlAttribute.BORDER, HtmlAttribute.BORDER_ID);
0273:                attributes.put(HtmlAttribute.COLOR, HtmlAttribute.COLOR_ID);
0274:                attributes.put(HtmlAttribute.SIZE, HtmlAttribute.SIZE_ID);
0275:                attributes.put(HtmlAttribute.FACE, HtmlAttribute.FACE_ID);
0276:                attributes.put(HtmlAttribute.TYPE, HtmlAttribute.TYPE_ID);
0277:            }
0278:
0279:            /** Error Handler which does nothing */
0280:            public static final ErrorHandler SILENT_ERROR_HANDLER = new ErrorHandler() {
0281:                public void error(CSSParseException cp) {
0282:                }
0283:
0284:                public void fatalError(CSSParseException cp) {
0285:                }
0286:
0287:                public void warning(CSSParseException cp) {
0288:                }
0289:            };
0290:
0291:            // <markup_separation>
0292:            //    private MarkupUnit unit;
0293:            // </markup_separation>
0294:            private ErrorHandler errorHandler;
0295:
0296:            /**
0297:             * Creates a new XhtmlCssEngine
0298:             * @param doc The associated document.
0299:             * @param uri The document URI.
0300:             * @param p The CSS parser to use.
0301:             * @param ctx The CSS context.
0302:             */
0303:            // <markup_separation>
0304:            //    private XhtmlCssEngine(Document doc, URL uri, ExtendedParser p, CSSContext ctx, MarkupUnit unit) {
0305:            // ====
0306:            private XhtmlCssEngine(Document doc, URL uri, ExtendedParser p,
0307:                    CSSContext ctx) {
0308:                // </markup_separation>
0309:                super (doc, uri, p, XHTML_VALUE_MANAGERS,
0310:                        XHTML_SHORTHAND_MANAGERS, null, null,
0311:                        HtmlAttribute.STYLE, null, HtmlAttribute.CLASS, true,
0312:                        null, ctx);
0313:
0314:                // SVG defines line-height to be font-size.
0315:                // What about XHTML?
0316:                //lineHeightIndex = fontSizeIndex;
0317:                // <markup_separation>
0318:                //        this.unit = unit;
0319:                // </markup_separation>
0320:
0321:                assert (XhtmlCss.FINAL_INDEX + 1) == XHTML_VALUE_MANAGERS.length;
0322:
0323:                // Initialize indices since we've commented that out from
0324:                // the superclass
0325:                indexes = valueManagerIndex;
0326:                fontSizeIndex = XhtmlCss.FONT_SIZE_INDEX;
0327:                lineHeightIndex = XhtmlCss.LINE_HEIGHT_INDEX;
0328:                colorIndex = XhtmlCss.COLOR_INDEX;
0329:                shorthandIndexes = shorthandManagerIndex;
0330:            }
0331:
0332:            /*
0333:             * TODO: Consider a performance optimization described by David Hyatt of Gecko and
0334:             * later Safari fame, listed here: http://weblogs.mozillazine.org/hyatt/archives/2005_05.html#007507
0335:
0336:            One of the most interesting problems (to me at least) in browser
0337:            layout engines is how to implement a style system that can
0338:            determine the style information for elements on a page
0339:            efficiently. I worked on this extensively in the Gecko layout
0340:            engine during my time at AOL and I've also done a lot of work on
0341:            it for WebCore at Apple. My ideal implementation would actually be
0342:            a hybrid of the two systems, since some of the optimizations I've
0343:            done exist only in one engine or the other.
0344:
0345:            When dealing with style information like font size or text color,
0346:            you have both the concept of back end information, what was
0347:            specified in the style rule, and the concept of front end
0348:            information, the computed result that you'll actually use when
0349:            rendering. The interesting problem is how to compute this front
0350:            end information for a given element efficiently.
0351:
0352:            Back end information can be specified in two different ways. It
0353:            can either be specified using CSS syntax, whether in a stylesheet
0354:            or in an inline style attribute on the element itself, or it is
0355:            implicitly present because another attribute on the element
0356:            specified presentational information. An example of such an
0357:            attribute would be the color attribute on the font tag. Both
0358:            WebCore and Gecko use the term mapped attribute to describe an
0359:            attribute whose value (or even mere presence) maps to some
0360:            implicit style declaration.
0361:
0362:            A rule in CSS consists of two pieces. There is the selector, that
0363:            bit of information that says under what conditions the rule should
0364:            match a given element, and there is the declaration, a list of
0365:            property/value pairs that should be applied to the element should
0366:            the selector be matched.
0367:
0368:            All back end information can ultimately be thought of as supplying
0369:            a declaration. A normal rule in a stylesheet that is matched has
0370:            the declaration specified as part of the rule. An inline style
0371:            attribute on an element has no selector and is simply a
0372:            declaration that always applies to that element. Similarly each
0373:            individual mapped attribute (like the color and face attributes on
0374:            the font tag) can be thought of as supplying a declaration as
0375:            well.
0376:
0377:            Therefore the process of computing the style information for an
0378:            element can be broken down into two phases. The first phase is to
0379:            determine what set of declarations apply to an element. Once that
0380:            back end information has been determined, the second phase is to
0381:            take that back end information and quickly determine the
0382:            information that should be used when rendering.
0383:
0384:            WebCore (in upcoming Safari releases) has a really cool
0385:            optimization that I came up with to avoid even having to compute
0386:            the set of declarations that apply to an element. This
0387:            optimization in practice results in not even having to match style
0388:            for about 60% of the elements on your page.
0389:
0390:            The idea behind the optimization is to recognize when two elements
0391:            in a page are going to have the same style through DOM (and other
0392:            state) inspection and to simply share the front end style
0393:            information between those two elements whenever possible.
0394:
0395:            There are a number of conditions that must be met in order for
0396:            this sharing to be possible:
0397:            
0398:             (1) The elements must be in the same mouse state (e.g., one can't
0399:                 be in :hover while the other isn't)
0400:            (2) Neither element should have an id
0401:            (3) The tag names should match
0402:            (4) The class attributes should match
0403:            (5) The set of mapped attributes must be identical
0404:            (6) The link states must match
0405:            (7) The focus states must match
0406:            (8) Neither element should be affected by attribute selectors,
0407:                where affected is defined as having any selector match that
0408:                uses an attribute selector in any position within the selector
0409:                at all
0410:            (9) There must be no inline style attribute on the elements
0411:            (10) There must be no sibling selectors in use at all. WebCore
0412:                 simply throws a global switch when any sibling selector is
0413:                 encountered and disables style sharing for the entire
0414:                 document when they are present. This includes the + selector
0415:                 and selectors like :first-child and :last-child.
0416:
0417:            The algorithm to locate a shared style then goes something like
0418:            this. You walk through your previous siblings and for each one see
0419:            if the above 10 conditions are met. If you find a match, then
0420:            simply share your style information with the other element. Such a
0421:            system obviously assumes a reference counting model for your front
0422:            end style information.
0423:
0424:            Where this optimization kicks into high gear, however, is that it
0425:            doesn't have to give up if no siblings can be located. Because the
0426:            detection of identical style contexts is essentially O(1), nothing
0427:            more than a straight pointer comparison, you can easily look for
0428:            cousins of your element and still share style with those elements.
0429:
0430:            The way this works is that if you can't locate a sibling, you can
0431:            go up to a parent element and attempt to find a sibling or cousin
0432:            of the parent element that has the same style pointer. If you find
0433:            such an element, you can then drill back down into its children
0434:            and attempt to find a match.
0435:
0436:            This means that for HTML like the following:
0437:
0438:            <table>
0439:            <tr class='row'>
0440:            <td class='cell' width=300 nowrap>Cell One</td>
0441:            </tr>
0442:            <tr class='row'>
0443:            <td class='cell' width=300 nowrap>Cell Two</td>
0444:            </tr>
0445:
0446:            In the above example, not only do the two rows share the same
0447:            style information, but the two cells do as well. This optimization
0448:            works extremely well for both old-school HTML (in which many
0449:            deprecated presentational tags are used) and newer HTML (in which
0450:            class attributes might figure more prominently).
0451:
0452:            Once the engine determines that a style can't be shared, i.e.,
0453:            that no pre-existing front end style pointer is available, then
0454:            it's time to figure out the set of declarations that match a given
0455:            element. It is obvious that for inline style attributes and mapped
0456:            attributes that you can find the corresponding declaration
0457:            quickly. The inline style declaration can be owned by the element,
0458:            and the mapped attributes can be kept in a document-level
0459:            hash. WebCore has a bit of an edge over Gecko here in that it
0460:            treats each individual mapped attribute on an element as a
0461:            separate declaration, whereas Gecko hashes all of the mapped
0462:            attributes on an element as a single "rule." This means that Gecko
0463:            will not be able to share the mapped attribute declaration for the
0464:            following two elements:
0465:
0466:            <img width=300 border=0>
0467:            <img width=500 border=0>
0468:
0469:            WebCore creates three unique declarations and hashes them, one for
0470:            a width of 300, one for a width of 500, and one for a border of
0471:            0. Gecko creates two different "rules," one for
0472:            (width=300,border=0) and another for (width=500,border=0). As you
0473:            can see in such a system, you will frequently not be able to treat
0474:            the identical border attributes as the same.
0475:
0476:            Aside from this difference in mapped attribute handling, the two
0477:            engines employ a similar optimization for quickly determining
0478:            matching stylesheet rules called rule filtering.
0479:            [removed - this is done.]
0480:
0481:            This brings us to the final phase of the style computation, which
0482:            is taking the set of matches and quickly computing the appropriate
0483:            front end style information. It is here that Gecko really
0484:            shines. What I implemented in Gecko was a data structure called
0485:            the rule tree for efficient storing of cached style information
0486:            that can be shared *even when* two elements are not necessarily
0487:            the same.
0488:
0489:            The idea behind the rule tree is as follows. You can think of the
0490:            universe of possible rules in your document as an alphabet and the
0491:            set of rules that are matched by an element as a given input
0492:            word. For example, imagine that you had 26 rules in a stylesheet
0493:            and you labeled them A-Z. One element might match three rules in
0494:            the sheet, thus forming the input word "C-A-T" or another might
0495:            form the input word "D-O-G."
0496:
0497:            There are several important observations one can make once you
0498:            formulate the problem this way. The first is that words that are
0499:            prefixes of a larger word will end up applying the same set of
0500:            rules. All additional letters in the word do is result in the
0501:            application of more declarations. Thus the rule tree is
0502:            effectively a lexicographic tree of nodes, with each node in a
0503:            tree being created lazily as you walk the tree spelling out a
0504:            given word.
0505:
0506:            This system allows you to cache style information at each node in
0507:            the tree. This means that once you've looked up the word
0508:            "C-A-T-E-R-W-A-U-L", and cached information at all of the nodes,
0509:            then looking up the word "C-A-T" becomes more efficient.
0510:
0511:            In order to make the caching efficient, properties can be grouped
0512:            into categories, with the primary criterion for categorization
0513:            being whether the property inherits by default. It's also
0514:            important to group properties together that would logically be
0515:            specified together, so that when a fault occurs and you have to
0516:            make a copy of a given struct, you do so knowing that the other
0517:            values in the struct were probably going to be different anyway.
0518:
0519:            Once you have the properties grouped into categories like the
0520:            border struct or the background struct, then you can either store
0521:            these structs in the rule tree or as part of a style tree that
0522:            more or less matches the structure of the document. Inheritance
0523:            has to apply down the style tree and tends to force a fault,
0524:            whereas non-inherited properties can usually be cached in the rule
0525:            tree for easy access.
0526:
0527:            WebCore doesn't contain a rule tree, but it is smart enough to
0528:            refcount the structs and share them as long as no properties have
0529:            been set in the struct. In practice this works pretty well but is
0530:            not as ideal as the rule tree solution.
0531:             */
0532:
0533:            /** Create a new engine and associate it with the given document */
0534:            // <markup_separation>
0535:            //    public static XhtmlCssEngine create(RaveDocument doc, MarkupUnit unit, URL url) {
0536:            // ====
0537:            static XhtmlCssEngine create(Document doc, URL url,
0538:                    CssUserAgentInfo userAgentInfo) {
0539:                if (doc == null) {
0540:                    throw new NullPointerException("Document many not be null!"); // NOI18N
0541:                }
0542:
0543:                // </markup_separation>
0544:                UserAgent userAgent = new UserAgent(userAgentInfo);
0545:                DesignerContext ctx = new DesignerContext(doc, userAgent,
0546:                        userAgentInfo);
0547:                //        Parser p = new org.apache.batik.css.parser.Parser()
0548:                Parser p = new RaveParser();
0549:                ExtendedParser ep = ExtendedParserWrapper.wrap(p);
0550:                // <markup_separation>
0551:                //        XhtmlCssEngine engine = new XhtmlCssEngine(doc, url, ep, ctx, unit);
0552:                // ====
0553:                XhtmlCssEngine engine = new XhtmlCssEngine(doc, url, ep, ctx);
0554:                // </markup_separation>
0555:                ctx.setEngine(engine);
0556:                engine.setUserAgentStyleSheet(getUserAgentStyleSheet(engine));
0557:
0558:                // <moved to caller this is not interesting for the engine itself>
0559:                //        if (doc != null) {
0560:                //            doc.setCssEngine(engine);
0561:                //        }
0562:                // </moved to caller>
0563:
0564:                engine.setCSSEngineUserAgent(userAgent);
0565:                engine.setMedia(userAgent.getMedia());
0566:
0567:                /* TODO User defined stylesheets not yet supported
0568:                String uri = userAgent.getUserStyleSheetURI();
0569:                if (uri != null) {
0570:                    try {
0571:                        URL url = new URL(uri);
0572:                        eng.setUserAgentStyleSheet
0573:                            (eng.parseStyleSheet(url, "all"));
0574:                    } catch (MalformedURLException e) {
0575:                        userAgent.displayError(e);
0576:                    }
0577:                }
0578:                engine.setAlternateStyleSheet(userAgent.getAlternateStyleSheet());
0579:                 */
0580:                return engine;
0581:            }
0582:
0583:            private static StyleSheet getUserAgentStyleSheet(CSSEngine engine) {
0584:                if (defaultRules == null) {
0585:                    URL url = XhtmlCssEngine.class.getResource("default.css"); // TODO: reuse UserAgentStylesheet
0586:
0587:                    //URL url = null;
0588:                    //
0589:                    //try {
0590:                    //    //url = new URL("file:" + System.getProperty("netbeans.home") + "/ua.css"); // NOI18N
0591:                    //    url = new URL("file:/tmp/default.css"); // NOI18N
0592:                    //} catch (java.net.MalformedURLException mue) {
0593:                    //    mue.printStackTrace();
0594:                    //}
0595:                    if (url != null) {
0596:                        InputSource is = new InputSource(url.toString());
0597:                        defaultRules = engine.parseStyleSheet(is, url, "all",
0598:                                url);
0599:                        defaultRules.setupFilters();
0600:                    }
0601:                }
0602:
0603:                return defaultRules;
0604:            }
0605:
0606:            // XXX Not used.
0607:            //    /** Reinitialize the engine by re-reading the document stylesheets
0608:            //     * @todo Attach to my DocumentFragment instead!
0609:            //     */
0610:            //    public void setDocument(/*RaveDocument*/Document doc) {
0611:            //        DesignerContext ctx = (DesignerContext)getCSSContext();
0612:            //
0613:            //        if (document != null) {
0614:            //            refreshStyles(document);
0615:            //        }
0616:            //
0617:            //        ctx.setDocument(doc);
0618:            //        this.document = doc;
0619:            //// <moving RaveDoc refs outside> engine is not interested in registering itself somewhere.
0620:            ////        doc.setCssEngine(this);
0621:            //// </moving RaveDoc refs outside>
0622:            //    }
0623:
0624:            //    private void handleError(String message, Object location, int lineno, int column, Exception e) {
0625:            //        if (errorHandler != null) {
0626:            //            String filename = null;
0627:            //            int line = lineno;
0628:            //
0629:            //            if (location != null) {
0630:            //                final String fullname = computeFilename(location);
0631:            //                filename = fullname.substring(fullname.lastIndexOf('/') + 1);
0632:            //                line = computeLineNumber(location, lineno);
0633:            //
0634:            //                if (filename != null) {
0635:            //                    message = filename + ":" + line + /* ":" + column + */
0636:            //                        ": " + message;
0637:            //                }
0638:            //            }
0639:            //
0640:            //            CSSParseException cpe = new CSSParseException(message, filename, line, column, e);
0641:            //            errorHandler.error(cpe);
0642:            //        }
0643:            //    }
0644:            private static CSSParseException createCSSParseException(
0645:                    String message, Object location, int lineno, int column,
0646:                    Exception e) {
0647:                String filename = null;
0648:                int line = lineno;
0649:
0650:                if (location != null) {
0651:                    //            final String fullname = computeFilename(location);
0652:                    //            filename = fullname.substring(fullname.lastIndexOf('/') + 1);
0653:                    //            line = computeLineNumber(location, lineno);
0654:                    //
0655:                    //            if (filename != null) {
0656:                    //                message = filename + ":" + line + /* ":" + column + */
0657:                    //                    ": " + message;
0658:                    //            }
0659:                    message = location + ":" + lineno + ": " + message; // NOI18N
0660:                }
0661:
0662:                return new CSSParseException(message, filename, line, column, e);
0663:            }
0664:
0665:            protected void warnCircularReference(URL uri, Object location) {
0666:                String message = NbBundle.getMessage(XhtmlCssEngine.class,
0667:                        "MSG_CircularReference", uri); // NOI18N
0668:
0669:                if (errorHandler != null) {
0670:                    //            handleError(message, location, -1, -1, null);
0671:                    errorHandler.error(createCSSParseException(message,
0672:                            location, -1, -1, null));
0673:                } else {
0674:                    //            OutputListener listener = getListener(location, -1, -1);
0675:                    //            MarkupService.displayError(message, listener);
0676:                    if (location instanceof  AbstractValue) {
0677:                        location = ((AbstractValue) location).getLocation();
0678:                    }
0679:                    //            InSyncService.getProvider().getRaveErrorHandler().displayErrorForLocation(message, location, -1, -1);
0680:                    UserAgent userAgent = getUserAgent();
0681:                    if (userAgent == null) {
0682:                        // XXX What to do now, log it?
0683:                    } else {
0684:                        userAgent.displayErrorForLocation(message, location,
0685:                                -1, -1);
0686:                    }
0687:                }
0688:            }
0689:
0690:            /**
0691:             * Scan attributes for an element and transcribe deprecated
0692:             * style-type attributes into real style properties
0693:             */
0694:            protected void applyNonCSSPresentationalHints(CSSStylableElement e,
0695:                    StyleMap map) {
0696:                String tname = e.getTagName(); // should already be lowercase
0697:                assert (tname != null) && (tname.length() > 0);
0698:
0699:                if (tname.indexOf(':') != -1) {
0700:                    // Attributes on JSF elements etc. should not alias.
0701:                    // For example, the Braveheart button component has a "text"
0702:                    // attribute which has nothing to do with the text attribute
0703:                    // in html which affects screen color.
0704:                    return;
0705:                }
0706:
0707:                org.w3c.dom.NamedNodeMap atts = e.getAttributes();
0708:
0709:                if (atts == null) {
0710:                    return;
0711:                }
0712:
0713:                int ac = atts.getLength();
0714:
0715:                for (int i = 0; i < ac; i++) {
0716:                    Attr att = (Attr) atts.item(i);
0717:                    String aname = att.getName().toLowerCase().intern();
0718:                    int attribute = attributes.get(aname);
0719:
0720:                    if (attribute == -1) {
0721:                        continue;
0722:                    }
0723:
0724:                    String aval = att.getValue();
0725:
0726:                    if ((aval == null) || (aval.length() == 0)) {
0727:                        // Avoid attributes like this:
0728:                        //  <body color="">
0729:                        // Here we'll try to CSS parse "", and we get a parse
0730:                        // error for this:
0731:                        // 'The attribute "?" represents an invalid CSS value ("").'
0732:                        continue;
0733:                    }
0734:
0735:                    int pname = -1;
0736:                    String pval = aval;
0737:
0738:                    switch (attribute) {
0739:                    // Todo: ALINK/VLINK attributes -> e.g. LINK=blue becomes
0740:                    //    a[href] {color: blue;}
0741:                    case HtmlAttribute.ALIGN_ID:
0742:
0743:                        // <table>: align = left|center|right [CI]
0744:                        // <object>/<image>: align = bottom|middle|top|left|right
0745:                        // <td>: align = left|center|right|justify|char [CI]
0746:                        if (tname.equals(HtmlTag.IMG.name)
0747:                                || // XXX just switch to block tag check instead?
0748:                                tname.equals(HtmlTag.DIV.name)
0749:                                || tname.equals(HtmlTag.FORM.name)
0750:                                || tname.equals(HtmlTag.IFRAME.name)
0751:                                || tname.equals(HtmlTag.TABLE.name)
0752:                                || tname.equals(HtmlTag.APPLET.name)
0753:                                || tname.equals(HtmlTag.OBJECT.name)) {
0754:                            if (aval.equals("left") || aval.equals("right")) { //!CQ need to tokenize aval?
0755:                                pname = XhtmlCss.FLOAT_INDEX;
0756:                            } else if (aval.equals("center")) { // NOI18N
0757:                                applyNonCSSPresentationalHint(e, map,
0758:                                        XhtmlCss.TEXT_ALIGN_INDEX,
0759:                                        CssConstants.CSS_RAVECENTER_VALUE);
0760:                            } else {
0761:                                // top/texttop,middle,bottom/baseline,absbottom
0762:                                pname = XhtmlCss.VERTICAL_ALIGN_INDEX;
0763:
0764:                                if (aval.equals("texttop")) { // NOI18N
0765:                                    pval = CssConstants.CSS_TEXT_TOP_VALUE;
0766:                                } else if (aval.equals("absmiddle")) { // NOI18N
0767:
0768:                                    // This is NOT right but from a quick google
0769:                                    // there's no direct equivalent value for
0770:                                    // vertical align to emulate the absmiddle behavior
0771:                                    pval = CssConstants.CSS_MIDDLE_VALUE;
0772:                                } else if (aval.equals("absbottom")) { // NOI18N
0773:                                    pval = CssConstants.CSS_BOTTOM_VALUE;
0774:                                }
0775:                            }
0776:                        } else {
0777:                            pname = XhtmlCss.TEXT_ALIGN_INDEX; // P, TD, TH, THEAD, TFOOT, TBODY
0778:                        }
0779:
0780:                        break;
0781:
0782:                    case HtmlAttribute.LINK_ID:
0783:
0784:                        if (tname.equals(HtmlTag.BODY.name)) {
0785:                            pname = XhtmlCss.RAVELINKCOLOR_INDEX;
0786:                        }
0787:
0788:                        break;
0789:
0790:                    case HtmlAttribute.VALIGN_ID: // TD, TH, THEAD, TFOOT, TBODY
0791:
0792:                        // valign = top|middle|bottom|baseline [CI]
0793:                        pname = XhtmlCss.VERTICAL_ALIGN_INDEX;
0794:
0795:                        break;
0796:
0797:                    case HtmlAttribute.CLEAR_ID: // BR, possibly others
0798:
0799:                        // clear =  none|left|right|all [CI]
0800:                        if (aval.equals("all")) { // NOI18N
0801:                            pval = "both"; // NOI18N
0802:                        } // none, left, right are the same for both
0803:
0804:                        pname = XhtmlCss.CLEAR_INDEX;
0805:
0806:                        break;
0807:
0808:                    case HtmlAttribute.BGCOLOR_ID: // BODY, TABLE
0809:                        pname = XhtmlCss.BACKGROUND_COLOR_INDEX;
0810:
0811:                        break;
0812:
0813:                    case HtmlAttribute.BACKGROUND_ID: // BODY
0814:                        pname = XhtmlCss.BACKGROUND_IMAGE_INDEX;
0815:
0816:                        // XXX #6457821 Encode the url string, to fix cases when there are spaces.
0817:                        if (!isEncodedUrl(aval)) {
0818:                            aval = encodeUrl(aval);
0819:                        }
0820:
0821:                        //plu = new LexicalUnitImpl.createURI(null, aval);
0822:                        pval = "url(" + aval + ")";
0823:
0824:                        break;
0825:
0826:                    case HtmlAttribute.TEXT_ID: // BODY
0827:                        pname = XhtmlCss.COLOR_INDEX;
0828:
0829:                        break;
0830:
0831:                    case HtmlAttribute.WIDTH_ID: //!CQ PRE, TH, TD, IMG only?
0832:                        pname = XhtmlCss.WIDTH_INDEX;
0833:
0834:                        if (pval.indexOf('%') > 0) { // XXXX should this be aval????
0835:                            pval = aval;
0836:                        } else if (hasNoUnits(pval)) {
0837:                            pval = aval + "px";
0838:                        }
0839:
0840:                        break;
0841:
0842:                    case HtmlAttribute.HEIGHT_ID: //!CQ PRE, TH, TD, IMG only?
0843:                        pname = XhtmlCss.HEIGHT_INDEX;
0844:
0845:                        if (pval.indexOf('%') > 0) { // XXXX should this be aval????
0846:                            pval = aval;
0847:                        } else if (hasNoUnits(pval)) {
0848:                            pval = aval + "px";
0849:                        }
0850:
0851:                        break;
0852:
0853:                    case HtmlAttribute.NOWRAP_ID:
0854:
0855:                        // MSDN docs on dhtml lists the nowrap attribute as applicable
0856:                        // to body, dd, div, dt, td, th.  However, Mozilla doesn't
0857:                        // seem to recognize it on div.
0858:                        if (tname.equals(HtmlTag.BODY.name)
0859:                                || tname.equals(HtmlTag.TD.name)
0860:                                || tname.equals(HtmlTag.TH.name)
0861:                                || tname.equals(HtmlTag.DD.name)
0862:                                || tname.equals(HtmlTag.DT.name)
0863:                                || tname.equals(HtmlTag.DIV.name)) {
0864:                            pname = XhtmlCss.WHITE_SPACE_INDEX;
0865:                            pval = CssConstants.CSS_NOWRAP_VALUE;
0866:                        }
0867:
0868:                        break;
0869:
0870:                    case HtmlAttribute.BORDER_ID:
0871:
0872:                        if (hasNoUnits(pval)) { // XXXX should this be aval????
0873:                            pval = aval + "px";
0874:                        }
0875:
0876:                        // Property translates to multiple properties,
0877:                        // so set them directly and continue
0878:                        applyNonCSSPresentationalHint(e, map,
0879:                                XhtmlCss.BORDER_TOP_WIDTH_INDEX, pval);
0880:                        applyNonCSSPresentationalHint(e, map,
0881:                                XhtmlCss.BORDER_LEFT_WIDTH_INDEX, pval);
0882:                        applyNonCSSPresentationalHint(e, map,
0883:                                XhtmlCss.BORDER_RIGHT_WIDTH_INDEX, pval);
0884:                        applyNonCSSPresentationalHint(e, map,
0885:                                XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX, pval);
0886:
0887:                        continue; // NOTE - continue, not break
0888:
0889:                    case HtmlAttribute.COLOR_ID: // generally applicable
0890:                        pname = XhtmlCss.COLOR_INDEX;
0891:
0892:                        break;
0893:
0894:                    case HtmlAttribute.SIZE_ID:
0895:
0896:                        if (tname.equals(HtmlTag.FONT.name)
0897:                                || tname.equals(HtmlTag.BASEFONT.name)) {
0898:                            pname = XhtmlCss.FONT_SIZE_INDEX;
0899:                            pval = CssConstants.CSS_MEDIUM_VALUE;
0900:
0901:                            if (aval.length() > 0) {
0902:                                if (aval.charAt(0) == '+') {
0903:                                    // XXX We could try to read the actual relative
0904:                                    // value here, and adjust - but the <font> tag
0905:                                    // is already deprecated and discouraged. If it
0906:                                    // was easy I'd do it but with CSS there isn't
0907:                                    // a way to mage the font size bigger/smaller
0908:                                    // by more than a factor of 1 so let's just
0909:                                    // leave it at this: <font size="+n"> is
0910:                                    // will be equivalent to <font size="+1">
0911:                                    pval = CssConstants.CSS_LARGER_VALUE;
0912:                                } else if (aval.charAt(0) == '-') {
0913:                                    // Same comment as under '+' handling above
0914:                                    pval = CssConstants.CSS_SMALLER_VALUE;
0915:                                } else {
0916:                                    // Map to absolute font size
0917:                                    try {
0918:                                        int n = Integer.parseInt(aval);
0919:
0920:                                        switch (n) {
0921:                                        case 1:
0922:                                            pval = CssConstants.CSS_XX_SMALL_VALUE;
0923:
0924:                                            break;
0925:
0926:                                        case 2:
0927:                                            pval = CssConstants.CSS_X_SMALL_VALUE;
0928:
0929:                                            break;
0930:
0931:                                        case 3:
0932:                                            pval = CssConstants.CSS_SMALL_VALUE;
0933:
0934:                                            break;
0935:
0936:                                        case 4:
0937:                                            pval = CssConstants.CSS_MEDIUM_VALUE;
0938:
0939:                                            break;
0940:
0941:                                        case 5:
0942:                                            pval = CssConstants.CSS_LARGE_VALUE;
0943:
0944:                                            break;
0945:
0946:                                        case 6:
0947:                                            pval = CssConstants.CSS_X_LARGE_VALUE;
0948:
0949:                                            break;
0950:
0951:                                        case 7:
0952:                                            pval = CssConstants.CSS_XX_LARGE_VALUE;
0953:
0954:                                            break;
0955:                                        }
0956:                                    } catch (NumberFormatException ex) {
0957:                                        // The attribute is set to a bogus value.
0958:                                        // In this case we should simply use the
0959:                                        // default of "medium".
0960:                                        // pval was set to "medium" already.
0961:                                    }
0962:                                }
0963:                            }
0964:                        } else if (tname.equals(HtmlTag.HR.name)) { //!CQ HR only?
0965:                            pname = XhtmlCss.HEIGHT_INDEX;
0966:
0967:                            if (pval.indexOf('%') > 0) {
0968:                                pval = aval;
0969:                            } else if (hasNoUnits(pval)) {
0970:                                pval = aval + "px";
0971:                            }
0972:                        }
0973:
0974:                        break;
0975:
0976:                    case HtmlAttribute.FACE_ID: // FONT
0977:                        pname = XhtmlCss.FONT_FAMILY_INDEX;
0978:
0979:                        break;
0980:
0981:                    case HtmlAttribute.TYPE_ID:
0982:
0983:                        if (tname.equals(HtmlTag.UL.name)
0984:                                || tname.equals(HtmlTag.OL.name)
0985:                                || tname.equals(HtmlTag.DL.name)
0986:                                || tname.equals(HtmlTag.LI.name)) {
0987:                            pname = XhtmlCss.LIST_STYLE_TYPE_INDEX;
0988:                        }
0989:
0990:                        break;
0991:
0992:                    //hspace, vspace => margin-[left+right], margin-[top+bottom] ?
0993:                    // What about this:
0994:                    //   <basefont> => "font"
0995:                    }
0996:
0997:                    // set the style property iff it was found
0998:                    if (pname != -1) {
0999:                        applyNonCSSPresentationalHint(e, map, pname, pval);
1000:                    }
1001:                }
1002:            }
1003:
1004:            /**
1005:             * Return true if the string parameter contains a number without any units at the end. For this
1006:             * purpose a unit will be considered any alphabetical characters or non space character.
1007:             */
1008:            public static boolean hasNoUnits(String s) {
1009:                for (int i = 0, n = s.length(); i < n; i++) {
1010:                    char c = s.charAt(i);
1011:
1012:                    if (!Character.isDigit(c) && !Character.isWhitespace(c)) {
1013:                        return false;
1014:                    }
1015:                }
1016:
1017:                return true;
1018:            }
1019:
1020:            // XXX Ugly method to test whether the url string is encoded already.
1021:            // FIXME How these things should be done correctly?
1022:            private static boolean isEncodedUrl(String url) {
1023:                if (url == null || url.length() == 0) {
1024:                    return false;
1025:                }
1026:                // XXX Checking for the same like used in encodeUrl.
1027:                if (url.indexOf("%09") != -1 // NOI18N
1028:                        || url.indexOf("%20") != -1 // NOI18N
1029:                        || url.indexOf("%23") != -1 // NOI18N
1030:                        || url.indexOf("%25") != -1 // NOI18N
1031:                        || url.indexOf("%3C") != -1 // NOI18N
1032:                        || url.indexOf("%3E") != -1 // NOI18N
1033:                        || url.indexOf("%5B") != -1 // NOI18N
1034:                        || url.indexOf("%5D") != -1 // NOI18N
1035:                        || url.indexOf("%7B") != -1 // NOI18N
1036:                        || url.indexOf("%7D") != -1 // NOI18N
1037:                        || url.indexOf("%7E") != -1) { // NOI18N
1038:                    return true;
1039:                }
1040:                return false;
1041:            }
1042:
1043:            // XXX Copied from propertyeditors/UrlPropertyEditor.
1044:            // There should be common utility method.
1045:            /**
1046:             * Convert a file system path to a URL by converting unsafe characters into
1047:             * numeric character entity references. The unsafe characters are listed in
1048:             * in the IETF specification of URLs
1049:             * (<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>). Safe URL
1050:             * characters are all printable ASCII characters, with the exception of the
1051:             * space characters, '#', <', '>', '%', '[', ']', '{', '}', and '~'. This
1052:             * method differs from {@link java.net.URLEncoder#encode(String)}, in that
1053:             * it is intended for encoding the path portion of a URL, not the query
1054:             * string.
1055:             */
1056:            private static String encodeUrl(String url) {
1057:                if (url == null || url.length() == 0)
1058:                    return url;
1059:                StringBuffer buffer = new StringBuffer();
1060:                String anchor = null;
1061:                int index = url.lastIndexOf('#');
1062:                if (index >= 0) {
1063:                    anchor = url.substring(index + 1);
1064:                    url = url.substring(0, index);
1065:                }
1066:                char[] chars = url.toCharArray();
1067:                for (int i = 0; i < chars.length; i++) {
1068:                    if (chars[i] <= '\u0020') {
1069:                        buffer.append('%');
1070:                        buffer.append(Integer.toHexString((int) chars[i]));
1071:                    } else {
1072:                        switch (chars[i]) {
1073:                        case '\u0009': // Tab
1074:                            buffer.append("%09");
1075:                            break;
1076:                        case '\u0020': // Space
1077:                            buffer.append("%20");
1078:                            break;
1079:                        case '#':
1080:                            buffer.append("%23");
1081:                            break;
1082:                        case '%':
1083:                            buffer.append("%25");
1084:                            break;
1085:                        case '<':
1086:                            buffer.append("%3C");
1087:                            break;
1088:                        case '>':
1089:                            buffer.append("%3E");
1090:                            break;
1091:                        case '[':
1092:                            buffer.append("%5B");
1093:                            break;
1094:                        case ']':
1095:                            buffer.append("%5D");
1096:                            break;
1097:                        case '{':
1098:                            buffer.append("%7B");
1099:                            break;
1100:                        case '}':
1101:                            buffer.append("%7D");
1102:                            break;
1103:                        case '~':
1104:                            buffer.append("%7E");
1105:                            break;
1106:                        default:
1107:                            buffer.append(chars[i]);
1108:                        }
1109:                    }
1110:                }
1111:                if (anchor != null) {
1112:                    buffer.append('#');
1113:                    buffer.append(anchor);
1114:                }
1115:                if (buffer.length() == url.length())
1116:                    return url;
1117:                return buffer.toString();
1118:            }
1119:
1120:            /** Refresh all styles
1121:             * @todo Rename to disposeStyles to reflect what this method
1122:             *   actually does.
1123:             */
1124:            public void refreshStyles() {
1125:                if (styleSheetNodes != null) {
1126:                    // Since elements hang on to their stylesheets, and on a pure
1127:                    // refresh we don't recreate the elements, we've gotta clear them
1128:                    // out
1129:                    Iterator it = styleSheetNodes.iterator();
1130:
1131:                    while (it.hasNext()) {
1132:                        Object o = it.next();
1133:
1134:                        //                if (o instanceof StyleElement) {
1135:                        //                    ((StyleElement)o).refresh();
1136:                        //                } else if (o instanceof StylesheetLinkElement) {
1137:                        //                    ((StylesheetLinkElement)o).refresh();
1138:                        //                }
1139:                        if (o instanceof  StyleRefreshable) {
1140:                            ((StyleRefreshable) o).refresh();
1141:                        }
1142:                    }
1143:
1144:                    styleSheetNodes = null;
1145:                }
1146:
1147:                disposeStyleMaps(document.getDocumentElement());
1148:
1149:                // XXX Is this still needed?
1150:                if (document.getDocumentElement() != document) {
1151:                    disposeStyleMaps(document);
1152:                }
1153:            }
1154:
1155:            // Moved to API.
1156:            //    /** XXX To be implemented by style elements in order the engine calls refresh on them.
1157:            //     * TODO the refreshing smells badly, revise entire func. */
1158:            //    public interface StyleRefreshable {
1159:            //        public void refresh();
1160:            //    } // Enf of StyleRefreshable.
1161:
1162:            /** Remove precomputed styles for the given element - compute them
1163:             * over again.
1164:             * @todo Do I have to clear computed styles on all the children too?
1165:             */
1166:            public void clearComputedStyles(Element element/*, String pseudo*/) {
1167:                disposeStyleMaps(element);
1168:            }
1169:
1170:            // <removing design bean manipulation in engine>
1171:            //    protected void setAttributeValue(Element elt, String name, String value) {
1172:            //        RaveElement xel = (RaveElement)elt;
1173:            //
1174:            //        if (xel.getDesignBean() != null) {
1175:            //            DesignProperty property = xel.getDesignBean().getProperty("style"); // NOI18N
1176:            //
1177:            //            if (property != null) {
1178:            //                try {
1179:            //                    if ((value != null) && (value.length() > 0)) {
1180:            //                        property.setValue(value);
1181:            //                    } else {
1182:            //                        property.unset();
1183:            //                    }
1184:            //
1185:            //                    return;
1186:            //                } catch (Exception ex) {
1187:            //                    ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
1188:            //                    // For some reason the above throws exceptions
1189:            //                    // sometimes, not sure why org.w3c.dom.DOMException:
1190:            //                    // NOT_FOUND_ERR: An attempt is made to reference a
1191:            //                    // node in a context where it does not exist.  TODO
1192:            //                    // - figure out WHY!  For now just swallow since
1193:            //                    // there's nothing more we can do about it.
1194:            //                    // (Update: It think this may be fixed now)
1195:            //                }
1196:            //            }
1197:            //        }
1198:            //
1199:            //        // If the above fails (shouldn't)
1200:            //        super.setAttributeValue(elt, name, value);
1201:            //    }
1202:            // ====
1203:            /** XXX Only a fallback for the original suspicious pattern. */
1204:            public void setStyleAttributeValue(Element elt, String value) {
1205:                setAttributeValue(elt, HtmlAttribute.STYLE, value);
1206:            }
1207:
1208:            // </removing design bean manipulation in engine>
1209:
1210:            /**
1211:             * Set the error handler to be used in the case of parse errors.
1212:             * If not set, the default handler will be used, which emits warnings
1213:             * in the output window.
1214:             */
1215:            public void setErrorHandler(ErrorHandler handler) {
1216:                this .errorHandler = handler;
1217:            }
1218:
1219:            //    protected OutputListener getListener(Object location, int lineno, final int column) {
1220:            //        OutputListener listener = null; // TODO - provide clickable errors
1221:            //
1222:            //        if (location != null) {
1223:            //            final String fullname = computeFilename(location);
1224:            //            String filename = fullname.substring(fullname.lastIndexOf('/') + 1);
1225:            //            final int line = computeLineNumber(location, lineno);
1226:            //
1227:            //            if (filename != null) {
1228:            //                listener =
1229:            //                    new OutputListener() {
1230:            //                            public void outputLineSelected(OutputEvent ev) {
1231:            //                            }
1232:            //
1233:            //                            public void outputLineAction(OutputEvent ev) {
1234:            //                                // <markup_separation>
1235:            ////                                Util.show(fullname, null, (line >= 1) ? line : 1, column, true);
1236:            //                                // ====
1237:            //                                MarkupService.show(fullname, (line >= 1) ? line : 1, column, true);
1238:            //                                // </markup_separation>
1239:            //                            }
1240:            //
1241:            //                            public void outputLineCleared(OutputEvent ev) {
1242:            //                            }
1243:            //                        };
1244:            //            }
1245:            //        }
1246:            //
1247:            //        return listener;
1248:            //    }
1249:
1250:            protected void displayError(DOMException e, Object location,
1251:                    int lineno, final int column) {
1252:                String message = e.getLocalizedMessage();
1253:
1254:                if ((message == null) || (message.length() == 0)) {
1255:                    return;
1256:                }
1257:
1258:                if (errorHandler != null) {
1259:                    //            handleError(message, location, lineno, column, null);
1260:                    errorHandler.error(createCSSParseException(message,
1261:                            location, lineno, column, null));
1262:                } else {
1263:                    //            OutputListener listener = getListener(location, lineno, column);
1264:                    //            MarkupService.displayError(message, listener);
1265:                    //            String fileName = computeFilename(location);
1266:                    //            int line = computeLineNumber(location, lineno);
1267:                    if (location instanceof  AbstractValue) {
1268:                        location = ((AbstractValue) location).getLocation();
1269:                    }
1270:                    //            InSyncService.getProvider().getRaveErrorHandler().displayErrorForLocation(message, location, lineno, column);
1271:                    UserAgent userAgent = getUserAgent();
1272:                    if (userAgent == null) {
1273:                        // XXX Log it?
1274:                    } else {
1275:                        userAgent.displayErrorForLocation(message, location,
1276:                                lineno, column);
1277:                    }
1278:                }
1279:            }
1280:
1281:            protected void displayMissingStyleSheet(String uri) {
1282:                String message = NbBundle.getMessage(XhtmlCssEngine.class,
1283:                        "MissingStylesheet", // NOI18N
1284:                        uri);
1285:
1286:                if (errorHandler != null) {
1287:                    //            handleError(message, null, -1, 0, null);
1288:                    errorHandler.error(createCSSParseException(message, null,
1289:                            -1, 0, null));
1290:                } else {
1291:                    //            OutputListener listener = null; // TODO - provide clickable errors
1292:                    //            MarkupService.displayError(message, listener);
1293:                    //            InSyncService.getProvider().getRaveErrorHandler().displayError(message);
1294:                    UserAgent userAgent = getUserAgent();
1295:                    if (userAgent == null) {
1296:                        // XXX Log it?
1297:                    } else {
1298:                        userAgent
1299:                                .displayErrorForLocation(message, null, -1, -1);
1300:                    }
1301:                }
1302:            }
1303:
1304:            /** Initialize all values for a given element (this is otherwise done
1305:             * lazily) on a getComputedStyle call for a particular property).
1306:             */
1307:            public void precomputeAllStyles(CSSStylableElement elt) {
1308:                for (int i = 0, n = XHTML_VALUE_MANAGERS.length; i < n; i++) {
1309:                    getComputedStyle(elt, null, i); // throwing away result
1310:                }
1311:            }
1312:
1313:            //    /**
1314:            //     * The filename where this CSS value is defined. This could be a
1315:            //     * CSS file but doesn't have to be -- it could point to a markup file
1316:            //     * with an inline style attribute.
1317:            //     */
1318:            //    public static String computeFilename(AbstractValue av) {
1319:            //        return computeFilename(av.getLocation());
1320:            //    }
1321:            //
1322:            //    /** Given a general location object provided from the CSS parser,
1323:            //     * compute the correct file name to use.
1324:            //     */
1325:            //    public static String computeFilename(Object location) {
1326:            //        if (location instanceof String) {
1327:            //            return (String)location;
1328:            //        } else if (location instanceof URL) {
1329:            //            // <markup_separation>
1330:            ////            return MarkupUnit.fromURL(((URL)location).toExternalForm());
1331:            //            // ====
1332:            //            return MarkupService.fromURL(((URL)location).toExternalForm());
1333:            //            // </markup_separation>
1334:            //        } else if (location instanceof Element) {
1335:            //            // Locate the filename for a given element
1336:            //            Element element = (Element)location;
1337:            //            element = MarkupService.getCorrespondingSourceElement(element);
1338:            //
1339:            //            // <markup_separation>
1340:            ////            // XXX I should derive this from the engine instead, after all
1341:            ////            // the engine can know the unit! (Since engines cannot be used
1342:            ////            // with multiple DOMs anyway)
1343:            ////            FileObject fo = unit.getFileObject();
1344:            //            // ====
1345:            //            FileObject fo = InSyncService.getProvider().getFileObject(element.getOwnerDocument());
1346:            //            // </markup_separation>
1347:            //            File f = FileUtil.toFile(fo);
1348:            //
1349:            //            return f.toString();
1350:            //        } else if (location != null) {
1351:            //            return location.toString();
1352:            //        }
1353:            //
1354:            //        return "";
1355:            //    }
1356:            //
1357:            //    /**
1358:            //     * The line number where this CSS value is defined, within the file
1359:            //     * returned by computeFilename. The first line is number 0.
1360:            //     */
1361:            //    public static int computeLineNumber(AbstractValue av) {
1362:            //        return computeLineNumber(av.getLocation(), av.getLineNumber());
1363:            //    }
1364:            //
1365:            //    public static int computeLineNumber(Object location, int lineno) {
1366:            //        if (location instanceof Element) {
1367:            //            /*
1368:            //            // The location is an XhtmlElement -- so the line number
1369:            //            // needs to be relative to it.... compute the line number
1370:            //            // of the element
1371:            //            if (lineno == -1)
1372:            //                lineno = 0;
1373:            //            Element element = (Element)location;
1374:            //            RaveDocument doc = (RaveDocument)element.getOwnerDocument();
1375:            //            lineno += doc.getLineNumber(element);
1376:            //             */
1377:            //            if (lineno == -1) {
1378:            //                lineno = 0;
1379:            //            }
1380:            //
1381:            //            Element element = (Element)location;
1382:            //            element = MarkupService.getCorrespondingSourceElement(element);
1383:            //            // <markup_separation>
1384:            ////            lineno += unit.computeLine(element);
1385:            //            // ====
1386:            //            lineno += InSyncService.getProvider().computeLine(element.getOwnerDocument(), element);
1387:            //            // </markup_separation>
1388:            //        }
1389:            //
1390:            //        return lineno;
1391:            //    }
1392:
1393:            /** Get the Link Color to use in this document */
1394:            Value getLinkColor() {
1395:                //        Element body = DesignerService.getDefault().getBody(document);
1396:                //        Element body = InSyncService.getProvider().getHtmlBodyForMarkupFile(InSyncService.getProvider().getFileObject(document));
1397:
1398:                UserAgent userAgent = getUserAgent();
1399:                Element body = userAgent == null ? null : userAgent
1400:                        .getHtmlBodyForDocument(document);
1401:                if (body == null) {
1402:                    // XXX Is it OK?
1403:                    return new RGBColorValue(new FloatValue(
1404:                            CSSPrimitiveValue.CSS_NUMBER, 0), new FloatValue(
1405:                            CSSPrimitiveValue.CSS_NUMBER, 0), new FloatValue(
1406:                            CSSPrimitiveValue.CSS_NUMBER, 200));
1407:                }
1408:
1409:                return getComputedStyle((CSSStylableElement) body, null,
1410:                        XhtmlCss.RAVELINKCOLOR_INDEX);
1411:            }
1412:
1413:            /** For use by page import */
1414:            public boolean mediaMatch(SACMediaList ml) {
1415:                return super .mediaMatch(ml);
1416:            }
1417:
1418:            /**
1419:             * Given a Map of style properties, serialize the set and compress
1420:             * properties into shorthands, when possible. See styleToMap.
1421:             */
1422:            public String mapToStyle(Map<String, String> map) {
1423:                StyleMap styleMap = new StyleMap(getNumberOfProperties());
1424:                StringBuffer unknown = null;
1425:                Iterator<String> it = map.keySet().iterator();
1426:
1427:                while (it.hasNext()) {
1428:                    String key = it.next();
1429:                    String value = map.get(key);
1430:
1431:                    int index = getXhtmlPropertyIndex(key);
1432:
1433:                    if (index == -1) {
1434:                        // Unknown property.... what to do, what to do... remember it
1435:                        // so we can attach it to the end
1436:                        if (unknown == null) {
1437:                            unknown = new StringBuffer(60);
1438:                        }
1439:
1440:                        unknown.append(key);
1441:                        unknown.append(':');
1442:                        unknown.append(' ');
1443:                        unknown.append(value);
1444:                        unknown.append(';');
1445:                    } else {
1446:                        styleMap.putValue(index, new MapStringValue(value));
1447:                    }
1448:                }
1449:
1450:                String style = toMinimalStyleString(styleMap);
1451:
1452:                if (unknown != null) {
1453:                    if (style.length() > 0) {
1454:                        style = style + "; " + unknown;
1455:                    } else {
1456:                        style = unknown.toString();
1457:                    }
1458:                }
1459:
1460:                return style;
1461:            }
1462:
1463:            /** Parse the given style declaration and return a map of properties
1464:             * stored in it. The Map will have String keys which correspond to
1465:             * property names, and String values which correspond to CSS
1466:             * raw text for the values.
1467:             */
1468:            public Map<String, String> styleToMap(String style) {
1469:                CSSStylableElement old = element;
1470:                StyleDeclaration sd = null;
1471:                int size = 0;
1472:
1473:                try {
1474:                    // There needs to be a current element for resolving
1475:                    // urls, for example for a background-image property.
1476:                    // The URL won't be right, but that's okay for now since
1477:                    // we won't try to access it.
1478:                    element = (CSSStylableElement) document
1479:                            .getDocumentElement();
1480:                    unknownPropertyNames = new ArrayList<String>();
1481:                    unknownPropertyValues = new ArrayList<String>();
1482:                    sd = parseStyleDeclaration(element, style);
1483:                    size = sd.size();
1484:
1485:                    if (size == 0) {
1486:                        return new HashMap<String, String>(0);
1487:                    }
1488:
1489:                    // XXX Pick a better data structure that preserves order?
1490:                    // Yeah, we don't really need to Hash aspect here; we're mostly
1491:                    // iterating!
1492:                    //            LinkedHashMap map = new LinkedHashMap(2 * size);
1493:                    Map<String, String> map = new LinkedHashMap<String, String>(
1494:                            2 * size);
1495:
1496:                    for (int j = 0, m = size; j < m; j++) {
1497:                        int idx = sd.getIndex(j);
1498:                        String key = getPropertyName(idx);
1499:                        Value value = sd.getValue(j);
1500:
1501:                        if (value != null) {
1502:                            map.put(key, value.getCssText());
1503:                        }
1504:                    }
1505:
1506:                    // Add unknown properties
1507:                    for (int i = 0, n = unknownPropertyNames.size(); i < n; i++) {
1508:                        map.put((String) unknownPropertyNames.get(i),
1509:                                (String) unknownPropertyValues.get(i));
1510:                    }
1511:
1512:                    return map;
1513:                } finally {
1514:                    unknownPropertyNames = null;
1515:                    unknownPropertyValues = null;
1516:                    element = old;
1517:                }
1518:            }
1519:
1520:            /**
1521:             * Returns the property index, or -1.
1522:             */
1523:            public static int getXhtmlPropertyIndex(String name) {
1524:                return valueManagerIndex.get(name);
1525:            }
1526:
1527:            /**
1528:             * Returns the shorthand property index, or -1.
1529:             */
1530:            public static int getXhtmlShorthandIndex(String name) {
1531:                return shorthandManagerIndex.get(name);
1532:            }
1533:
1534:            protected void findStyleSheetNodes() {
1535:                // <removing set/getRoot from RaveDocument>
1536:                //        Node root = ((RaveDocument)document).getRoot();
1537:                //        findStyleSheetNodes(root);
1538:                // ====
1539:                // XXX FIXME Here we need to work with the rendered HTML DOM directly,
1540:                // there is no interest in the original JSP DOM.
1541:                //        FileObject markupFile = InSyncService.getProvider().getFileObject(document);
1542:                //        if (markupFile != null) {
1543:                //            DocumentFragment df = InSyncService.getProvider().getHtmlDomFragmentForMarkupFile(markupFile);
1544:                //        DocumentFragment df = InSyncService.getProvider().getHtmlDomFragmentForDocument(document);
1545:                UserAgent userAgent = getUserAgent();
1546:                DocumentFragment df = userAgent == null ? null : userAgent
1547:                        .getHtmlDomFragmentForDocument(document);
1548:                if (df != null) {
1549:                    findStyleSheetNodes(df);
1550:                    return;
1551:                }
1552:                //        }
1553:
1554:                // XXX Log problem?
1555:                super .findStyleSheetNodes();
1556:                // <removing set/getRoot from RaveDocument>
1557:            }
1558:
1559:            // Moved to service impl.
1560:            //    /**
1561:            //     * Return true iff the given CSS property for the given element
1562:            //     * is set by an inline property setting
1563:            //     */
1564:            //    public static boolean isInlineValue(CSSStylableElement elt, int propidx) {
1565:            //        String pseudo = ""; // Pending
1566:            //        StyleMap sm = elt.getComputedStyleMap(pseudo);
1567:            //
1568:            //        if (sm == null) {
1569:            //            return false;
1570:            //        }
1571:            //
1572:            //        Value value = sm.getValue(propidx);
1573:            //
1574:            //        if (value == null) {
1575:            //            return false;
1576:            //        }
1577:            //
1578:            //        return sm.getOrigin(propidx) == StyleMap.INLINE_AUTHOR_ORIGIN;
1579:            //    }
1580:
1581:            /**
1582:             * Try to create a minimal (as short as possible) style string
1583:             * from this map, by using shorthands when possible.
1584:             * This will for example compress border-color-left/right/bottom/top
1585:             * into border-color: one two three four, and so on.
1586:             * @todo Handle the font shorthand property.
1587:             */
1588:            protected String toMinimalStyleString(StyleMap map) {
1589:                int size = map.getSize(true);
1590:                boolean[] used = new boolean[size];
1591:                StringBuffer sb = new StringBuffer();
1592:
1593:                // TODO how does isImportant on an individual property get translated
1594:                // into a shorthand??? Try the reverse!
1595:                // First see if I can use border. That's true when
1596:                // all of
1597:                boolean allBorderWidths = (map
1598:                        .getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX) != null)
1599:                        && (map.getValue(XhtmlCss.BORDER_TOP_WIDTH_INDEX) != null)
1600:                        && (map.getValue(XhtmlCss.BORDER_RIGHT_WIDTH_INDEX) != null)
1601:                        && (map.getValue(XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX) != null);
1602:                boolean sameBorderWidth = allBorderWidths
1603:                        && map
1604:                                .getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX)
1605:                                .equals(
1606:                                        map
1607:                                                .getValue(XhtmlCss.BORDER_TOP_WIDTH_INDEX))
1608:                        && map
1609:                                .getValue(XhtmlCss.BORDER_TOP_WIDTH_INDEX)
1610:                                .equals(
1611:                                        map
1612:                                                .getValue(XhtmlCss.BORDER_RIGHT_WIDTH_INDEX))
1613:                        && map
1614:                                .getValue(XhtmlCss.BORDER_RIGHT_WIDTH_INDEX)
1615:                                .equals(
1616:                                        map
1617:                                                .getValue(XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX));
1618:                boolean allBorderColors = (map
1619:                        .getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX) != null)
1620:                        && (map.getValue(XhtmlCss.BORDER_TOP_COLOR_INDEX) != null)
1621:                        && (map.getValue(XhtmlCss.BORDER_RIGHT_COLOR_INDEX) != null)
1622:                        && (map.getValue(XhtmlCss.BORDER_BOTTOM_COLOR_INDEX) != null);
1623:                boolean sameBorderColor = allBorderColors
1624:                        && map
1625:                                .getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX)
1626:                                .equals(
1627:                                        map
1628:                                                .getValue(XhtmlCss.BORDER_TOP_COLOR_INDEX))
1629:                        && map
1630:                                .getValue(XhtmlCss.BORDER_TOP_COLOR_INDEX)
1631:                                .equals(
1632:                                        map
1633:                                                .getValue(XhtmlCss.BORDER_RIGHT_COLOR_INDEX))
1634:                        && map
1635:                                .getValue(XhtmlCss.BORDER_RIGHT_COLOR_INDEX)
1636:                                .equals(
1637:                                        map
1638:                                                .getValue(XhtmlCss.BORDER_BOTTOM_COLOR_INDEX));
1639:                boolean allBorderStyles = (map
1640:                        .getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX) != null)
1641:                        && (map.getValue(XhtmlCss.BORDER_TOP_STYLE_INDEX) != null)
1642:                        && (map.getValue(XhtmlCss.BORDER_RIGHT_STYLE_INDEX) != null)
1643:                        && (map.getValue(XhtmlCss.BORDER_BOTTOM_STYLE_INDEX) != null);
1644:                boolean sameBorderStyle = allBorderStyles
1645:                        && map
1646:                                .getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX)
1647:                                .equals(
1648:                                        map
1649:                                                .getValue(XhtmlCss.BORDER_TOP_STYLE_INDEX))
1650:                        && map
1651:                                .getValue(XhtmlCss.BORDER_TOP_STYLE_INDEX)
1652:                                .equals(
1653:                                        map
1654:                                                .getValue(XhtmlCss.BORDER_RIGHT_STYLE_INDEX))
1655:                        && map
1656:                                .getValue(XhtmlCss.BORDER_RIGHT_STYLE_INDEX)
1657:                                .equals(
1658:                                        map
1659:                                                .getValue(XhtmlCss.BORDER_BOTTOM_STYLE_INDEX));
1660:
1661:                if (sameBorderStyle && sameBorderWidth && sameBorderColor) {
1662:                    sb.append(CssConstants.CSS_BORDER_PROPERTY);
1663:                    sb.append(": "); // NOI18N
1664:                    sb.append(map.getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX));
1665:                    sb.append(" "); // NOI18N
1666:                    sb.append(map.getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX));
1667:                    sb.append(" "); // NOI18N
1668:                    sb.append(map.getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX));
1669:                    used[XhtmlCss.BORDER_LEFT_WIDTH_INDEX] = true;
1670:                    used[XhtmlCss.BORDER_TOP_WIDTH_INDEX] = true;
1671:                    used[XhtmlCss.BORDER_RIGHT_WIDTH_INDEX] = true;
1672:                    used[XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX] = true;
1673:                    used[XhtmlCss.BORDER_LEFT_COLOR_INDEX] = true;
1674:                    used[XhtmlCss.BORDER_TOP_COLOR_INDEX] = true;
1675:                    used[XhtmlCss.BORDER_RIGHT_COLOR_INDEX] = true;
1676:                    used[XhtmlCss.BORDER_BOTTOM_COLOR_INDEX] = true;
1677:                    used[XhtmlCss.BORDER_LEFT_STYLE_INDEX] = true;
1678:                    used[XhtmlCss.BORDER_TOP_STYLE_INDEX] = true;
1679:                    used[XhtmlCss.BORDER_RIGHT_STYLE_INDEX] = true;
1680:                    used[XhtmlCss.BORDER_BOTTOM_STYLE_INDEX] = true;
1681:                    sb.append("; ");
1682:                } else {
1683:                    if (allBorderWidths) {
1684:                        sb.append(CssConstants.CSS_BORDER_WIDTH_PROPERTY);
1685:                        sb.append(": "); // NOI18N
1686:
1687:                        if (sameBorderWidth) {
1688:                            sb
1689:                                    .append(map
1690:                                            .getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX));
1691:                        } else {
1692:                            sb.append(map
1693:                                    .getValue(XhtmlCss.BORDER_TOP_WIDTH_INDEX));
1694:                            sb.append(" "); // NOI18N
1695:                            sb
1696:                                    .append(map
1697:                                            .getValue(XhtmlCss.BORDER_RIGHT_WIDTH_INDEX));
1698:                            sb.append(" "); // NOI18N
1699:                            sb
1700:                                    .append(map
1701:                                            .getValue(XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX));
1702:                            sb.append(" "); // NOI18N
1703:                            sb
1704:                                    .append(map
1705:                                            .getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX));
1706:                        }
1707:
1708:                        used[XhtmlCss.BORDER_LEFT_WIDTH_INDEX] = true;
1709:                        used[XhtmlCss.BORDER_TOP_WIDTH_INDEX] = true;
1710:                        used[XhtmlCss.BORDER_RIGHT_WIDTH_INDEX] = true;
1711:                        used[XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX] = true;
1712:                        sb.append("; ");
1713:                    }
1714:
1715:                    if (allBorderStyles) {
1716:                        sb.append(CssConstants.CSS_BORDER_STYLE_PROPERTY);
1717:                        sb.append(": "); // NOI18N
1718:
1719:                        if (sameBorderStyle) {
1720:                            sb
1721:                                    .append(map
1722:                                            .getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX));
1723:                        } else {
1724:                            sb.append(map
1725:                                    .getValue(XhtmlCss.BORDER_TOP_STYLE_INDEX));
1726:                            sb.append(" "); // NOI18N
1727:                            sb
1728:                                    .append(map
1729:                                            .getValue(XhtmlCss.BORDER_RIGHT_STYLE_INDEX));
1730:                            sb.append(" "); // NOI18N
1731:                            sb
1732:                                    .append(map
1733:                                            .getValue(XhtmlCss.BORDER_BOTTOM_STYLE_INDEX));
1734:                            sb.append(" "); // NOI18N
1735:                            sb
1736:                                    .append(map
1737:                                            .getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX));
1738:                        }
1739:
1740:                        used[XhtmlCss.BORDER_LEFT_STYLE_INDEX] = true;
1741:                        used[XhtmlCss.BORDER_TOP_STYLE_INDEX] = true;
1742:                        used[XhtmlCss.BORDER_RIGHT_STYLE_INDEX] = true;
1743:                        used[XhtmlCss.BORDER_BOTTOM_STYLE_INDEX] = true;
1744:                        sb.append("; ");
1745:                    }
1746:
1747:                    if (allBorderColors) {
1748:                        sb.append(CssConstants.CSS_BORDER_COLOR_PROPERTY);
1749:                        sb.append(": "); // NOI18N
1750:
1751:                        if (sameBorderColor) {
1752:                            sb
1753:                                    .append(map
1754:                                            .getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX));
1755:                        } else {
1756:                            sb.append(map
1757:                                    .getValue(XhtmlCss.BORDER_TOP_COLOR_INDEX));
1758:                            sb.append(" "); // NOI18N
1759:                            sb
1760:                                    .append(map
1761:                                            .getValue(XhtmlCss.BORDER_RIGHT_COLOR_INDEX));
1762:                            sb.append(" "); // NOI18N
1763:                            sb
1764:                                    .append(map
1765:                                            .getValue(XhtmlCss.BORDER_BOTTOM_COLOR_INDEX));
1766:                            sb.append(" "); // NOI18N
1767:                            sb
1768:                                    .append(map
1769:                                            .getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX));
1770:                        }
1771:
1772:                        used[XhtmlCss.BORDER_LEFT_COLOR_INDEX] = true;
1773:                        used[XhtmlCss.BORDER_TOP_COLOR_INDEX] = true;
1774:                        used[XhtmlCss.BORDER_RIGHT_COLOR_INDEX] = true;
1775:                        used[XhtmlCss.BORDER_BOTTOM_COLOR_INDEX] = true;
1776:                        sb.append("; ");
1777:                    }
1778:
1779:                    // TODO - do something about border-left, border-right, etc.?
1780:                    boolean allBorderTop = !used[XhtmlCss.BORDER_TOP_STYLE_INDEX]
1781:                            && !used[XhtmlCss.BORDER_TOP_COLOR_INDEX]
1782:                            && !used[XhtmlCss.BORDER_TOP_WIDTH_INDEX]
1783:                            && (map.getValue(XhtmlCss.BORDER_TOP_STYLE_INDEX) != null)
1784:                            && (map.getValue(XhtmlCss.BORDER_TOP_COLOR_INDEX) != null)
1785:                            && (map.getValue(XhtmlCss.BORDER_TOP_WIDTH_INDEX) != null);
1786:
1787:                    if (allBorderTop) {
1788:                        sb.append(CssConstants.CSS_BORDER_TOP_PROPERTY);
1789:                        sb.append(": "); // NOI18N
1790:                        sb
1791:                                .append(map
1792:                                        .getValue(XhtmlCss.BORDER_TOP_STYLE_INDEX));
1793:                        sb.append(" "); // NOI18N
1794:                        sb
1795:                                .append(map
1796:                                        .getValue(XhtmlCss.BORDER_TOP_COLOR_INDEX));
1797:                        sb.append(" "); // NOI18N
1798:                        sb
1799:                                .append(map
1800:                                        .getValue(XhtmlCss.BORDER_TOP_WIDTH_INDEX));
1801:                        sb.append("; ");
1802:                        used[XhtmlCss.BORDER_TOP_STYLE_INDEX] = true;
1803:                        used[XhtmlCss.BORDER_TOP_COLOR_INDEX] = true;
1804:                        used[XhtmlCss.BORDER_TOP_WIDTH_INDEX] = true;
1805:                    }
1806:
1807:                    boolean allBorderRight = !used[XhtmlCss.BORDER_RIGHT_STYLE_INDEX]
1808:                            && !used[XhtmlCss.BORDER_RIGHT_COLOR_INDEX]
1809:                            && !used[XhtmlCss.BORDER_RIGHT_WIDTH_INDEX]
1810:                            && (map.getValue(XhtmlCss.BORDER_RIGHT_STYLE_INDEX) != null)
1811:                            && (map.getValue(XhtmlCss.BORDER_RIGHT_COLOR_INDEX) != null)
1812:                            && (map.getValue(XhtmlCss.BORDER_RIGHT_WIDTH_INDEX) != null);
1813:
1814:                    if (allBorderRight) {
1815:                        sb.append(CssConstants.CSS_BORDER_RIGHT_PROPERTY);
1816:                        sb.append(": "); // NOI18N
1817:                        sb.append(map
1818:                                .getValue(XhtmlCss.BORDER_RIGHT_STYLE_INDEX));
1819:                        sb.append(" "); // NOI18N
1820:                        sb.append(map
1821:                                .getValue(XhtmlCss.BORDER_RIGHT_COLOR_INDEX));
1822:                        sb.append(" "); // NOI18N
1823:                        sb.append(map
1824:                                .getValue(XhtmlCss.BORDER_RIGHT_WIDTH_INDEX));
1825:                        sb.append("; ");
1826:                        used[XhtmlCss.BORDER_RIGHT_STYLE_INDEX] = true;
1827:                        used[XhtmlCss.BORDER_RIGHT_COLOR_INDEX] = true;
1828:                        used[XhtmlCss.BORDER_RIGHT_WIDTH_INDEX] = true;
1829:                    }
1830:
1831:                    boolean allBorderBottom = !used[XhtmlCss.BORDER_BOTTOM_STYLE_INDEX]
1832:                            && !used[XhtmlCss.BORDER_BOTTOM_COLOR_INDEX]
1833:                            && !used[XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX]
1834:                            && (map
1835:                                    .getValue(XhtmlCss.BORDER_BOTTOM_STYLE_INDEX) != null)
1836:                            && (map
1837:                                    .getValue(XhtmlCss.BORDER_BOTTOM_COLOR_INDEX) != null)
1838:                            && (map
1839:                                    .getValue(XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX) != null);
1840:
1841:                    if (allBorderBottom) {
1842:                        sb.append(CssConstants.CSS_BORDER_BOTTOM_PROPERTY);
1843:                        sb.append(": "); // NOI18N
1844:                        sb.append(map
1845:                                .getValue(XhtmlCss.BORDER_BOTTOM_STYLE_INDEX));
1846:                        sb.append(" "); // NOI18N
1847:                        sb.append(map
1848:                                .getValue(XhtmlCss.BORDER_BOTTOM_COLOR_INDEX));
1849:                        sb.append(" "); // NOI18N
1850:                        sb.append(map
1851:                                .getValue(XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX));
1852:                        sb.append("; ");
1853:                        used[XhtmlCss.BORDER_BOTTOM_STYLE_INDEX] = true;
1854:                        used[XhtmlCss.BORDER_BOTTOM_COLOR_INDEX] = true;
1855:                        used[XhtmlCss.BORDER_BOTTOM_WIDTH_INDEX] = true;
1856:                    }
1857:
1858:                    boolean allBorderLeft = !used[XhtmlCss.BORDER_LEFT_STYLE_INDEX]
1859:                            && !used[XhtmlCss.BORDER_LEFT_COLOR_INDEX]
1860:                            && !used[XhtmlCss.BORDER_LEFT_WIDTH_INDEX]
1861:                            && (map.getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX) != null)
1862:                            && (map.getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX) != null)
1863:                            && (map.getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX) != null);
1864:
1865:                    if (allBorderLeft) {
1866:                        sb.append(CssConstants.CSS_BORDER_LEFT_PROPERTY);
1867:                        sb.append(": "); // NOI18N
1868:                        sb.append(map
1869:                                .getValue(XhtmlCss.BORDER_LEFT_STYLE_INDEX));
1870:                        sb.append(" "); // NOI18N
1871:                        sb.append(map
1872:                                .getValue(XhtmlCss.BORDER_LEFT_COLOR_INDEX));
1873:                        sb.append(" "); // NOI18N
1874:                        sb.append(map
1875:                                .getValue(XhtmlCss.BORDER_LEFT_WIDTH_INDEX));
1876:                        sb.append("; ");
1877:                        used[XhtmlCss.BORDER_LEFT_STYLE_INDEX] = true;
1878:                        used[XhtmlCss.BORDER_LEFT_COLOR_INDEX] = true;
1879:                        used[XhtmlCss.BORDER_LEFT_WIDTH_INDEX] = true;
1880:                    }
1881:                }
1882:
1883:                // Look for collapsible margins
1884:                boolean allMargins = (map.getValue(XhtmlCss.MARGIN_TOP_INDEX) != null)
1885:                        && (map.getValue(XhtmlCss.MARGIN_RIGHT_INDEX) != null)
1886:                        && (map.getValue(XhtmlCss.MARGIN_BOTTOM_INDEX) != null)
1887:                        && (map.getValue(XhtmlCss.MARGIN_LEFT_INDEX) != null);
1888:
1889:                if (allMargins) {
1890:                    sb.append(CssConstants.CSS_MARGIN_PROPERTY);
1891:                    sb.append(": "); // NOI18N
1892:
1893:                    // TODO - compress to two or one values if sides are the same
1894:                    sb.append(map.getValue(XhtmlCss.MARGIN_TOP_INDEX));
1895:
1896:                    if (map.getValue(XhtmlCss.MARGIN_TOP_INDEX).equals(
1897:                            map.getValue(XhtmlCss.MARGIN_RIGHT_INDEX))
1898:                            && map.getValue(XhtmlCss.MARGIN_TOP_INDEX).equals(
1899:                                    map.getValue(XhtmlCss.MARGIN_BOTTOM_INDEX))
1900:                            && map.getValue(XhtmlCss.MARGIN_TOP_INDEX).equals(
1901:                                    map.getValue(XhtmlCss.MARGIN_LEFT_INDEX))) {
1902:                        // Use a single value to represent all four sides.
1903:                        // I could also look to see if the horizontal and vertical sides are identical
1904:                        // and compress to two values but I'm getting bored
1905:                    } else {
1906:                        sb.append(" "); // NOI18N
1907:                        sb.append(map.getValue(XhtmlCss.MARGIN_RIGHT_INDEX));
1908:                        sb.append(" "); // NOI18N
1909:                        sb.append(map.getValue(XhtmlCss.MARGIN_BOTTOM_INDEX));
1910:                        sb.append(" "); // NOI18N
1911:                        sb.append(map.getValue(XhtmlCss.MARGIN_LEFT_INDEX));
1912:                    }
1913:
1914:                    sb.append("; ");
1915:                    used[XhtmlCss.MARGIN_TOP_INDEX] = true;
1916:                    used[XhtmlCss.MARGIN_RIGHT_INDEX] = true;
1917:                    used[XhtmlCss.MARGIN_BOTTOM_INDEX] = true;
1918:                    used[XhtmlCss.MARGIN_LEFT_INDEX] = true;
1919:                }
1920:
1921:                // Look for collapsible padding
1922:                boolean allPadding = (map.getValue(XhtmlCss.PADDING_TOP_INDEX) != null)
1923:                        && (map.getValue(XhtmlCss.PADDING_RIGHT_INDEX) != null)
1924:                        && (map.getValue(XhtmlCss.PADDING_BOTTOM_INDEX) != null)
1925:                        && (map.getValue(XhtmlCss.PADDING_LEFT_INDEX) != null);
1926:
1927:                if (allPadding) {
1928:                    sb.append(CssConstants.CSS_PADDING_PROPERTY);
1929:                    sb.append(": "); // NOI18N
1930:
1931:                    // TODO - compress to two or one values if sides are the same
1932:                    sb.append(map.getValue(XhtmlCss.PADDING_TOP_INDEX));
1933:
1934:                    if (map.getValue(XhtmlCss.PADDING_TOP_INDEX).equals(
1935:                            map.getValue(XhtmlCss.PADDING_RIGHT_INDEX))
1936:                            && map
1937:                                    .getValue(XhtmlCss.PADDING_TOP_INDEX)
1938:                                    .equals(
1939:                                            map
1940:                                                    .getValue(XhtmlCss.PADDING_BOTTOM_INDEX))
1941:                            && map.getValue(XhtmlCss.PADDING_TOP_INDEX).equals(
1942:                                    map.getValue(XhtmlCss.PADDING_LEFT_INDEX))) {
1943:                        // Use a single value to represent all four sides.
1944:                        // I could also look to see if the horizontal and vertical sides are identical
1945:                        // and compress to two values but I'm getting bored
1946:                    } else {
1947:                        sb.append(" "); // NOI18N
1948:                        sb.append(map.getValue(XhtmlCss.PADDING_RIGHT_INDEX));
1949:                        sb.append(" "); // NOI18N
1950:                        sb.append(map.getValue(XhtmlCss.PADDING_BOTTOM_INDEX));
1951:                        sb.append(" "); // NOI18N
1952:                        sb.append(map.getValue(XhtmlCss.PADDING_LEFT_INDEX));
1953:                    }
1954:
1955:                    sb.append("; ");
1956:                    used[XhtmlCss.PADDING_TOP_INDEX] = true;
1957:                    used[XhtmlCss.PADDING_RIGHT_INDEX] = true;
1958:                    used[XhtmlCss.PADDING_BOTTOM_INDEX] = true;
1959:                    used[XhtmlCss.PADDING_LEFT_INDEX] = true;
1960:                }
1961:
1962:                // Background
1963:                boolean allBackground = (map
1964:                        .getValue(XhtmlCss.BACKGROUND_COLOR_INDEX) != null)
1965:                        && // OR: same as default
1966:                        (map.getValue(XhtmlCss.BACKGROUND_IMAGE_INDEX) != null)
1967:                        && (map.getValue(XhtmlCss.BACKGROUND_POSITION_INDEX) != null)
1968:                        &&
1969:                        // TODO: (map.getValue(XhtmlCss.BACKGROUND_ATTACHMENT_INDEX) != null) &&
1970:                        (map.getValue(XhtmlCss.BACKGROUND_REPEAT_INDEX) != null);
1971:
1972:                if (allBackground) {
1973:                    sb.append(CssConstants.CSS_BACKGROUND_PROPERTY);
1974:                    sb.append(": "); // NOI18N
1975:
1976:                    // TODO -- only do if different from the default!
1977:                    sb.append(map.getValue(XhtmlCss.BACKGROUND_COLOR_INDEX));
1978:                    sb.append(" "); // NOI18N
1979:                    sb.append(map.getValue(XhtmlCss.BACKGROUND_IMAGE_INDEX));
1980:                    sb.append(" "); // NOI18N
1981:                    sb.append(map.getValue(XhtmlCss.BACKGROUND_REPEAT_INDEX));
1982:
1983:                    //sb.append(" "); // NOI18N
1984:                    //sb.append(map.getValue(XhtmlCss.BACKGROUND_ATTACHMENT_INDEX));
1985:                    sb.append(" "); // NOI18N
1986:                    sb.append(map.getValue(XhtmlCss.BACKGROUND_POSITION_INDEX));
1987:                    sb.append("; ");
1988:                    used[XhtmlCss.BACKGROUND_COLOR_INDEX] = true;
1989:                    used[XhtmlCss.BACKGROUND_IMAGE_INDEX] = true;
1990:                    used[XhtmlCss.BACKGROUND_POSITION_INDEX] = true;
1991:                    used[XhtmlCss.BACKGROUND_REPEAT_INDEX] = true;
1992:
1993:                    //used[XhtmlCss.BACKGROUND_ATTACHMENT_INDEX] = true;
1994:                }
1995:
1996:                // List Style
1997:                boolean allListStyles = (map
1998:                        .getValue(XhtmlCss.LIST_STYLE_TYPE_INDEX) != null)
1999:                        &&
2000:                        //(map.getValue(XhtmlCss.LIST_STYLE_POSITION_INDEX) != null) &&
2001:                        (map.getValue(XhtmlCss.LIST_STYLE_IMAGE_INDEX) != null);
2002:
2003:                if (allListStyles) {
2004:                    sb.append(CssConstants.CSS_LIST_STYLE_PROPERTY);
2005:                    sb.append(": "); // NOI18N
2006:                    sb.append(map.getValue(XhtmlCss.LIST_STYLE_TYPE_INDEX));
2007:                    sb.append(" "); // NOI18N
2008:                    sb.append(map.getValue(XhtmlCss.LIST_STYLE_IMAGE_INDEX));
2009:
2010:                    //sb.append(" "); // NOI18N
2011:                    //sb.append(map.getValue(XhtmlCss.LIST_STYLE_POSITION_INDEX));
2012:                    sb.append("; ");
2013:                    used[XhtmlCss.LIST_STYLE_TYPE_INDEX] = true;
2014:                    used[XhtmlCss.LIST_STYLE_IMAGE_INDEX] = true;
2015:
2016:                    //used[XhtmlCss.LIST_STYLE_POSITION_INDEX] = true;
2017:                }
2018:
2019:                // TODO: font
2020:                // Write out all items in the map we haven't already covered by a shorthand property
2021:                boolean first = true;
2022:
2023:                for (int i = 0; i < size; i++) {
2024:                    if (used[i]) {
2025:                        // Already processed as a shorthand
2026:                        continue;
2027:                    }
2028:
2029:                    Value v = map.getValue(i);
2030:
2031:                    if (v != null) {
2032:                        if (first) {
2033:                            first = false;
2034:                        } else {
2035:                            sb.append("; ");
2036:                        }
2037:
2038:                        sb.append(getPropertyName(i));
2039:                        sb.append(": ");
2040:                        sb.append(v);
2041:
2042:                        if (map.isImportant(i)) {
2043:                            sb.append(" !important");
2044:                        }
2045:                    }
2046:                }
2047:
2048:                return sb.toString();
2049:            }
2050:
2051:            String computeFileName(Object location) {
2052:                UserAgent userAgent = getUserAgent();
2053:                if (userAgent == null) {
2054:                    return location == null ? null : location.toString();
2055:                }
2056:
2057:                return userAgent.computeFileName(location);
2058:            }
2059:
2060:            int computeLineNumber(Object location, int lineno) {
2061:                UserAgent userAgent = getUserAgent();
2062:                if (userAgent == null) {
2063:                    return lineno;
2064:                }
2065:
2066:                return userAgent.computeLineNumber(location, lineno);
2067:            }
2068:
2069:            URL getDocumentUrl() {
2070:                UserAgent userAgent = getUserAgent();
2071:                if (userAgent == null) {
2072:                    return null;
2073:                }
2074:
2075:                return userAgent.getDocumentUrl(getDocument());
2076:            }
2077:
2078:            private UserAgent getUserAgent() {
2079:                CSSEngineUserAgent cssEngineUserAgent = getCSSEngineUserAgent();
2080:                if (cssEngineUserAgent instanceof  UserAgent) {
2081:                    return (UserAgent) cssEngineUserAgent;
2082:                }
2083:                return null;
2084:            }
2085:
2086:            /** Class used to wrap serialized Strings as batik values and get
2087:             * the right behavior out of the style map serialization routines
2088:             * without having the Strings modified in anyway. These Strings
2089:             * aren't necessarily Strings in the style - the may represent
2090:             * floats, urls, etc.
2091:             */
2092:            class MapStringValue extends AbstractValue {
2093:                private String s;
2094:
2095:                MapStringValue(String s) {
2096:                    this .s = s;
2097:                }
2098:
2099:                public String getCssText() {
2100:                    return s;
2101:                }
2102:
2103:                public boolean equals(Object obj) {
2104:                    if (obj instanceof  MapStringValue) {
2105:                        return s.equals(((MapStringValue) obj).s);
2106:                    }
2107:
2108:                    return false;
2109:                }
2110:
2111:                public String toString() {
2112:                    return s;
2113:                }
2114:            }
2115:
2116:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.