• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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      */
Element(String name, int type, boolean empty, boolean optionalEndTag, boolean breaksFlow, Flow flow)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      */
Element(String name, int type, boolean empty, boolean optionalEndTag, boolean breaksFlow)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" */
getName()88     public String getName() {
89       return name;
90     }
91 
92     /** Type, e.g. TABLE_TYPE */
getType()93     public int getType() {
94       return type;
95     }
96 
97     /** True if it's empty, has no inner elements or end tag */
isEmpty()98     public boolean isEmpty() {
99       return empty;
100     }
101 
102     /** True if the end tag is optional */
isEndTagOptional()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      */
breaksFlow()111     public boolean breaksFlow() {
112       return breaksFlow;
113     }
114 
115     /** Flow type. */
getFlow()116     public Flow getFlow() {
117       return flow;
118     }
119 
120     /**
121      * @return just name, not proper HTML
122      */
123     @Override
toString()124     public String toString() {
125       return name;
126     }
127 
128     @Override
equals(Object o)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
hashCode()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      */
Attribute(String name, int type)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      */
Attribute(String name, int type, Set<String> values)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 */
getName()189     public String getName() {
190       return name;
191     }
192 
193     /** Gets the type, e.g. URI_TYPE */
getType()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      */
getEnumValues()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
toString()216     public String toString() {
217       return name;
218     }
219 
220     @Override
equals(Object o)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
hashCode()233     public int hashCode() {
234       return this.name.hashCode();
235     }
236   }
237 }