Package com.google.minijoe.html.css

Source Code of com.google.minijoe.html.css.Style

// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.minijoe.html.css;


import com.google.minijoe.common.Util;
import com.google.minijoe.html.HtmlWidget;
import com.google.minijoe.html.SystemRequestHandler;

import java.util.*;

import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Image;

/**
* Class to representing a set of CSS properties (e.g. a CSS style attribute).
*
* @author Stefan Haustein
*/
public class Style {

  /**
   * Assumed device DPI constant.
   */
  public static final int DPI = 100;

  // inherited properties and background color
  public static final int BACKGROUND_COLOR = 0; // only non-inherited
  public static final int BORDER_COLLAPSE = 1;
  public static final int BORDER_SPACING = 2;   
  public static final int CAPTION_SIDE = 3;
  public static final int COLOR = 4;
  public static final int DISPLAY = 5;
  public static final int EMPTY_CELLS = 6;
  public static final int FONT_WEIGHT = 7;
  public static final int FONT_SIZE = 8;
  public static final int LIST_STYLE_POSITION = 9;
  public static final int LIST_STYLE_TYPE = 10;
  public static final int TEXT_ALIGN = 11;
  public static final int TEXT_DECORATION = 12;
  public static final int TEXT_INDENT = 13;
  public static final int TEXT_TRANSFORM = 14;
  public static final int VISIBILITY = 15;
  public static final int WHITE_SPACE = 16;

  // Note: TOP/RIGHT/BOTTOM/LEFT must be adjacent constants in ascending order
  public static final int BACKGROUND_POSITION_X = 17;
  public static final int BACKGROUND_POSITION_Y = 18;
  public static final int BACKGROUND_REPEAT = 19;
 
  public static final int BORDER_TOP_COLOR = 20;
  public static final int BORDER_RIGHT_COLOR = 21;
  public static final int BORDER_BOTTOM_COLOR = 22;
  public static final int BORDER_LEFT_COLOR = 23;
  public static final int BORDER_TOP_WIDTH = 24;
  public static final int BORDER_RIGHT_WIDTH = 25;
  public static final int BORDER_BOTTOM_WIDTH = 26;
  public static final int BORDER_LEFT_WIDTH = 27;
  public static final int BORDER_TOP_STYLE = 28;
  public static final int BORDER_RIGHT_STYLE = 29;
  public static final int BORDER_BOTTOM_STYLE = 30;
  public static final int BORDER_LEFT_STYLE = 31;
  public static final int BOTTOM = 32;
  public static final int CLEAR = 33;
  public static final int CLIP = 34;
  public static final int FLOAT = 35;
  public static final int HEIGHT = 36;
  public static final int LEFT = 37;
  public static final int MARGIN_TOP = 38;
  public static final int MARGIN_RIGHT = 39;
  public static final int MARGIN_BOTTOM = 40;
  public static final int MARGIN_LEFT = 41;
  public static final int OVERFLOW = 42;
  public static final int PADDING_TOP = 43;
  public static final int PADDING_RIGHT = 44;
  public static final int PADDING_BOTTOM = 45;
  public static final int PADDING_LEFT = 46;
  public static final int POSITION = 47;
  public static final int RIGHT = 48;
  public static final int TABLE_LAYOUT = 49;
  public static final int TOP = 50;
  public static final int VERTICAL_ALIGN = 51;
  public static final int WIDTH = 52;
  public static final int Z_INDEX = 53;
 
  private static final int BORDER_TOP_SPACING = 54;
  private static final int BORDER_RIGHT_SPACING = 55;
  private static final int BORDER_BOTTOM_SPACING = 56;
  private static final int BORDER_LEFT_SPACING = 57;

  // all inherited properties and the background color
  private static final int TEXT_PROPERTY_COUNT = 17;
  private static final int PROPERTY_COUNT = 58;

  /**
   * Flag for -top/-right/-bottom/-left abbreviation multiple value property
   * handling
   */
  public static final int MULTIVALUE_TRBL = 0x10000;
  private static final int MULTIVALUE_BORDER = 0x20000;

  private static final int MULTIVALUE_BACKGROUND = 0x1000;
  private static final int MULTIVALUE_BACKGROUND_POSITION = 0x1001;
  private static final int MULTIVALUE_FONT = 0x1002;
  private static final int MULTIVALUE_LIST_STYLE = 0x1003;

  static final int UNRECOGNIZED_PROPERTY_ID = 0x1234;
  static final Integer UNRECOGNIZED_PROPERTY =
    new Integer(UNRECOGNIZED_PROPERTY_ID);

  // general values
  public static final int NONE = 0;
  public static final int AUTO = 1001;
  public static final int INHERIT = 1002;
  public static final int HIDDEN = 1003;
  public static final int INVALID = 1004;

  // font-weights
  public static final int NORMAL = 500000;
  public static final int BOLD = 700000;

  // various
  // note: top/left/right/bottom already defined as property names
  public static final int ABSOLUTE = 1100;
  public static final int BASELINE = 1101;
  public static final int BOTH = 1102;
  public static final int CENTER = 1103;
  public static final int CAPITALIZE = 1104;
  public static final int FIXED = 1105;
  public static final int HIDE = 1106;
  public static final int INSIDE = 1107;
  public static final int JUSTIFY = 1108;
  public static final int MEDIUM = 1109;
  public static final int MIDDLE = 1110;
  public static final int NO_REPEAT = 1111;
  public static final int NOWRAP = 1112;
  public static final int OUTSIDE = 1113;
  public static final int PRE = 1114;
  public static final int PRE_WRAP = 1115;
  public static final int PRE_LINE = 1116;
  public static final int RELATIVE = 1117;
  public static final int REPEAT = 1118;
  public static final int REPEAT_X = 1119;
  public static final int REPEAT_Y = 1120;
  public static final int SCROLL = 1121;
  public static final int SUB = 1122;
  public static final int SUPER = 1123;
  public static final int SHOW = 1124;
  public static final int STATIC = 1125;
  public static final int TEXT_TOP = 1126;
  public static final int TEXT_BOTTOM = 1127;
  public static final int THICK = 1128;
  public static final int THIN = 1129;
  public static final int UNDERLINE = 1130;
  public static final int UPPERCASE = 1131;

  // display values
  public static final int INLINE = 1201;
  public static final int BLOCK = 1202;
  public static final int COLLAPSE = 1203;
  public static final int INLINE_BLOCK = 1204;
  public static final int LIST_ITEM = 1205;
  public static final int TABLE = 1206;
  public static final int INLINE_TABLE = 1207;
  public static final int TABLE_ROW = 1208;
  public static final int TABLE_ROW_GROUP = 1209;
  public static final int TABLE_HEADER_GROUP = 1210;
  public static final int TABLE_FOOTER_GROUP = 1211;
  public static final int TABLE_COLUMN = 1212;
  public static final int TABLE_COLUMN_GROUP = 1213;
  public static final int TABLE_CELL = 1214;
  public static final int TABLE_CAPTION = 1215;

  // list styles
  public static final int SQUARE = 1301;
  public static final int CIRCLE = 1302;
  public static final int DISC = 1303;
  public static final int DECIMAL = 1304;

  // border styles
  public static final int DOTTED = 1401;
  public static final int DASHED = 1402;
  public static final int SOLID = 1403;
  public static final int DOUBLE = 1404;
  public static final int GROOVE = 1405;
  public static final int RIDGE = 1406;
  public static final int INSET = 1407;
  public static final int OUTSET = 1408;

  /**
   * Unit constant for numbers without unit.
   */
  public static final byte NUMBER = 0;

  /**
   * Unit constant for percent values.
   */
  public static final byte PERCENT = 1;

  /**
   * Unit constant for centimeters (cm).
   */
  public static final byte CM = 2;

  /**
   * Unit constant for the m-width typographic unit.
   */
  public static final byte EM = 3;

  /**
   * Unit constant for the lowercase letter height typographic unit (ex).
   */
  public static final byte EX = 4;

  /**
   * Unit constant for inches (in).
   */
  public static final byte IN = 5;

  /**
   * Unit constant for millimeters (cm).
   */
  public static final byte MM = 6;

  /**
   * Unit constant for pica (pc, 12pt).
   */
  public static final byte PC = 7;

  /**
   * Unit constant for point (pt, 1/72 in).
   */
  public static final byte PT = 8;

  /**
   * Unit constant for pixels.
   */
  public static final byte PX = 9;

  /**
   * Unit constant to mark enumerated values (e.g. LEFT/RIGHT/CENTER/JUSTIFY
   * etc.).
   */
  public static final byte ENUM = 16;

  /**
   * Unit constant for color values (Note: The COLOR constant denotes the CSS
   * property name "color").
   */
  public static final byte ARGB = 17;

  private static final Style EMPTY_STYLE = new Style();

  /**
   * Names of the units, the order must correspond to the unit constants
   * (NUMBER, PERCENT, CM, ...)
   */
  private static final String[] UNIT_NAMES = {
    "", "%", "cm", "em", "ex", "in", "mm", "pc", "pt", "px"};

  private static final Hashtable NAME_TO_ID_MAP;
  private static final Hashtable ID_TO_NAME_MAP;
  private static final Hashtable VALUE_TO_ID_MAP;
  private static final Hashtable ID_TO_VALUE_MAP;

  private static Font[] FONT_CACHE;
  private static final Object[] CHAR_WIDTHS = new Object[4];
  private static final int CHAR_WIDTH_CACHE_SIZE = 128;

  /**
   * Bit field, keeping track of which fields have explicitly been set for this
   * Style object.
   */
  private long valuesSet;
  private int[] values = new int[TEXT_PROPERTY_COUNT];
  private byte[] units = new byte[TEXT_PROPERTY_COUNT];


  static final int[] TOP_LEVEL = new int[0];

  public Image[] backgroundImage;

  /**
   * Specificity of this style, set by the corresponding selector in the
   * stylesheet parse method.
   */
  int specificity;

  /**
   * Position of this style declaration inside the style sheet
   */
  int position;

  /**
   * Nested import positions
   */
  int[] nesting = TOP_LEVEL;


  private int firstSet = PROPERTY_COUNT;
  private int lastSet;

  /**
   * Font matching the style, filled on demand only.
   */
  private Font font;


  private static final String[] TRBL = {
    "-top", "-right", "-bottom", "-left"
  };

  static {
    NAME_TO_ID_MAP = new Hashtable();
    ID_TO_NAME_MAP = new Hashtable();
    VALUE_TO_ID_MAP = new Hashtable();
    ID_TO_VALUE_MAP = new Hashtable();

    addName("background", MULTIVALUE_BACKGROUND);
    addName("background-color", BACKGROUND_COLOR);
    addName("background-position", MULTIVALUE_BACKGROUND_POSITION);
    addName("background-repeat", BACKGROUND_REPEAT);
    addName("border", MULTIVALUE_BORDER | MULTIVALUE_TRBL);
    addName("border-collapse", BORDER_COLLAPSE);
    addName("border-color", MULTIVALUE_TRBL | BORDER_TOP_COLOR);
    addName("border-style", MULTIVALUE_TRBL | BORDER_TOP_STYLE);
    addName("border-width", MULTIVALUE_TRBL | BORDER_TOP_WIDTH);
    addName("border-spacing", MULTIVALUE_TRBL | BORDER_TOP_SPACING);
    addName("bottom", BOTTOM);
    addName("caption-side", CAPTION_SIDE);
    addName("clear", CLEAR);
    addName("clip", CLIP);
    addName("color", COLOR);
    addName("display", DISPLAY);
    addName("empty-cells", EMPTY_CELLS);
    addName("float", FLOAT);
    addName("font", MULTIVALUE_FONT);
    addName("font-weight", FONT_WEIGHT);
    addName("font-size", FONT_SIZE);
   
    addName("height", HEIGHT);
    addName("left", LEFT);
    addName("list-style", MULTIVALUE_LIST_STYLE);
    addName("list-style-postion", LIST_STYLE_POSITION);
    addName("list-style-type", LIST_STYLE_TYPE);
    addName("margin", MULTIVALUE_TRBL | MARGIN_TOP);
    addName("overflow", OVERFLOW);
    addName("padding", MULTIVALUE_TRBL | PADDING_TOP);
    addName("position", POSITION);
    addName("right", RIGHT);
    addName("table-layout", TABLE_LAYOUT);
    addName("text-align", TEXT_ALIGN);
    addName("text-decoration", TEXT_DECORATION);
    addName("text-indent", TEXT_INDENT);
    addName("text-transform", TEXT_TRANSFORM);
    addName("top", TOP);
    addName("vertical-align", VERTICAL_ALIGN);
    addName("visibility", VISIBILITY);
    addName("white-space", WHITE_SPACE);
    addName("width", WIDTH);
    addName("z-index", Z_INDEX);

    // special-cased in url handler
    addName("background-image", UNRECOGNIZED_PROPERTY_ID);
    // ignored
    addName("font-family", UNRECOGNIZED_PROPERTY_ID);
    addName("text-size", UNRECOGNIZED_PROPERTY_ID);

    for (int i = 0; i < 4; i++) {
      addName("border" + TRBL[i] + "-color", BORDER_TOP_COLOR + i);
      addName("border" + TRBL[i] + "-style", BORDER_TOP_STYLE + i);
      addName("border" + TRBL[i] + "-width", BORDER_TOP_WIDTH + i);
      addName("border" + TRBL[i] + "-spacing", BORDER_TOP_SPACING + i);
      addName("border" + TRBL[i], MULTIVALUE_BORDER | i);
      addName("margin" + TRBL[i], MARGIN_TOP + i);
      addName("padding" + TRBL[i], PADDING_TOP + i);
    }
   
    addValue("auto", AUTO, ENUM);
    addValue("none", NONE, ENUM);
    addValue("hidden", HIDDEN, ENUM);
    addValue("inherit", INHERIT, ENUM);

    addValue("lighter", NORMAL, NUMBER);
    addValue("normal", NORMAL, NUMBER);
    addValue("bold", BOLD, NUMBER);
    addValue("bolder", BOLD, NUMBER);

    addValue("inline", INLINE, ENUM);
    addValue("inline-block", INLINE_BLOCK, ENUM);
    addValue("block", BLOCK, ENUM);
    addValue("list-item", LIST_ITEM, ENUM);
    addValue("table", TABLE, ENUM);
    addValue("inline-table", INLINE_TABLE, ENUM);
    addValue("table-row", TABLE_ROW, ENUM);
    addValue("table-tow-group", TABLE_ROW_GROUP, ENUM);
    addValue("table-header-group", TABLE_HEADER_GROUP, ENUM);
    addValue("table-footer-group", TABLE_FOOTER_GROUP, ENUM);
    addValue("table-column", TABLE_COLUMN, ENUM);
    addValue("table-column-group", TABLE_COLUMN_GROUP, ENUM);
    addValue("table-cell", TABLE_CELL, ENUM);
    addValue("table-caption", TABLE_CAPTION, ENUM);

    // various
    // note: top/left/right/bottom already defined as property names
    addValue("absolute", ABSOLUTE, ENUM);
    addValue("baseline", BASELINE, ENUM);
    addValue("both", BOTH, ENUM);
    addValue("bottom", BOTTOM, ENUM);
    addValue("center", CENTER, ENUM);
    addValue("capitalize", CAPITALIZE, ENUM);
    addValue("fixed", FIXED, ENUM);
    addValue("hide", HIDE, ENUM);
    addValue("inside", INSIDE, ENUM);
    addValue("justify", JUSTIFY, ENUM);
    addValue("medium", MEDIUM, ENUM);
    addValue("middle", MIDDLE, ENUM);
    addValue("no-repeat", NO_REPEAT, ENUM);
    addValue("nowrap", NOWRAP, ENUM);
    addValue("outside", OUTSIDE, ENUM);
    addValue("pre", PRE, ENUM);
    addValue("pre-wrap", PRE_WRAP, ENUM);
    addValue("pre-line", PRE_LINE, ENUM);
    addValue("relative", RELATIVE, ENUM);
    addValue("scroll", SCROLL, ENUM);
    addValue("sub", SUB, ENUM);
    addValue("super", SUPER, ENUM);
    addValue("show", SHOW, ENUM);
    addValue("static", STATIC, ENUM);
    addValue("top", TOP, ENUM);
    addValue("text-top", TEXT_TOP, ENUM);
    addValue("text-bottom", TEXT_BOTTOM, ENUM);
    addValue("thick", THICK, ENUM);
    addValue("thin", THIN, ENUM);
    addValue("underline", UNDERLINE, ENUM);
    addValue("uppercase", UPPERCASE, ENUM);
    addValue("repeat", REPEAT, ENUM);
    addValue("repeat-x", REPEAT_X, ENUM);
    addValue("repeat-y", REPEAT_Y, ENUM);

    addValue("square", SQUARE, ENUM);
    addValue("circle", CIRCLE, ENUM);
    addValue("disc", DISC, ENUM);
    addValue("decimal", DECIMAL, ENUM);

    addValue("dotted", DOTTED, ENUM);
    addValue("dashed", DASHED, ENUM);
    addValue("solid", SOLID, ENUM);
    addValue("double", DOUBLE, ENUM);
    addValue("groove", GROOVE, ENUM);
    addValue("rdige", RIDGE, ENUM);
    addValue("inset", INSET, ENUM);
    addValue("outset", OUTSET, ENUM);

    addValue("left", LEFT, ENUM);
    addValue("right", RIGHT, ENUM);

    addValue("transparent", 0, ARGB);   
    addValue("maroon"0xff800000, ARGB);
    addValue("red", 0x0ffff0000, ARGB);
    addValue("orange", 0xffffA500, ARGB);
    addValue("yellow", 0xffffff00, ARGB);
    addValue("olive", 0xff808000, ARGB);
    addValue("purple", 0xff800080, ARGB);
    addValue("fuchsia", 0xffff00ff, ARGB);
    addValue("white", 0xffffffff, ARGB);
    addValue("lime", 0xff00ff00, ARGB);
    addValue("green", 0xff008000, ARGB);
    addValue("navy", 0xff000080, ARGB);
    addValue("blue", 0xff0000ff, ARGB);
    addValue("aqua", 0xff00ffff, ARGB);
    addValue("teal", 0xff008080, ARGB);
    addValue("black", 0xff000000, ARGB);
    addValue("silver", 0xffc0c0c0, ARGB);
    addValue("gray", 0xff808080, ARGB);
   
  }

  private static void addName(String name, int id) {
    Integer i = new Integer(id);
    NAME_TO_ID_MAP.put(name, i);
    ID_TO_NAME_MAP.put(i, name);
  }

  private static void addValue(String value, int id, byte unit) {
    VALUE_TO_ID_MAP.put(value, new Long(
        (((long) unit) << 32) | (id & 0x0ffffffffL)));
    if (unit == ENUM) {
      ID_TO_VALUE_MAP.put(new Integer(id), value);
    }
  }

  /**
   * Creates a style object with the color propery black, normal font weight and
   * display type "inline"; all other values are 0.
   */
  public Style() {
  }

  /**
   * Inherit values from the given style. Needs to be called before a style can
   * be used in order to get rid of INHERIT values.
   *
   * @param from the style to inherit from
   */
  public void inherit(Style from) {
    if (from == null) {
      from = EMPTY_STYLE;
    }

    int max = Math.max(lastSet, from.lastSet);

    for (int id = Math.min(firstSet, from.firstSet); id <= max; id++) {
      boolean set = isSet(id);
      if ((set && values[id] == INHERIT && units[id] == ENUM) ||
          (!set && id < TEXT_PROPERTY_COUNT && id != BACKGROUND_COLOR &&
              id != DISPLAY && from.isSet(id))) {
        set(id, from.values[id], from.units[id]);
      }
    }
  }

  /**
   * Copies all style information set in from to this
   *
   * @param from the style to copy from
   */
  public void set(Style from) {
    if (from == null) {
      return;
    }
    for (int id = from.firstSet; id <= from.lastSet; id++) {
      if (from.isSet(id)) {
        set(id, from.values[id], from.units[id]);
      }
    }
    if (from.backgroundImage != null) {
      backgroundImage = from.backgroundImage;
    }
  }

  /**
   * Returns true if the given property is set to a value
   */
  public boolean isSet(int id) {
    return (valuesSet & (1L << id)) != 0;
  }

  /**
   * Set the given property to the given value and unit.
   *
   * @param id CSS property id constant
   * @param value the value to set (multiply lengths with 1000)
   * @param unit the unit (NUMBER, PERCENT, CM, EM, EX, IN, MM, PC, PT, PX,
   *            ARGB)
   * @return this style
   */
  public Style set(int id, int value, byte unit) {
    if (id != UNRECOGNIZED_PROPERTY_ID) {
      if (id >= values.length) {
        int[] newValues = new int[PROPERTY_COUNT];
        byte[] newUnits = new byte[PROPERTY_COUNT];
        System.arraycopy(values, 0, newValues, 0, values.length);
        System.arraycopy(units, 0, newUnits, 0, units.length);
        values = newValues;
        units = newUnits;
      }

      values[id] = value;
      units[id] = unit;
      valuesSet |= 1L << id;
      firstSet = Math.min(firstSet, id);
      lastSet = Math.max(lastSet, id);
    }
    return this;
  }

  /**
   * Internal version of set that takes the value position into account
   * for multi value properties (border, font, margin etc.)
   *
   * @param id property id
   * @param value property value
   * @param unit unit constant
   * @param pos poition of this value
   * @return this
   */
  public Style set(int id, int value, byte unit, int pos) {
    if ((id & MULTIVALUE_BORDER) != 0) {
      id -= MULTIVALUE_BORDER;
      switch (unit) {
        case ARGB:
          id += BORDER_TOP_COLOR;
          break;

        case ENUM:
          switch(value) {
            case MEDIUM:
            case THIN:
            case THICK:
              id += BORDER_TOP_WIDTH;
              break;
            default:
              id += BORDER_TOP_STYLE;
          }
          break;

        default:
          id += BORDER_TOP_WIDTH;
      }
      set(id, value, unit, 0);
    } else if ((id & MULTIVALUE_TRBL) != 0) {
      id -= MULTIVALUE_TRBL;
      switch (pos) {
        case 0:
          set(id, value, unit);
          set(id + 1, value, unit);
          set(id + 2, value, unit);
          set(id + 3, value, unit);
          break;
        case 1:
          set(id + 1, value, unit);
          set(id + 3, value, unit);
          break;
        case 2:
          set(id + 2, value, unit);
          break;
        case 3:
          set(id + 3, value, unit);
          break;
      }
    } else {
      switch (id) {
        case MULTIVALUE_FONT:
          if (unit == NUMBER) {
            set(FONT_WEIGHT, value, unit);
          }
          break;
        case MULTIVALUE_BACKGROUND:
          if (unit == ENUM && value == INHERIT && pos == 0) {
            set(BACKGROUND_COLOR, INHERIT, ENUM);
            set(BACKGROUND_REPEAT, INHERIT, ENUM);
            set(BACKGROUND_POSITION_X, INHERIT, ENUM);
            set(BACKGROUND_POSITION_Y, INHERIT, ENUM);
          } else if (unit == ARGB) {
            set(BACKGROUND_COLOR, value, ARGB);
          } else if (unit == ENUM && (value == NO_REPEAT || value == REPEAT ||
              value == REPEAT_X || value == REPEAT_Y)) {
            set(BACKGROUND_REPEAT, value, ENUM);
          } else if (unit == ENUM && (value == SCROLL || value == FIXED)){
            // ignore attachment
          } else if (!isSet(BACKGROUND_POSITION_X)) {
            set(BACKGROUND_POSITION_X, value, unit);
            set(BACKGROUND_POSITION_Y, value, unit);
          } else {
            set(BACKGROUND_POSITION_Y, value, unit);
          }       
          break;
        case MULTIVALUE_BACKGROUND_POSITION:
          if (pos == 0) {
            set(BACKGROUND_POSITION_X, value, unit);
          }
          if (pos == 0 || pos == 1) {
            set(BACKGROUND_POSITION_Y, value, unit);
          }
          break;
        case MULTIVALUE_LIST_STYLE:
          if (pos == 0 && unit == ENUM && value == INHERIT) {
            set(LIST_STYLE_POSITION, INHERIT, ENUM);
            set(LIST_STYLE_TYPE, INHERIT, ENUM);
          } else if (unit == ENUM && (value == INSIDE || value == OUTSIDE)) {
            set(LIST_STYLE_POSITION, value, ENUM);
          } else {
            set(LIST_STYLE_TYPE, value, unit);
          }
          break;

        default:
          set(id, value, unit);
      }
    }
    return this;
  }

  /**
   * Determines whether a length should be calculated automatically.
   *
   * @param id property id
   * @param baseAvailable set to true if the corresponding container dimension
   *        is available, false otherwise
   * @return true if the property should be calculated instead of calling
   *         getPx().
   */
  public boolean lengthIsFixed(int id, boolean baseAvailable) {
    switch(getUnit(id)) {
      case PERCENT:
        return baseAvailable;
      case NUMBER:
      case CM:
      case EM:
      case EX:
      case IN:
      case MM:
      case PC:
      case PT:
      case PX:
        return true;
    }
    return false;
  }

  /**
   * Returns the pixel value as a rounded integer, i.e. not in the internal
   * fixpoint format. Other units are converted to pixel automatically. Percent
   * values are converted to 0. For properties permitting percent values, please
   * use getPx(int id, int base).
   */
  public int getPx(int id) {

    if (id >= BORDER_TOP_WIDTH && id <= BORDER_LEFT_WIDTH) {
      if (getValue(id - BORDER_TOP_WIDTH + BORDER_TOP_STYLE) == 0) {
        return 0;
      }

      if (getUnit(id) == ENUM){
        switch(getValue(id)) {
          case THIN:
            return 1;
          case THICK:
            return 3;
          default:
            return 2;
        }
      }
    }

    int v = getValue(id);
    // none, 0


    if (v < 0) {
      switch(id) {
        case BORDER_TOP_WIDTH:
        case BORDER_RIGHT_WIDTH:
        case BORDER_BOTTOM_WIDTH:
        case BORDER_LEFT_WIDTH:
          return 0;
      }
    }

    if (v == 0) {
      return 0;
    }

    switch (getUnit(id)) {
      case PX:
        return v / 1000;
      case EM:
        // TODO(haustein) get real size out of googlefont?
        return v * getFont().getHeight() / 1000;
      case EX:
        return v * getFont().getHeight() / 2000;
      case IN:
        return (v * DPI) / 1000;
      case CM:
        return (v * DPI * 100 / 254) / 1000;
      case MM:
        return (v * DPI * 10 / 254) / 1000;
      case PT:
        return (v * DPI / 72) / 1000;
      case PC:
        return (v * DPI / 6) / 1000;
      default:
        return 0;
    }
  }

  /**
   * Returns the value of the property if it is an ENUM, INVALID otherwise.
   *
   * @param id the property id
   * @return the value if getUnit() returns ENUM, INVALID otherwise
   */
  public int getEnum(int id) {
    return getUnit(id) == ENUM ? getValue(id) : INVALID;
  }

  /**
   *
   *
   * @param id
   * @param containerLength
   * @param imageLength
   * @return
   */
  public int getBackgroundReferencePoint(int id, int containerLength,
      int imageLength) {
    int percent = 0;
    switch(getUnit(id)) {
      case ENUM:
        switch(getValue(id)) {
          case TOP:
          case LEFT:
            return 0;
          case CENTER:
            percent = 50;
            break;
          case RIGHT:
          case BOTTOM:
            percent = 100;
            break;
          default:
            return 0;
        }
        break;
      case PERCENT:
        percent = getValue(id) / 1000;
        break;
      default:
        return getPx(id);
    }
    return (containerLength - imageLength) * percent / 100;   
  }

  /**
   * Returns the pixel value as a rounded integer, i.e. not in the internal
   * fixpoint format. Other units are converted to pixel automatically. Percent
   * values are multiplied with the base value. Note: Automatic margins 
   * are implemented by shifting the child component to the right in order to
   * keep the implementation of getPx() and BlockWidget.preDraw() simple.
   */
  public int getPx(int id, int base) {
    return isSet(id) && units[id] == PERCENT
    ? base * values[id] / 100000 : getPx(id);
  }

  /**
   * Returns the raw integer value for the given property value. For lengths,
   * please use getPx() to obtain a pixel integer value. Lengths are stored
   * internally multiplied by 1000. This method does all the default handling
   * (that is not handled in the default style sheet).
   *
   * @param id property id
   * @return raw propery value
   */
  public int getValue(int id) {
    //    if (id >= units.length || (units[id] == PERCENT && id == HEIGHT)) {
    //      return id == WIDTH || id == HEIGHT ? AUTO : 0;
    //    }
    if (isSet(id)) {
      if (id == HEIGHT && units[id] == PERCENT) {
        return AUTO;
      }
      return values[id];
    }
    switch(id) {
      case BORDER_TOP_WIDTH:
      case BORDER_BOTTOM_WIDTH:
      case BORDER_LEFT_WIDTH:
      case BORDER_RIGHT_WIDTH:
        return MEDIUM;
      case BOTTOM:
      case HEIGHT:
      case LEFT:
      case RIGHT:
      case TABLE_LAYOUT:
      case TOP:
      case WIDTH:
        return AUTO;
      case COLOR:
        return 0x0ff000000;
      case DISPLAY:
        return INLINE;
      case FONT_WEIGHT:
        return 400000;
      case LIST_STYLE_TYPE:
        return DISC;
      case POSITION:
        return STATIC;
      case BACKGROUND_REPEAT:
      return REPEAT;
    }
    return 0;
  }

  /**
   * Returns the unit for the given property.
   *
   * @param id
   * @return One of the lenght unit constants (PX etc), PERCENT, NUMBER or ENUM.
   */
  public int getUnit(int id) {
    if (isSet(id)) {
      return units[id];
    }

    switch(id) {
      case BACKGROUND_POSITION_X:
      case BACKGROUND_POSITION_Y:
        return PERCENT;
      case BACKGROUND_COLOR:
      case COLOR:
        return ARGB;
      case FONT_WEIGHT:
        return NUMBER;
    }

    // Note: ENUM is fine for number types since 0 is returned for getPx()
    return ENUM;
  }

  /**
   * Returns the font for the given style.
   */
  public Font getFont() {
    if (font == null) {
      if (FONT_CACHE == null) {
        FONT_CACHE = new Font[]{
            Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL),
            Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL),
            Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_UNDERLINED, Font.SIZE_SMALL),
            Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD | Font.STYLE_UNDERLINED,
                Font.SIZE_SMALL)};
      }
      int id = (getValue(FONT_WEIGHT) > (NORMAL + BOLD) / 2 ? 1 : 0)
      | (getEnum(TEXT_DECORATION) == UNDERLINE ? 2 : 0);

      font = FONT_CACHE[id];
    }
    return font;
  }

  /**
   * Returns the char widths for the first 128 characters of the font
   * associated wit this style. The actual number of characters may change,
   * please use the length of the returned array to determine the number of
   * widths available.
   */
  public int[] getCharWidths() {
    int id = (getValue(FONT_WEIGHT) > (NORMAL + BOLD) / 2 ? 1 : 0)
    | (getEnum(TEXT_DECORATION) == UNDERLINE ? 2 : 0);

    int[] widths = (int[]) CHAR_WIDTHS[id];
    if (widths == null) {
      widths = new int[CHAR_WIDTH_CACHE_SIZE];
      for (int i = 0; i < CHAR_WIDTH_CACHE_SIZE; i++) {
        widths[i] = getFont().charWidth((char) i);
      }
      CHAR_WIDTHS[id] = widths;
    }
    return widths;
  }

  /**
   * Reads a style declaration from a string.
   */
  public void read(HtmlWidget htmlWidget, String def) {
    CssTokenizer ct =
      new CssTokenizer(htmlWidget, htmlWidget.getBaseURL(), def);
    read(ct);
  }

  /**
   * Reads a style declaration from a CSS tokenizer.
   */
  void read(CssTokenizer tokenizer) {

    while (tokenizer.ttype != CssTokenizer.TT_EOF && tokenizer.ttype != '}') {
      if (tokenizer.ttype == CssTokenizer.TT_IDENT) {
        String name = tokenizer.sval;
        Integer idObj = (Integer) NAME_TO_ID_MAP.get(name);
        int id;
        if (idObj == null) {
          tokenizer.debug("unrecognized property");
          id = UNRECOGNIZED_PROPERTY_ID;
        } else {
          id = idObj.intValue();
        }
        tokenizer.nextToken(false);
        if (tokenizer.ttype != ':') {
          continue;
        }
        tokenizer.nextToken(false);

        int pos = 0;
        loop : while (true) {

          switch (tokenizer.ttype) {
            case CssTokenizer.TT_HASH:
              setColor(id, '#' + tokenizer.sval, pos);
              break;

            case CssTokenizer.TT_DIMENSION:
              set(id, tokenizer.nval,
                  (byte) Util.indexOf(UNIT_NAMES, tokenizer.sval.toLowerCase()), pos);
              break;

            case CssTokenizer.TT_NUMBER:
              set(id, tokenizer.nval, NUMBER, pos);
              break;

            case CssTokenizer.TT_PERCENTAGE:
              set(id, tokenizer.nval, PERCENT, pos);
              break;

            case CssTokenizer.TT_IDENT:
              Long v = (Long) VALUE_TO_ID_MAP.get(tokenizer.sval);
              if (v != null) {
                set(id, (int) v.longValue(),
                    (byte) (v.longValue() >>> 32), pos);
              } else if (id != UNRECOGNIZED_PROPERTY_ID && id != MULTIVALUE_FONT) {
                tokenizer.debug("Unrecognized value '" + v + "' for property " + name);
              }
              break;

            case CssTokenizer.TT_URI:
              if (id == MULTIVALUE_BACKGROUND || "background-image".equals(name)) {
                backgroundImage = new Image[1];
                Image bg = (Image) tokenizer.htmlWidget.getResource(tokenizer.sval,
                    SystemRequestHandler.TYPE_IMAGE, backgroundImage);
                // null check necessary to avoid overwriting image inserted in a separate thread!
                if (bg != null) {
                  backgroundImage[0] = bg;
                }
              }
              break;

            case ',':
            case CssTokenizer.TT_STRING:             
              // ignore for now...
              break;

            default:
              break loop;
          }
          pos++;
          tokenizer.nextToken(false);
        }
      }

      // handle !important
      if (tokenizer.ttype == '!') {
        tokenizer.nextToken(false);
        if (tokenizer.ttype == CssTokenizer.TT_IDENT &&
            "important".equals(tokenizer.sval)) {
          specificity = StyleSheet.SPECIFICITY_IMPORTANT;
          tokenizer.nextToken(false);
        }
      }

      // skip trailing trash
      while (tokenizer.ttype != CssTokenizer.TT_EOF
          && tokenizer.ttype != ';' && tokenizer.ttype != '}') {
        tokenizer.debug("skipping");
        tokenizer.nextToken(false);
      }
      while (tokenizer.ttype == ';') {
        tokenizer.nextToken(false);
      }
    }
  }

  /**
   * Set a CSS color value.
   *
   * @param id field id (COLOR, ...)
   * @param color the color in the form #RGB or #RRGGBB or one of the 16 CSS
   *              color identifiers
   * @param pos index of the border-color value (0..3); 0 otherwise
   */
  public void setColor(int id, String color, int pos) {
    if (color.length() > 0 && color.charAt(0) == '#') {
      try {
        // #RGB or #RRGGBB hexadecimal color value
        int value = Integer.parseInt(color.substring(1), 16);
        if (color.length() == 4) {
          value = (value & 0x00f) | ((value & 0x0ff) << 4)
          | ((value & 0xff0) << 8) | ((value & 0xf00) << 12);
        }
        // set with transparency opaque
        set(id, 0x0ff000000 | value, ARGB, pos);
      } catch (NumberFormatException e) {
        // ignore invalid colors
      }
    } else {
      Long v = (Long) VALUE_TO_ID_MAP.get(color.toLowerCase());
      if (v != null) {
        long l = v.longValue();
        if ((l >>> 32) == ARGB) {
          set(id, (int) l, ARGB, pos);
        }
      }
    }
  }

  /**
   * Dumps this style sheet to stdout for debugging purposes.
   */
  public void dump(String indent) {
    for (int id = 0; id < PROPERTY_COUNT; id++) {
      if (isSet(id)) {
        System.out.print(indent + ID_TO_NAME_MAP.get(new Integer(id)) + ": ");
        int v = values[id];

        byte unit = units[id];
        switch (units[id]) {
          case ARGB:
            System.out.print("#"
                + Integer.toString((v & 0x0ffffff) | 0x01000000, 16).substring(
                    1));
            break;
          case ENUM:
            System.out.print("" + ID_TO_VALUE_MAP.get(new Integer(v)));
            break;
          default:
            StringBuffer buf;
            if (v % 1000 == 0) {
              System.out.print(v / 1000);
            } else {
              buf = new StringBuffer(Integer.toString(v));
              while (buf.length() < 4) {
                buf.insert(0, '0');
              }
              buf.insert(buf.length() - 3, '.');
              System.out.print(buf.toString());
            }
            if (unit >= 0 && unit < UNIT_NAMES.length) {
              System.out.print(UNIT_NAMES[unit]);
            }
        }
        System.out.println("; ");
      }
    }
    if (backgroundImage != null && backgroundImage[0] != null) {
      System.out.println(indent + "background-image: [w:" + backgroundImage[0].getWidth() +
          " h:" + backgroundImage[0].getHeight() + "]");
    }
    System.out.println("/* specifity: " + specificity + " */");
  }

  /**
   * Compares the specificity of this style to s2 and returns the difference.
   */
  public int compare(Style s2) {

    if (specificity > s2.specificity) {
      return 1;
    } else if (specificity < s2.specificity) {
      return -1;
    } else {
      int min = Math.min(nesting.length, s2.nesting.length);
      for (int i = 0; i < min; i++) {
        if (nesting[i] > s2.nesting[i]) {
          return 1;
        } else if (nesting[i] < s2.nesting[i]) {
          return -1;
        }
      }

      int n1 = min + 1 < nesting.length ? nesting[min + 1] : position;
      int n2 = min + 1 < s2.nesting.length ? s2.nesting[min + 1] : s2.position;

      return n1 - n2;
    }
  }

  /**
   * Returns true if this is a (inline)block style.
   *
   * @param full if false, true is returned for inline blocks, too.
   */
  public boolean isBlock(boolean full) {
    int display = getEnum(DISPLAY);
    if (display == BLOCK || display == TABLE || display == LIST_ITEM) {
      return true;
    }
    if (full) {
      return false;
    }
    return backgroundImage != null || getEnum(DISPLAY) != INLINE  ||
    getPx(BORDER_BOTTOM_WIDTH) != 0 || getPx(BORDER_LEFT_WIDTH) != 0 ||
    getPx(BORDER_RIGHT_WIDTH) != 0 || getPx(BORDER_TOP_WIDTH) != 0 ||
    getEnum(POSITION) == ABSOLUTE ||
    lengthIsFixed(Style.HEIGHT, true) || lengthIsFixed(Style.WIDTH, true)
    ;
  }
}
TOP

Related Classes of com.google.minijoe.html.css.Style

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.