src/share/classes/com/sun/tools/doclint/HtmlTag.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
equal deleted inserted replaced
-1:000000000000 0:959103a6100f
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.doclint;
27
28 import java.util.Set;
29 import java.util.Collections;
30 import java.util.EnumMap;
31 import java.util.EnumSet;
32 import java.util.HashMap;
33 import java.util.Locale;
34 import java.util.Map;
35
36 import javax.lang.model.element.Name;
37
38 import static com.sun.tools.doclint.HtmlTag.Attr.*;
39 import com.sun.tools.javac.util.StringUtils;
40
41 /**
42 * Enum representing HTML tags.
43 *
44 * The intent of this class is to embody the semantics of W3C HTML 4.01
45 * to the extent supported/used by javadoc.
46 * In time, we may wish to transition javadoc and doclint to using HTML 5.
47 *
48 * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag.
49 * Eventually, these two should be merged back together, and possibly made
50 * public.
51 *
52 * @see <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a>
53 * @see <a href="http://www.w3.org/TR/html5/">HTML 5 Specification</a>
54 * @author Bhavesh Patel
55 * @author Jonathan Gibbons (revised)
56 */
57 public enum HtmlTag {
58 A(BlockType.INLINE, EndKind.REQUIRED,
59 attrs(AttrKind.OK, HREF, TARGET, NAME)),
60
61 B(BlockType.INLINE, EndKind.REQUIRED,
62 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
63
64 BIG(BlockType.INLINE, EndKind.REQUIRED,
65 EnumSet.of(Flag.EXPECT_CONTENT)),
66
67 BLOCKQUOTE(BlockType.BLOCK, EndKind.REQUIRED,
68 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
69
70 BODY(BlockType.OTHER, EndKind.REQUIRED),
71
72 BR(BlockType.INLINE, EndKind.NONE,
73 attrs(AttrKind.USE_CSS, CLEAR)),
74
75 CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED,
76 EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
77
78 CENTER(BlockType.BLOCK, EndKind.REQUIRED,
79 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
80
81 CITE(BlockType.INLINE, EndKind.REQUIRED,
82 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
83
84 CODE(BlockType.INLINE, EndKind.REQUIRED,
85 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
86
87 DD(BlockType.LIST_ITEM, EndKind.OPTIONAL,
88 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
89
90 DFN(BlockType.INLINE, EndKind.REQUIRED,
91 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
92
93 DIV(BlockType.BLOCK, EndKind.REQUIRED,
94 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
95
96 DL(BlockType.BLOCK, EndKind.REQUIRED,
97 EnumSet.of(Flag.EXPECT_CONTENT),
98 attrs(AttrKind.USE_CSS, COMPACT)) {
99 @Override
100 public boolean accepts(HtmlTag t) {
101 return (t == DT) || (t == DD);
102 }
103 },
104
105 DT(BlockType.LIST_ITEM, EndKind.OPTIONAL,
106 EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
107
108 EM(BlockType.INLINE, EndKind.REQUIRED,
109 EnumSet.of(Flag.NO_NEST)),
110
111 FONT(BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated
112 EnumSet.of(Flag.EXPECT_CONTENT),
113 attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)),
114
115 FRAME(BlockType.OTHER, EndKind.NONE),
116
117 FRAMESET(BlockType.OTHER, EndKind.REQUIRED),
118
119 H1(BlockType.BLOCK, EndKind.REQUIRED),
120 H2(BlockType.BLOCK, EndKind.REQUIRED),
121 H3(BlockType.BLOCK, EndKind.REQUIRED),
122 H4(BlockType.BLOCK, EndKind.REQUIRED),
123 H5(BlockType.BLOCK, EndKind.REQUIRED),
124 H6(BlockType.BLOCK, EndKind.REQUIRED),
125
126 HEAD(BlockType.OTHER, EndKind.REQUIRED),
127
128 HR(BlockType.BLOCK, EndKind.NONE,
129 attrs(AttrKind.OK, WIDTH)), // OK in 4.01; not allowed in 5
130
131 HTML(BlockType.OTHER, EndKind.REQUIRED),
132
133 I(BlockType.INLINE, EndKind.REQUIRED,
134 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
135
136 IMG(BlockType.INLINE, EndKind.NONE,
137 attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH),
138 attrs(AttrKind.OBSOLETE, NAME),
139 attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)),
140
141 LI(BlockType.LIST_ITEM, EndKind.OPTIONAL,
142 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
143 attrs(AttrKind.OK, VALUE)),
144
145 LINK(BlockType.OTHER, EndKind.NONE),
146
147 MENU(BlockType.BLOCK, EndKind.REQUIRED) {
148 @Override
149 public boolean accepts(HtmlTag t) {
150 return (t == LI);
151 }
152 },
153
154 META(BlockType.OTHER, EndKind.NONE),
155
156 NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
157
158 NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED),
159
160 OL(BlockType.BLOCK, EndKind.REQUIRED,
161 EnumSet.of(Flag.EXPECT_CONTENT),
162 attrs(AttrKind.OK, START, TYPE)) {
163 @Override
164 public boolean accepts(HtmlTag t) {
165 return (t == LI);
166 }
167 },
168
169 P(BlockType.BLOCK, EndKind.OPTIONAL,
170 EnumSet.of(Flag.EXPECT_CONTENT),
171 attrs(AttrKind.USE_CSS, ALIGN)),
172
173 PRE(BlockType.BLOCK, EndKind.REQUIRED,
174 EnumSet.of(Flag.EXPECT_CONTENT)) {
175 @Override
176 public boolean accepts(HtmlTag t) {
177 switch (t) {
178 case IMG: case BIG: case SMALL: case SUB: case SUP:
179 return false;
180 default:
181 return (t.blockType == BlockType.INLINE);
182 }
183 }
184 },
185
186 SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
187
188 SMALL(BlockType.INLINE, EndKind.REQUIRED,
189 EnumSet.of(Flag.EXPECT_CONTENT)),
190
191 SPAN(BlockType.INLINE, EndKind.REQUIRED,
192 EnumSet.of(Flag.EXPECT_CONTENT)),
193
194 STRONG(BlockType.INLINE, EndKind.REQUIRED,
195 EnumSet.of(Flag.EXPECT_CONTENT)),
196
197 SUB(BlockType.INLINE, EndKind.REQUIRED,
198 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
199
200 SUP(BlockType.INLINE, EndKind.REQUIRED,
201 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
202
203 TABLE(BlockType.BLOCK, EndKind.REQUIRED,
204 EnumSet.of(Flag.EXPECT_CONTENT),
205 attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
206 CELLPADDING, CELLSPACING, WIDTH), // width OK in 4.01; not allowed in 5
207 attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) {
208 @Override
209 public boolean accepts(HtmlTag t) {
210 switch (t) {
211 case CAPTION:
212 case THEAD: case TBODY: case TFOOT:
213 case TR: // HTML 3.2
214 return true;
215 default:
216 return false;
217 }
218 }
219 },
220
221 TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED,
222 EnumSet.of(Flag.EXPECT_CONTENT),
223 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
224 @Override
225 public boolean accepts(HtmlTag t) {
226 return (t == TR);
227 }
228 },
229
230 TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
231 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
232 attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
233 ALIGN, CHAR, CHAROFF, VALIGN),
234 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
235
236 TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED,
237 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
238 @Override
239 public boolean accepts(HtmlTag t) {
240 return (t == TR);
241 }
242 },
243
244 TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
245 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
246 attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
247 ALIGN, CHAR, CHAROFF, VALIGN),
248 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
249
250 THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED,
251 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
252 @Override
253 public boolean accepts(HtmlTag t) {
254 return (t == TR);
255 }
256 },
257
258 TITLE(BlockType.OTHER, EndKind.REQUIRED),
259
260 TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
261 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
262 attrs(AttrKind.USE_CSS, BGCOLOR)) {
263 @Override
264 public boolean accepts(HtmlTag t) {
265 return (t == TH) || (t == TD);
266 }
267 },
268
269 TT(BlockType.INLINE, EndKind.REQUIRED,
270 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
271
272 U(BlockType.INLINE, EndKind.REQUIRED,
273 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
274
275 UL(BlockType.BLOCK, EndKind.REQUIRED,
276 EnumSet.of(Flag.EXPECT_CONTENT),
277 attrs(AttrKind.OK, COMPACT, TYPE)) { // OK in 4.01; not allowed in 5
278 @Override
279 public boolean accepts(HtmlTag t) {
280 return (t == LI);
281 }
282 },
283
284 VAR(BlockType.INLINE, EndKind.REQUIRED);
285
286 /**
287 * Enum representing the type of HTML element.
288 */
289 public static enum BlockType {
290 BLOCK,
291 INLINE,
292 LIST_ITEM,
293 TABLE_ITEM,
294 OTHER;
295 }
296
297 /**
298 * Enum representing HTML end tag requirement.
299 */
300 public static enum EndKind {
301 NONE,
302 OPTIONAL,
303 REQUIRED;
304 }
305
306 public static enum Flag {
307 ACCEPTS_BLOCK,
308 ACCEPTS_INLINE,
309 EXPECT_CONTENT,
310 NO_NEST
311 }
312
313 public static enum Attr {
314 ABBR,
315 ALIGN,
316 ALT,
317 AXIS,
318 BGCOLOR,
319 BORDER,
320 CELLSPACING,
321 CELLPADDING,
322 CHAR,
323 CHAROFF,
324 CLEAR,
325 CLASS,
326 COLOR,
327 COLSPAN,
328 COMPACT,
329 FACE,
330 FRAME,
331 HEADERS,
332 HEIGHT,
333 HREF,
334 HSPACE,
335 ID,
336 NAME,
337 NOWRAP,
338 REVERSED,
339 ROWSPAN,
340 RULES,
341 SCOPE,
342 SIZE,
343 SPACE,
344 SRC,
345 START,
346 STYLE,
347 SUMMARY,
348 TARGET,
349 TYPE,
350 VALIGN,
351 VALUE,
352 VSPACE,
353 WIDTH;
354
355 public String getText() {
356 return StringUtils.toLowerCase(name());
357 }
358
359 static final Map<String,Attr> index = new HashMap<String,Attr>();
360 static {
361 for (Attr t: values()) {
362 index.put(t.getText(), t);
363 }
364 }
365 }
366
367 public static enum AttrKind {
368 INVALID,
369 OBSOLETE,
370 USE_CSS,
371 OK
372 }
373
374 // This class exists to avoid warnings from using parameterized vararg type
375 // Map<Attr,AttrKind> in signature of HtmlTag constructor.
376 private static class AttrMap extends EnumMap<Attr,AttrKind> {
377 private static final long serialVersionUID = 0;
378 AttrMap() {
379 super(Attr.class);
380 }
381 }
382
383
384 public final BlockType blockType;
385 public final EndKind endKind;
386 public final Set<Flag> flags;
387 private final Map<Attr,AttrKind> attrs;
388
389 HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
390 this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
391 }
392
393 HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
394 this.blockType = blockType;
395 this.endKind = endKind;
396 this.flags = flags;
397 this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
398 for (Map<Attr,AttrKind> m: attrMaps)
399 this.attrs.putAll(m);
400 attrs.put(Attr.CLASS, AttrKind.OK);
401 attrs.put(Attr.ID, AttrKind.OK);
402 attrs.put(Attr.STYLE, AttrKind.OK);
403 }
404
405 public boolean accepts(HtmlTag t) {
406 if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) {
407 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE);
408 } else if (flags.contains(Flag.ACCEPTS_BLOCK)) {
409 return (t.blockType == BlockType.BLOCK);
410 } else if (flags.contains(Flag.ACCEPTS_INLINE)) {
411 return (t.blockType == BlockType.INLINE);
412 } else
413 switch (blockType) {
414 case BLOCK:
415 case INLINE:
416 return (t.blockType == BlockType.INLINE);
417 case OTHER:
418 // OTHER tags are invalid in doc comments, and will be
419 // reported separately, so silently accept/ignore any content
420 return true;
421 default:
422 // any combination which could otherwise arrive here
423 // ought to have been handled in an overriding method
424 throw new AssertionError(this + ":" + t);
425 }
426 }
427
428 public boolean acceptsText() {
429 // generally, anywhere we can put text we can also put inline tag
430 // so check if a typical inline tag is allowed
431 return accepts(B);
432 }
433
434 public String getText() {
435 return StringUtils.toLowerCase(name());
436 }
437
438 public Attr getAttr(Name attrName) {
439 return Attr.index.get(StringUtils.toLowerCase(attrName.toString()));
440 }
441
442 public AttrKind getAttrKind(Name attrName) {
443 AttrKind k = attrs.get(getAttr(attrName)); // null-safe
444 return (k == null) ? AttrKind.INVALID : k;
445 }
446
447 private static AttrMap attrs(AttrKind k, Attr... attrs) {
448 AttrMap map = new AttrMap();
449 for (Attr a: attrs) map.put(a, k);
450 return map;
451 }
452
453 private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>();
454 static {
455 for (HtmlTag t: values()) {
456 index.put(t.getText(), t);
457 }
458 }
459
460 static HtmlTag get(Name tagName) {
461 return index.get(StringUtils.toLowerCase(tagName.toString()));
462 }
463
464 }

mercurial