Home | History | Annotate | Download | only in parser
      1 /**
      2  * Copyright (c) 2004, Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.android.mail.common.html.parser;
     18 
     19 import com.google.android.mail.common.base.Preconditions;
     20 
     21 import java.util.Set;
     22 
     23 /**
     24  * HTML class defines Element and Attribute classes.
     25  *
     26  * @author jlim (at) google.com (Jing Yee Lim)
     27  */
     28 public final class HTML {
     29 
     30   /**
     31    * Html element
     32    */
     33   public static final class Element {
     34 
     35     // TODO(ptucker) other candidate types are list and form elements. Better for this to be
     36     // enumerated type.
     37     /** Types */
     38     public static final int NO_TYPE = 0;
     39     public static final int TABLE_TYPE = 1;
     40 
     41     /**
     42      * INLINE - charater level elements and text strings
     43      * BLOCK  - block-like elements; e.g., paragraphs and lists
     44      * NONE   - everything else
     45      */
     46     public enum Flow {
     47       INLINE,
     48       BLOCK,
     49       NONE
     50     }
     51 
     52     private final String name;
     53     private final int type;
     54     private final boolean empty;
     55     private final boolean optionalEndTag;
     56     private final boolean breaksFlow;
     57     private final Flow flow;
     58 
     59     /**
     60      * Construct an Element.
     61      *
     62      * NOTE: Even though breaksFlow and flow are named similarly, they're not quite the same thing.
     63      * Flow refers to whether the element is inherently character or block level. Breaks flow
     64      * refers to whether it forces a line break.
     65      *
     66      * @throws IllegalArgumentException if name or flow is null.
     67      */
     68     public Element(String name, int type, boolean empty,
     69                    boolean optionalEndTag, boolean breaksFlow, Flow flow) {
     70       Preconditions.checkNotNull(name, "Element name can not be null");
     71       Preconditions.checkNotNull(flow, "Element flow can not be null");
     72       this.name = name;
     73       this.type = type;
     74       this.empty = empty;
     75       this.optionalEndTag = optionalEndTag;
     76       this.breaksFlow = breaksFlow;
     77       this.flow = flow;
     78     }
     79 
     80     /**
     81      * Construct an Element with inline=true.
     82      */
     83     public Element(String name, int type, boolean empty,
     84                    boolean optionalEndTag, boolean breaksFlow) {
     85       this(name, type, empty, optionalEndTag, breaksFlow, Flow.NONE);
     86     }
     87 
     88     /** Name of the element, in lowercase, e.g. "a", "br" */
     89     public String getName() {
     90       return name;
     91     }
     92 
     93     /** Type, e.g. TABLE_TYPE */
     94     public int getType() {
     95       return type;
     96     }
     97 
     98     /** True if it's empty, has no inner elements or end tag */
     99     public boolean isEmpty() {
    100       return empty;
    101     }
    102 
    103     /** True if the end tag is optional */
    104     public boolean isEndTagOptional() {
    105       return optionalEndTag;
    106     }
    107 
    108     /**
    109      * True if it breaks the flow, and may force a new line before/after the
    110      * tag.
    111      */
    112     public boolean breaksFlow() {
    113       return breaksFlow;
    114     }
    115 
    116     /** Flow type. */
    117     public Flow getFlow() {
    118       return flow;
    119     }
    120 
    121     /**
    122      * @return just name, not proper HTML
    123      */
    124     @Override
    125     public String toString() {
    126       return name;
    127     }
    128 
    129     @Override
    130     public boolean equals(Object o) {
    131       if (o == this) {
    132         return true;
    133       }
    134       if (o instanceof HTML.Element) {
    135         HTML.Element that = (HTML.Element) o;
    136         return this.name.equals(that.name);
    137       }
    138       return false;
    139     }
    140 
    141     @Override
    142     public int hashCode() {
    143       return this.name.hashCode();
    144     }
    145   }
    146 
    147   /**
    148    * Html attribute
    149    */
    150   public static final class Attribute {
    151     /** Value types */
    152     public static final int NO_TYPE = 0;
    153     public static final int URI_TYPE = 1;
    154     public static final int SCRIPT_TYPE = 2;
    155     public static final int ENUM_TYPE = 3;
    156     public static final int BOOLEAN_TYPE = 4;
    157 
    158     /** Name of the element, e.g. "HREF" */
    159     private final String name;
    160 
    161     /** Type of the attribute value, e.g. URI_TYPE */
    162     private final int type;
    163 
    164     /** The list of allowed values, or null if any value is allowed */
    165     private final Set<String> values;
    166 
    167     /**
    168      * Construct an Attribute
    169      * @throws IllegalArgumentException if name is null
    170      */
    171     public Attribute(String name, int type) {
    172       this(name, type, null);
    173     }
    174 
    175     /**
    176      * Construct an Attribute
    177      * @throws IllegalArgumentException if name is null
    178      * or if Attribute is of type ENUM_TYPE and the values are null
    179      */
    180     public Attribute(String name, int type, Set<String> values) {
    181       Preconditions.checkNotNull(name, "Attribute name can not be null");
    182       Preconditions.checkArgument((values == null) ^ (type == ENUM_TYPE),
    183           "Only ENUM_TYPE can have values != null");
    184       this.name = name;
    185       this.type = type;
    186       this.values = values;
    187     }
    188 
    189     /** Gets the name of the attribute, in lowercase */
    190     public String getName() {
    191       return name;
    192     }
    193 
    194     /** Gets the type, e.g. URI_TYPE */
    195     public int getType() {
    196       return type;
    197     }
    198 
    199     /**
    200      * When called on an attribute of ENUM_TYPE, returns a Set of Strings
    201      * containing the allowed attribute values. The return set is guaranteed to
    202      * only contain lower case Strings.
    203      *
    204      * @return a Set of Strings, in lower case, for the allowed attribute
    205      *         values.
    206      * @throws IllegalStateException if attribute type is not ENUM_TYPE
    207      */
    208     public Set<String> getEnumValues() {
    209       Preconditions.checkState(type == ENUM_TYPE);
    210       return values;
    211     }
    212 
    213     /**
    214      * @return Element name (name only, not proper HTML).
    215      */
    216     @Override
    217     public String toString() {
    218       return name;
    219     }
    220 
    221     @Override
    222     public boolean equals(Object o) {
    223       if (o == this) {
    224         return true;
    225       }
    226       if (o instanceof HTML.Attribute) {
    227         HTML.Attribute that = (HTML.Attribute) o;
    228         return this.name.equals(that.name);
    229       }
    230       return false;
    231     }
    232 
    233     @Override
    234     public int hashCode() {
    235       return this.name.hashCode();
    236     }
    237   }
    238 }