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