📄 stylesheet.java
字号:
elements.addElement(null); } else { elements.addElement(selector.substring(dotIndex + 1, spaceIndex)); } elements.addElement(null); dotIndex = spaceIndex + 1; } else if (poundIndex != -1 && poundIndex < spaceIndex) { // # if (poundIndex == lastIndex) { elements.addElement(""); } else { elements.addElement(selector.substring(lastIndex, poundIndex)); } elements.addElement(null); if ((poundIndex + 1) == spaceIndex) { elements.addElement(null); } else { elements.addElement(selector.substring(poundIndex + 1, spaceIndex)); } poundIndex = spaceIndex + 1; } else { // id elements.addElement(selector.substring(lastIndex, spaceIndex)); elements.addElement(null); elements.addElement(null); } lastIndex = spaceIndex + 1; } // Create the tag, id, and class arrays. int total = elements.size(); int numTags = total / 3; String[] tags = new String[numTags]; String[] ids = new String[numTags]; String[] classes = new String[numTags]; for (int index = 0, eIndex = total - 3; index < numTags; index++, eIndex -= 3) { tags[index] = (String)elements.elementAt(eIndex); classes[index] = (String)elements.elementAt(eIndex + 1); ids[index] = (String)elements.elementAt(eIndex + 2); } return createResolvedStyle(selector, tags, ids, classes); } finally { SearchBuffer.releaseSearchBuffer(sb); } } /** * Should be invoked when a new rule is added that did not previously * exist. Goes through and refreshes the necessary resolved * rules. */ private synchronized void refreshResolvedRules(String selectorName, String[] selector, Style newStyle, int specificity) { if (resolvedStyles.size() > 0) { Enumeration values = resolvedStyles.elements(); while (values.hasMoreElements()) { ResolvedStyle style = (ResolvedStyle)values.nextElement(); if (style.matches(selectorName)) { style.insertStyle(newStyle, specificity); } } } } /** * A temporary class used to hold a Vector, a StringBuffer and a * Hashtable. This is used to avoid allocing a lot of garbage when * searching for rules. Use the static method obtainSearchBuffer and * releaseSearchBuffer to get a SearchBuffer, and release it when * done. */ private static class SearchBuffer { /** A stack containing instances of SearchBuffer. Used in getting * rules. */ static Stack searchBuffers = new Stack(); // A set of temporary variables that can be used in whatever way. Vector vector = null; StringBuffer stringBuffer = null; Hashtable hashtable = null; /** * Returns an instance of SearchBuffer. Be sure and issue * a releaseSearchBuffer when done with it. */ static SearchBuffer obtainSearchBuffer() { SearchBuffer sb; try { if(!searchBuffers.empty()) { sb = (SearchBuffer)searchBuffers.pop(); } else { sb = new SearchBuffer(); } } catch (EmptyStackException ese) { sb = new SearchBuffer(); } return sb; } /** * Adds <code>sb</code> to the stack of SearchBuffers that can * be used. */ static void releaseSearchBuffer(SearchBuffer sb) { sb.empty(); searchBuffers.push(sb); } StringBuffer getStringBuffer() { if (stringBuffer == null) { stringBuffer = new StringBuffer(); } return stringBuffer; } Vector getVector() { if (vector == null) { vector = new Vector(); } return vector; } Hashtable getHashtable() { if (hashtable == null) { hashtable = new Hashtable(); } return hashtable; } void empty() { if (stringBuffer != null) { stringBuffer.setLength(0); } if (vector != null) { vector.removeAllElements(); } if (hashtable != null) { hashtable.clear(); } } } static final Border noBorder = new EmptyBorder(0,0,0,0); /** * Class to carry out some of the duties of * CSS formatting. Implementations of this * class enable views to present the CSS formatting * while not knowing anything about how the CSS values * are being cached. * <p> * As a delegate of Views, this object is responsible for * the insets of a View and making sure the background * is maintained according to the CSS attributes. */ public static class BoxPainter implements Serializable { BoxPainter(AttributeSet a, CSS css, StyleSheet ss) { this.ss = ss; this.css = css; border = getBorder(a); binsets = border.getBorderInsets(null); topMargin = getLength(CSS.Attribute.MARGIN_TOP, a); bottomMargin = getLength(CSS.Attribute.MARGIN_BOTTOM, a); leftMargin = getLength(CSS.Attribute.MARGIN_LEFT, a); rightMargin = getLength(CSS.Attribute.MARGIN_RIGHT, a); bg = ss.getBackground(a); if (ss.getBackgroundImage(a) != null) { bgPainter = new BackgroundImagePainter(a, css, ss); } } /** * Fetches a border to render for the given attributes. * PENDING(prinz) This is pretty badly hacked at the * moment. */ Border getBorder(AttributeSet a) { Border b = noBorder; Object o = a.getAttribute(CSS.Attribute.BORDER_STYLE); if (o != null) { String bstyle = o.toString(); int bw = (int) getLength(CSS.Attribute.BORDER_TOP_WIDTH, a); if (bw > 0) { if (bstyle.equals("inset")) { Color c = getBorderColor(a); b = new BevelBorder(BevelBorder.LOWERED, c.brighter(), c.darker()); } else if (bstyle.equals("outset")) { Color c = getBorderColor(a); b = new BevelBorder(BevelBorder.RAISED, c.brighter(), c.darker()); } else if (bstyle.equals("solid")) { Color c = getBorderColor(a); b = new LineBorder(c, bw); } } } return b; } /** * Fetches the color to use for borders. This will either be * the value specified by the border-color attribute (which * is not inherited), or it will default to the color attribute * (which is inherited). */ Color getBorderColor(AttributeSet a) { Color color = css.getColor(a, CSS.Attribute.BORDER_COLOR); if (color == null) { color = css.getColor(a, CSS.Attribute.COLOR); if (color == null) { return Color.black; } } return color; } /** * Fetches the inset needed on a given side to * account for the margin, border, and padding. * * @param side The size of the box to fetch the * inset for. This can be View.TOP, * View.LEFT, View.BOTTOM, or View.RIGHT. * @param v the view making the request. This is * used to get the AttributeSet, and may be used to * resolve percentage arguments. * @exception IllegalArgumentException for an invalid direction */ public float getInset(int side, View v) { AttributeSet a = v.getAttributes(); float inset = 0; switch(side) { case View.LEFT: inset += getOrientationMargin(HorizontalMargin.LEFT, leftMargin, a, isLeftToRight(v)); inset += binsets.left; inset += getLength(CSS.Attribute.PADDING_LEFT, a); break; case View.RIGHT: inset += getOrientationMargin(HorizontalMargin.RIGHT, rightMargin, a, isLeftToRight(v)); inset += binsets.right; inset += getLength(CSS.Attribute.PADDING_RIGHT, a); break; case View.TOP: inset += topMargin; inset += binsets.top; inset += getLength(CSS.Attribute.PADDING_TOP, a); break; case View.BOTTOM: inset += bottomMargin; inset += binsets.bottom; inset += getLength(CSS.Attribute.PADDING_BOTTOM, a); break; default: throw new IllegalArgumentException("Invalid side: " + side); } return inset; } /** * Paints the CSS box according to the attributes * given. This should paint the border, padding, * and background. * * @param g the rendering surface. * @param x the x coordinate of the allocated area to * render into. * @param y the y coordinate of the allocated area to * render into. * @param w the width of the allocated area to render into. * @param h the height of the allocated area to render into. * @param v the view making the request. This is * used to get the AttributeSet, and may be used to * resolve percentage arguments. */ public void paint(Graphics g, float x, float y, float w, float h, View v) { // PENDING(prinz) implement real rendering... which would // do full set of border and background capabilities. // remove margin float dx = 0; float dy = 0; float dw = 0; float dh = 0; AttributeSet a = v.getAttributes(); boolean isLeftToRight = isLeftToRight(v); float localLeftMargin = getOrientationMargin(HorizontalMargin.LEFT, leftMargin, a, isLeftToRight); float localRightMargin = getOrientationMargin(HorizontalMargin.RIGHT, rightMargin, a, isLeftToRight); if (!(v instanceof HTMLEditorKit.HTMLFactory.BodyBlockView)) { dx = localLeftMargin; dy = topMargin; dw = -(localLeftMargin + localRightMargin); dh = -(topMargin + bottomMargin); } if (bg != null) { g.setColor(bg); g.fillRect((int) (x + dx), (int) (y + dy), (int) (w + dw), (int) (h + dh)); } if (bgPainter != null) { bgPainter.paint(g, x + dx, y + dy, w + dw, h + dh, v); } x += localLeftMargin; y += topMargin; w -= localLeftMargin + localRightMargin; h -= topMargin + bottomMargin; if (border instanceof BevelBorder) { //BevelBorder does not support border width int bw = (int) getLength(CSS.Attribute.BORDER_TOP_WIDTH, a); for (int i = bw - 1; i >= 0; i--) { border.paintBorder(null, g, (int) x + i, (int) y + i, (int) w - 2 * i, (int) h - 2 * i); } } else { border.paintBorder(null, g, (int) x, (int) y, (int) w, (int) h); } } float getLength(CSS.Attribute key, AttributeSet a) { return css.getLength(a, key, ss); } static boolean isLeftToRight(View v) { boolean ret = true; if (isOrientationAware(v)) { Container container = null; if (v != null && (container = v.getContainer()) != null) { ret = container.getComponentOrientation().isLeftToRight(); } } return ret; } /* * only certain tags are concerned about orientation * <dir>, <menu>, <ul>, <ol> * for all others we return true. It is implemented this way * for performance purposes */ static boolean isOrientationAware(View v) { boolean ret = false; AttributeSet attr = null; Object obj = null; if (v != null && (attr = v.getElement().getAttributes()) != null && (obj = attr.getAttribute(StyleConstants.NameAttribute)) instanceof HTML.Tag && (obj == HTML.Tag.DIR || obj == HTML.Tag.MENU || obj == HTML.Tag.UL || obj == HTML.Tag.OL)) { ret = true; } return ret; } static enum HorizontalMargin { LEFT, RIGHT }; /** * for <dir>, <menu>, <ul> etc. * margins are Left-To-Right/Right-To-Left depended. * see 5088268 for more details * margin-(left|right)-(ltr|rtl) were introduced to describe it * if margin-(left|right) is present we are to use it. * * @param side The horizontal side to fetch margin for * This can be HorizontalMargin.LEFT or HorizontalMargin.RIGHT * @param cssMargin margin from css * @param a AttributeSet for the View we getting margin for * @param isLeftToRight * @return orientation depended margin */ float getOrientationMargin(HorizontalMargin side, float cssMargin, AttributeSet a, boolean isLeftToRight) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -