tidy-ext 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. data/.gitignore +4 -0
  2. data/LICENSE +50 -0
  3. data/README +12 -0
  4. data/Rakefile +60 -0
  5. data/VERSION +1 -0
  6. data/ext/tidy/access.c +3310 -0
  7. data/ext/tidy/access.h +279 -0
  8. data/ext/tidy/alloc.c +107 -0
  9. data/ext/tidy/attrask.c +209 -0
  10. data/ext/tidy/attrdict.c +2398 -0
  11. data/ext/tidy/attrdict.h +122 -0
  12. data/ext/tidy/attrget.c +213 -0
  13. data/ext/tidy/attrs.c +1911 -0
  14. data/ext/tidy/attrs.h +374 -0
  15. data/ext/tidy/buffio.c +232 -0
  16. data/ext/tidy/buffio.h +118 -0
  17. data/ext/tidy/charsets.c +1032 -0
  18. data/ext/tidy/charsets.h +14 -0
  19. data/ext/tidy/clean.c +2674 -0
  20. data/ext/tidy/clean.h +87 -0
  21. data/ext/tidy/config.c +1746 -0
  22. data/ext/tidy/config.h +153 -0
  23. data/ext/tidy/entities.c +419 -0
  24. data/ext/tidy/entities.h +24 -0
  25. data/ext/tidy/extconf.rb +5 -0
  26. data/ext/tidy/fileio.c +106 -0
  27. data/ext/tidy/fileio.h +46 -0
  28. data/ext/tidy/forward.h +69 -0
  29. data/ext/tidy/iconvtc.c +105 -0
  30. data/ext/tidy/iconvtc.h +15 -0
  31. data/ext/tidy/istack.c +373 -0
  32. data/ext/tidy/lexer.c +3825 -0
  33. data/ext/tidy/lexer.h +617 -0
  34. data/ext/tidy/localize.c +1882 -0
  35. data/ext/tidy/mappedio.c +329 -0
  36. data/ext/tidy/mappedio.h +16 -0
  37. data/ext/tidy/message.h +207 -0
  38. data/ext/tidy/parser.c +4408 -0
  39. data/ext/tidy/parser.h +76 -0
  40. data/ext/tidy/platform.h +636 -0
  41. data/ext/tidy/pprint.c +2276 -0
  42. data/ext/tidy/pprint.h +93 -0
  43. data/ext/tidy/ruby-tidy.c +195 -0
  44. data/ext/tidy/streamio.c +1407 -0
  45. data/ext/tidy/streamio.h +222 -0
  46. data/ext/tidy/tagask.c +286 -0
  47. data/ext/tidy/tags.c +955 -0
  48. data/ext/tidy/tags.h +235 -0
  49. data/ext/tidy/tidy-int.h +129 -0
  50. data/ext/tidy/tidy.h +1097 -0
  51. data/ext/tidy/tidyenum.h +622 -0
  52. data/ext/tidy/tidylib.c +1751 -0
  53. data/ext/tidy/tmbstr.c +306 -0
  54. data/ext/tidy/tmbstr.h +92 -0
  55. data/ext/tidy/utf8.c +539 -0
  56. data/ext/tidy/utf8.h +52 -0
  57. data/ext/tidy/version.h +14 -0
  58. data/ext/tidy/win32tc.c +795 -0
  59. data/ext/tidy/win32tc.h +19 -0
  60. data/spec/spec_helper.rb +5 -0
  61. data/spec/tidy/compat_spec.rb +44 -0
  62. data/spec/tidy/remote_uri_spec.rb +14 -0
  63. data/spec/tidy/test1.html +5 -0
  64. data/spec/tidy/tidy_spec.rb +34 -0
  65. metadata +125 -0
data/ext/tidy/access.c ADDED
@@ -0,0 +1,3310 @@
1
+ /* access.c -- carry out accessibility checks
2
+
3
+ Copyright University of Toronto
4
+ Portions (c) 1998-2009 (W3C) MIT, ERCIM, Keio University
5
+ See tidy.h for the copyright notice.
6
+
7
+ CVS Info :
8
+
9
+ $Author: arnaud02 $
10
+ $Date: 2009/03/25 22:04:35 $
11
+ $Revision: 1.42 $
12
+
13
+ */
14
+
15
+ /*********************************************************************
16
+ * AccessibilityChecks
17
+ *
18
+ * Carries out processes for all accessibility checks. Traverses
19
+ * through all the content within the tree and evaluates the tags for
20
+ * accessibility.
21
+ *
22
+ * To perform the following checks, 'AccessibilityChecks' must be
23
+ * called AFTER the tree structure has been formed.
24
+ *
25
+ * If, in the command prompt, there is no specification of which
26
+ * accessibility priorities to check, no accessibility checks will be
27
+ * performed. (ie. '1' for priority 1, '2' for priorities 1 and 2,
28
+ * and '3') for priorities 1, 2 and 3.)
29
+ *
30
+ * Copyright University of Toronto
31
+ * Programmed by: Mike Lam and Chris Ridpath
32
+ * Modifications by : Terry Teague (TRT)
33
+ *
34
+ * Reference document: http://www.w3.org/TR/WAI-WEBCONTENT/
35
+ *********************************************************************/
36
+
37
+
38
+ #include "tidy-int.h"
39
+
40
+ #if SUPPORT_ACCESSIBILITY_CHECKS
41
+
42
+ #include "access.h"
43
+ #include "message.h"
44
+ #include "tags.h"
45
+ #include "attrs.h"
46
+ #include "tmbstr.h"
47
+
48
+
49
+ /*
50
+ The accessibility checks to perform depending on user's desire.
51
+
52
+ 1. priority 1
53
+ 2. priority 1 & 2
54
+ 3. priority 1, 2, & 3
55
+ */
56
+
57
+ /* List of possible image types */
58
+ static const ctmbstr imageExtensions[] =
59
+ {".jpg", ".gif", ".tif", ".pct", ".pic", ".iff", ".dib",
60
+ ".tga", ".pcx", ".png", ".jpeg", ".tiff", ".bmp"};
61
+
62
+ #define N_IMAGE_EXTS (sizeof(imageExtensions)/sizeof(ctmbstr))
63
+
64
+ /* List of possible sound file types */
65
+ static const ctmbstr soundExtensions[] =
66
+ {".wav", ".au", ".aiff", ".snd", ".ra", ".rm"};
67
+
68
+ static const int soundExtErrCodes[] =
69
+ {
70
+ AUDIO_MISSING_TEXT_WAV,
71
+ AUDIO_MISSING_TEXT_AU,
72
+ AUDIO_MISSING_TEXT_AIFF,
73
+ AUDIO_MISSING_TEXT_SND,
74
+ AUDIO_MISSING_TEXT_RA,
75
+ AUDIO_MISSING_TEXT_RM
76
+ };
77
+
78
+ #define N_AUDIO_EXTS (sizeof(soundExtensions)/sizeof(ctmbstr))
79
+
80
+ /* List of possible media extensions */
81
+ static const ctmbstr mediaExtensions[] =
82
+ {".mpg", ".mov", ".asx", ".avi", ".ivf", ".m1v", ".mmm", ".mp2v",
83
+ ".mpa", ".mpe", ".mpeg", ".ram", ".smi", ".smil", ".swf",
84
+ ".wm", ".wma", ".wmv"};
85
+
86
+ #define N_MEDIA_EXTS (sizeof(mediaExtensions)/sizeof(ctmbstr))
87
+
88
+ /* List of possible frame sources */
89
+ static const ctmbstr frameExtensions[] =
90
+ {".htm", ".html", ".shtm", ".shtml", ".cfm", ".cfml",
91
+ ".asp", ".cgi", ".pl", ".smil"};
92
+
93
+ #define N_FRAME_EXTS (sizeof(frameExtensions)/sizeof(ctmbstr))
94
+
95
+ /* List of possible colour values */
96
+ static const int colorValues[][3] =
97
+ {
98
+ { 0, 0, 0},
99
+ {128,128,128},
100
+ {192,192,192},
101
+ {255,255,255},
102
+ {192, 0, 0},
103
+ {255, 0, 0},
104
+ {128, 0,128},
105
+ {255, 0,255},
106
+ { 0,128, 0},
107
+ { 0,255, 0},
108
+ {128,128, 0},
109
+ {255,255, 0},
110
+ { 0, 0,128},
111
+ { 0, 0,255},
112
+ { 0,128,128},
113
+ { 0,255,255}
114
+ };
115
+
116
+ #define N_COLOR_VALS (sizeof(colorValues)/(sizeof(int[3]))
117
+
118
+ /* These arrays are used to convert color names to their RGB values */
119
+ static const ctmbstr colorNames[] =
120
+ {
121
+ "black",
122
+ "silver",
123
+ "grey",
124
+ "white",
125
+ "maroon",
126
+ "red",
127
+ "purple",
128
+ "fuchsia",
129
+ "green",
130
+ "lime",
131
+ "olive",
132
+ "yellow",
133
+ "navy",
134
+ "blue",
135
+ "teal",
136
+ "aqua"
137
+ };
138
+
139
+ #define N_COLOR_NAMES (sizeof(colorNames)/sizeof(ctmbstr))
140
+ #define N_COLORS N_COLOR_NAMES
141
+
142
+
143
+ /* function prototypes */
144
+ static void InitAccessibilityChecks( TidyDocImpl* doc, int level123 );
145
+ static void FreeAccessibilityChecks( TidyDocImpl* doc );
146
+
147
+ static Bool GetRgb( ctmbstr color, int rgb[3] );
148
+ static Bool CompareColors( const int rgbBG[3], const int rgbFG[3] );
149
+ static int ctox( tmbchar ch );
150
+
151
+ /*
152
+ static void CheckMapAccess( TidyDocImpl* doc, Node* node, Node* front);
153
+ static void GetMapLinks( TidyDocImpl* doc, Node* node, Node* front);
154
+ static void CompareAnchorLinks( TidyDocImpl* doc, Node* front, int counter);
155
+ static void FindMissingLinks( TidyDocImpl* doc, Node* node, int counter);
156
+ */
157
+ static void CheckFormControls( TidyDocImpl* doc, Node* node );
158
+ static void MetaDataPresent( TidyDocImpl* doc, Node* node );
159
+ static void CheckEmbed( TidyDocImpl* doc, Node* node );
160
+ static void CheckListUsage( TidyDocImpl* doc, Node* node );
161
+
162
+ /*
163
+ GetFileExtension takes a path and returns the extension
164
+ portion of the path (if any).
165
+ */
166
+
167
+ static void GetFileExtension( ctmbstr path, tmbchar *ext, uint maxExt )
168
+ {
169
+ int i = TY_(tmbstrlen)(path) - 1;
170
+
171
+ ext[0] = '\0';
172
+
173
+ do {
174
+ if ( path[i] == '/' || path[i] == '\\' )
175
+ break;
176
+ else if ( path[i] == '.' )
177
+ {
178
+ TY_(tmbstrncpy)( ext, path+i, maxExt );
179
+ break;
180
+ }
181
+ } while ( --i > 0 );
182
+ }
183
+
184
+ /************************************************************************
185
+ * IsImage
186
+ *
187
+ * Checks if the given filename is an image file.
188
+ * Returns 'yes' if it is, 'no' if it's not.
189
+ ************************************************************************/
190
+
191
+ static Bool IsImage( ctmbstr iType )
192
+ {
193
+ uint i;
194
+
195
+ /* Get the file extension */
196
+ tmbchar ext[20];
197
+ GetFileExtension( iType, ext, sizeof(ext) );
198
+
199
+ /* Compare it to the array of known image file extensions */
200
+ for (i = 0; i < N_IMAGE_EXTS; i++)
201
+ {
202
+ if ( TY_(tmbstrcasecmp)(ext, imageExtensions[i]) == 0 )
203
+ return yes;
204
+ }
205
+
206
+ return no;
207
+ }
208
+
209
+
210
+ /***********************************************************************
211
+ * IsSoundFile
212
+ *
213
+ * Checks if the given filename is a sound file.
214
+ * Returns 'yes' if it is, 'no' if it's not.
215
+ ***********************************************************************/
216
+
217
+ static int IsSoundFile( ctmbstr sType )
218
+ {
219
+ uint i;
220
+ tmbchar ext[ 20 ];
221
+ GetFileExtension( sType, ext, sizeof(ext) );
222
+
223
+ for (i = 0; i < N_AUDIO_EXTS; i++)
224
+ {
225
+ if ( TY_(tmbstrcasecmp)(ext, soundExtensions[i]) == 0 )
226
+ return soundExtErrCodes[i];
227
+ }
228
+ return 0;
229
+ }
230
+
231
+
232
+ /***********************************************************************
233
+ * IsValidSrcExtension
234
+ *
235
+ * Checks if the 'SRC' value within the FRAME element is valid
236
+ * The 'SRC' extension must end in ".htm", ".html", ".shtm", ".shtml",
237
+ * ".cfm", ".cfml", ".asp", ".cgi", ".pl", or ".smil"
238
+ *
239
+ * Returns yes if it is, returns no otherwise.
240
+ ***********************************************************************/
241
+
242
+ static Bool IsValidSrcExtension( ctmbstr sType )
243
+ {
244
+ uint i;
245
+ tmbchar ext[20];
246
+ GetFileExtension( sType, ext, sizeof(ext) );
247
+
248
+ for (i = 0; i < N_FRAME_EXTS; i++)
249
+ {
250
+ if ( TY_(tmbstrcasecmp)(ext, frameExtensions[i]) == 0 )
251
+ return yes;
252
+ }
253
+ return no;
254
+ }
255
+
256
+
257
+ /*********************************************************************
258
+ * IsValidMediaExtension
259
+ *
260
+ * Checks to warn the user that syncronized text equivalents are
261
+ * required if multimedia is used.
262
+ *********************************************************************/
263
+
264
+ static Bool IsValidMediaExtension( ctmbstr sType )
265
+ {
266
+ uint i;
267
+ tmbchar ext[20];
268
+ GetFileExtension( sType, ext, sizeof(ext) );
269
+
270
+ for (i = 0; i < N_MEDIA_EXTS; i++)
271
+ {
272
+ if ( TY_(tmbstrcasecmp)(ext, mediaExtensions[i]) == 0 )
273
+ return yes;
274
+ }
275
+ return no;
276
+ }
277
+
278
+
279
+ /************************************************************************
280
+ * IsWhitespace
281
+ *
282
+ * Checks if the given string is all whitespace.
283
+ * Returns 'yes' if it is, 'no' if it's not.
284
+ ************************************************************************/
285
+
286
+ static Bool IsWhitespace( ctmbstr pString )
287
+ {
288
+ Bool isWht = yes;
289
+ ctmbstr cp;
290
+
291
+ for ( cp = pString; isWht && cp && *cp; ++cp )
292
+ {
293
+ isWht = TY_(IsWhite)( *cp );
294
+ }
295
+ return isWht;
296
+ }
297
+
298
+ static Bool hasValue( AttVal* av )
299
+ {
300
+ return ( av && ! IsWhitespace(av->value) );
301
+ }
302
+
303
+ /***********************************************************************
304
+ * IsPlaceholderAlt
305
+ *
306
+ * Checks to see if there is an image and photo place holder contained
307
+ * in the ALT text.
308
+ *
309
+ * Returns 'yes' if there is, 'no' if not.
310
+ ***********************************************************************/
311
+
312
+ static Bool IsPlaceholderAlt( ctmbstr txt )
313
+ {
314
+ return ( strstr(txt, "image") != NULL ||
315
+ strstr(txt, "photo") != NULL );
316
+ }
317
+
318
+
319
+ /***********************************************************************
320
+ * IsPlaceholderTitle
321
+ *
322
+ * Checks to see if there is an TITLE place holder contained
323
+ * in the 'ALT' text.
324
+ *
325
+ * Returns 'yes' if there is, 'no' if not.
326
+
327
+ static Bool IsPlaceHolderTitle( ctmbstr txt )
328
+ {
329
+ return ( strstr(txt, "title") != NULL );
330
+ }
331
+ ***********************************************************************/
332
+
333
+
334
+ /***********************************************************************
335
+ * IsPlaceHolderObject
336
+ *
337
+ * Checks to see if there is an OBJECT place holder contained
338
+ * in the 'ALT' text.
339
+ *
340
+ * Returns 'yes' if there is, 'no' if not.
341
+ ***********************************************************************/
342
+
343
+ static Bool IsPlaceHolderObject( ctmbstr txt )
344
+ {
345
+ return ( strstr(txt, "object") != NULL );
346
+ }
347
+
348
+
349
+ /**********************************************************
350
+ * EndsWithBytes
351
+ *
352
+ * Checks to see if the ALT text ends with 'bytes'
353
+ * Returns 'yes', if true, 'no' otherwise.
354
+ **********************************************************/
355
+
356
+ static Bool EndsWithBytes( ctmbstr txt )
357
+ {
358
+ uint len = TY_(tmbstrlen)( txt );
359
+ return ( len >= 5 && TY_(tmbstrcmp)(txt+len-5, "bytes") == 0 );
360
+ }
361
+
362
+
363
+ /*******************************************************
364
+ * textFromOneNode
365
+ *
366
+ * Returns a list of characters contained within one
367
+ * text node.
368
+ *******************************************************/
369
+
370
+ static ctmbstr textFromOneNode( TidyDocImpl* doc, Node* node )
371
+ {
372
+ uint i;
373
+ uint x = 0;
374
+ tmbstr txt = doc->access.text;
375
+
376
+ if ( node )
377
+ {
378
+ /* Copy contents of a text node */
379
+ for (i = node->start; i < node->end; ++i, ++x )
380
+ {
381
+ txt[x] = doc->lexer->lexbuf[i];
382
+
383
+ /* Check buffer overflow */
384
+ if ( x >= sizeof(doc->access.text)-1 )
385
+ break;
386
+ }
387
+ }
388
+
389
+ txt[x] = '\0';
390
+ return txt;
391
+ }
392
+
393
+
394
+ /*********************************************************
395
+ * getTextNode
396
+ *
397
+ * Locates text nodes within a container element.
398
+ * Retrieves text that are found contained within
399
+ * text nodes, and concatenates the text.
400
+ *********************************************************/
401
+
402
+ static void getTextNode( TidyDocImpl* doc, Node* node )
403
+ {
404
+ tmbstr txtnod = doc->access.textNode;
405
+
406
+ /*
407
+ Continues to traverse through container element until it no
408
+ longer contains any more contents
409
+ */
410
+
411
+ /* If the tag of the node is NULL, then grab the text within the node */
412
+ if ( TY_(nodeIsText)(node) )
413
+ {
414
+ uint i;
415
+
416
+ /* Retrieves each character found within the text node */
417
+ for (i = node->start; i < node->end; i++)
418
+ {
419
+ /* The text must not exceed buffer */
420
+ if ( doc->access.counter >= TEXTBUF_SIZE-1 )
421
+ return;
422
+
423
+ txtnod[ doc->access.counter++ ] = doc->lexer->lexbuf[i];
424
+ }
425
+
426
+ /* Traverses through the contents within a container element */
427
+ for ( node = node->content; node != NULL; node = node->next )
428
+ getTextNode( doc, node );
429
+ }
430
+ }
431
+
432
+
433
+ /**********************************************************
434
+ * getTextNodeClear
435
+ *
436
+ * Clears the current 'textNode' and reloads it with new
437
+ * text. The textNode must be cleared before use.
438
+ **********************************************************/
439
+
440
+ static tmbstr getTextNodeClear( TidyDocImpl* doc, Node* node )
441
+ {
442
+ /* Clears list */
443
+ TidyClearMemory( doc->access.textNode, TEXTBUF_SIZE );
444
+ doc->access.counter = 0;
445
+
446
+ getTextNode( doc, node->content );
447
+ return doc->access.textNode;
448
+ }
449
+
450
+ /**********************************************************
451
+ * LevelX_Enabled
452
+ *
453
+ * Tell whether access "X" is enabled.
454
+ **********************************************************/
455
+
456
+ static Bool Level1_Enabled( TidyDocImpl* doc )
457
+ {
458
+ return doc->access.PRIORITYCHK == 1 ||
459
+ doc->access.PRIORITYCHK == 2 ||
460
+ doc->access.PRIORITYCHK == 3;
461
+ }
462
+ static Bool Level2_Enabled( TidyDocImpl* doc )
463
+ {
464
+ return doc->access.PRIORITYCHK == 2 ||
465
+ doc->access.PRIORITYCHK == 3;
466
+ }
467
+ static Bool Level3_Enabled( TidyDocImpl* doc )
468
+ {
469
+ return doc->access.PRIORITYCHK == 3;
470
+ }
471
+
472
+ /********************************************************
473
+ * CheckColorAvailable
474
+ *
475
+ * Verify that information conveyed with color is
476
+ * available without color.
477
+ ********************************************************/
478
+
479
+ static void CheckColorAvailable( TidyDocImpl* doc, Node* node )
480
+ {
481
+ if (Level1_Enabled( doc ))
482
+ {
483
+ if ( nodeIsIMG(node) )
484
+ TY_(ReportAccessWarning)( doc, node, INFORMATION_NOT_CONVEYED_IMAGE );
485
+
486
+ else if ( nodeIsAPPLET(node) )
487
+ TY_(ReportAccessWarning)( doc, node, INFORMATION_NOT_CONVEYED_APPLET );
488
+
489
+ else if ( nodeIsOBJECT(node) )
490
+ TY_(ReportAccessWarning)( doc, node, INFORMATION_NOT_CONVEYED_OBJECT );
491
+
492
+ else if ( nodeIsSCRIPT(node) )
493
+ TY_(ReportAccessWarning)( doc, node, INFORMATION_NOT_CONVEYED_SCRIPT );
494
+
495
+ else if ( nodeIsINPUT(node) )
496
+ TY_(ReportAccessWarning)( doc, node, INFORMATION_NOT_CONVEYED_INPUT );
497
+ }
498
+ }
499
+
500
+ /*********************************************************************
501
+ * CheckColorContrast
502
+ *
503
+ * Checks elements for color contrast. Must have valid contrast for
504
+ * valid visibility.
505
+ *
506
+ * This logic is extremely fragile as it does not recognize
507
+ * the fact that color is inherited by many components and
508
+ * that BG and FG colors are often set separately. E.g. the
509
+ * background color may be set by for the body or a table
510
+ * or a cell. The foreground color may be set by any text
511
+ * element (p, h1, h2, input, textarea), either explicitly
512
+ * or by style. Ergo, this test will not handle most real
513
+ * world cases. It's a start, however.
514
+ *********************************************************************/
515
+
516
+ static void CheckColorContrast( TidyDocImpl* doc, Node* node )
517
+ {
518
+ int rgbBG[3] = {255,255,255}; /* Black text on white BG */
519
+
520
+ if (Level3_Enabled( doc ))
521
+ {
522
+ Bool gotBG = yes;
523
+ AttVal* av;
524
+
525
+ /* Check for 'BGCOLOR' first to compare with other color attributes */
526
+ for ( av = node->attributes; av; av = av->next )
527
+ {
528
+ if ( attrIsBGCOLOR(av) )
529
+ {
530
+ if ( hasValue(av) )
531
+ gotBG = GetRgb( av->value, rgbBG );
532
+ }
533
+ }
534
+
535
+ /*
536
+ Search for COLOR attributes to compare with background color
537
+ Must have valid colour contrast
538
+ */
539
+ for ( av = node->attributes; gotBG && av != NULL; av = av->next )
540
+ {
541
+ uint errcode = 0;
542
+ if ( attrIsTEXT(av) )
543
+ errcode = COLOR_CONTRAST_TEXT;
544
+ else if ( attrIsLINK(av) )
545
+ errcode = COLOR_CONTRAST_LINK;
546
+ else if ( attrIsALINK(av) )
547
+ errcode = COLOR_CONTRAST_ACTIVE_LINK;
548
+ else if ( attrIsVLINK(av) )
549
+ errcode = COLOR_CONTRAST_VISITED_LINK;
550
+
551
+ if ( errcode && hasValue(av) )
552
+ {
553
+ int rgbFG[3] = {0, 0, 0}; /* Black text */
554
+
555
+ if ( GetRgb(av->value, rgbFG) &&
556
+ !CompareColors(rgbBG, rgbFG) )
557
+ {
558
+ TY_(ReportAccessWarning)( doc, node, errcode );
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }
564
+
565
+
566
+ /**************************************************************
567
+ * CompareColors
568
+ *
569
+ * Compares two RGB colors for good contrast.
570
+ **************************************************************/
571
+ static int minmax( int i1, int i2 )
572
+ {
573
+ return MAX(i1, i2) - MIN(i1,i2);
574
+ }
575
+ static int brightness( const int rgb[3] )
576
+ {
577
+ return ((rgb[0]*299) + (rgb[1]*587) + (rgb[2]*114)) / 1000;
578
+ }
579
+
580
+ static Bool CompareColors( const int rgbBG[3], const int rgbFG[3] )
581
+ {
582
+ int brightBG = brightness( rgbBG );
583
+ int brightFG = brightness( rgbFG );
584
+
585
+ int diffBright = minmax( brightBG, brightFG );
586
+
587
+ int diffColor = minmax( rgbBG[0], rgbFG[0] )
588
+ + minmax( rgbBG[1], rgbFG[1] )
589
+ + minmax( rgbBG[2], rgbFG[2] );
590
+
591
+ return ( diffBright > 180 &&
592
+ diffColor > 500 );
593
+ }
594
+
595
+
596
+ /*********************************************************************
597
+ * GetRgb
598
+ *
599
+ * Gets the red, green and blue values for this attribute for the
600
+ * background.
601
+ *
602
+ * Example: If attribute is BGCOLOR="#121005" then red = 18, green = 16,
603
+ * blue = 5.
604
+ *********************************************************************/
605
+
606
+ static Bool GetRgb( ctmbstr color, int rgb[] )
607
+ {
608
+ uint x;
609
+
610
+ /* Check if we have a color name */
611
+ for (x = 0; x < N_COLORS; x++)
612
+ {
613
+ if ( strstr(colorNames[x], color) != NULL )
614
+ {
615
+ rgb[0] = colorValues[x][0];
616
+ rgb[1] = colorValues[x][1];
617
+ rgb[2] = colorValues[x][2];
618
+ return yes;
619
+ }
620
+ }
621
+
622
+ /*
623
+ No color name so must be hex values
624
+ Is this a number in hexadecimal format?
625
+ */
626
+
627
+ /* Must be 7 characters in the RGB value (including '#') */
628
+ if ( TY_(tmbstrlen)(color) == 7 && color[0] == '#' )
629
+ {
630
+ rgb[0] = (ctox(color[1]) * 16) + ctox(color[2]);
631
+ rgb[1] = (ctox(color[3]) * 16) + ctox(color[4]);
632
+ rgb[2] = (ctox(color[5]) * 16) + ctox(color[6]);
633
+ return yes;
634
+ }
635
+ return no;
636
+ }
637
+
638
+
639
+
640
+ /*******************************************************************
641
+ * ctox
642
+ *
643
+ * Converts a character to a number.
644
+ * Example: if given character is 'A' then returns 10.
645
+ *
646
+ * Returns the number that the character represents. Returns -1 if not a
647
+ * valid number.
648
+ *******************************************************************/
649
+
650
+ static int ctox( tmbchar ch )
651
+ {
652
+ if ( ch >= '0' && ch <= '9' )
653
+ {
654
+ return ch - '0';
655
+ }
656
+ else if ( ch >= 'a' && ch <= 'f' )
657
+ {
658
+ return ch - 'a' + 10;
659
+ }
660
+ else if ( ch >= 'A' && ch <= 'F' )
661
+ {
662
+ return ch - 'A' + 10;
663
+ }
664
+ return -1;
665
+ }
666
+
667
+
668
+ /***********************************************************
669
+ * CheckImage
670
+ *
671
+ * Checks all image attributes for specific elements to
672
+ * check for validity of the values contained within
673
+ * the attributes. An appropriate warning message is displayed
674
+ * to indicate the error.
675
+ ***********************************************************/
676
+
677
+ static void CheckImage( TidyDocImpl* doc, Node* node )
678
+ {
679
+ Bool HasAlt = no;
680
+ Bool HasIsMap = no;
681
+ Bool HasLongDesc = no;
682
+ Bool HasDLINK = no;
683
+ Bool HasValidHeight = no;
684
+ Bool HasValidWidthBullet = no;
685
+ Bool HasValidWidthHR = no;
686
+ Bool HasTriggeredMissingLongDesc = no;
687
+
688
+ AttVal* av;
689
+
690
+ if (Level1_Enabled( doc ))
691
+ {
692
+ /* Checks all image attributes for invalid values within attributes */
693
+ for (av = node->attributes; av != NULL; av = av->next)
694
+ {
695
+ /*
696
+ Checks for valid ALT attribute.
697
+ The length of the alt text must be less than 150 characters
698
+ long.
699
+ */
700
+ if ( attrIsALT(av) )
701
+ {
702
+ if (av->value != NULL)
703
+ {
704
+ if ((TY_(tmbstrlen)(av->value) < 150) &&
705
+ (IsPlaceholderAlt (av->value) == no) &&
706
+ (IsPlaceHolderObject (av->value) == no) &&
707
+ (EndsWithBytes (av->value) == no) &&
708
+ (IsImage (av->value) == no))
709
+ {
710
+ HasAlt = yes;
711
+ }
712
+
713
+ else if (TY_(tmbstrlen)(av->value) > 150)
714
+ {
715
+ HasAlt = yes;
716
+ TY_(ReportAccessWarning)( doc, node, IMG_ALT_SUSPICIOUS_TOO_LONG );
717
+ }
718
+
719
+ else if (IsImage (av->value) == yes)
720
+ {
721
+ HasAlt = yes;
722
+ TY_(ReportAccessWarning)( doc, node, IMG_ALT_SUSPICIOUS_FILENAME);
723
+ }
724
+
725
+ else if (IsPlaceholderAlt (av->value) == yes)
726
+ {
727
+ HasAlt = yes;
728
+ TY_(ReportAccessWarning)( doc, node, IMG_ALT_SUSPICIOUS_PLACEHOLDER);
729
+ }
730
+
731
+ else if (EndsWithBytes (av->value) == yes)
732
+ {
733
+ HasAlt = yes;
734
+ TY_(ReportAccessWarning)( doc, node, IMG_ALT_SUSPICIOUS_FILE_SIZE);
735
+ }
736
+ }
737
+ }
738
+
739
+ /*
740
+ Checks for width values of 'bullets' and 'horizontal
741
+ rules' for validity.
742
+
743
+ Valid pixel width for 'bullets' must be < 30, and > 150 for
744
+ horizontal rules.
745
+ */
746
+ else if ( attrIsWIDTH(av) )
747
+ {
748
+ /* Longdesc attribute needed if width attribute is not present. */
749
+ if ( hasValue(av) )
750
+ {
751
+ int width = atoi( av->value );
752
+ if ( width < 30 )
753
+ HasValidWidthBullet = yes;
754
+
755
+ if ( width > 150 )
756
+ HasValidWidthHR = yes;
757
+ }
758
+ }
759
+
760
+ /*
761
+ Checks for height values of 'bullets' and horizontal
762
+ rules for validity.
763
+
764
+ Valid pixel height for 'bullets' and horizontal rules
765
+ mustt be < 30.
766
+ */
767
+ else if ( attrIsHEIGHT(av) )
768
+ {
769
+ /* Longdesc attribute needed if height attribute not present. */
770
+ if ( hasValue(av) && atoi(av->value) < 30 )
771
+ HasValidHeight = yes;
772
+ }
773
+
774
+ /*
775
+ Checks for longdesc and determines validity.
776
+ The length of the 'longdesc' must be > 1
777
+ */
778
+ else if ( attrIsLONGDESC(av) )
779
+ {
780
+ if ( hasValue(av) && TY_(tmbstrlen)(av->value) > 1 )
781
+ HasLongDesc = yes;
782
+ }
783
+
784
+ /*
785
+ Checks for 'USEMAP' attribute. Ensures that
786
+ text links are provided for client-side image maps
787
+ */
788
+ else if ( attrIsUSEMAP(av) )
789
+ {
790
+ if ( hasValue(av) )
791
+ doc->access.HasUseMap = yes;
792
+ }
793
+
794
+ else if ( attrIsISMAP(av) )
795
+ {
796
+ HasIsMap = yes;
797
+ }
798
+ }
799
+
800
+
801
+ /*
802
+ Check to see if a dLINK is present. The ANCHOR element must
803
+ be present following the IMG element. The text found between
804
+ the ANCHOR tags must be < 6 characters long, and must contain
805
+ the letter 'd'.
806
+ */
807
+ if ( nodeIsA(node->next) )
808
+ {
809
+ node = node->next;
810
+
811
+ /*
812
+ Node following the anchor must be a text node
813
+ for dLINK to exist
814
+ */
815
+
816
+ if (node->content != NULL && (node->content)->tag == NULL)
817
+ {
818
+ /* Number of characters found within the text node */
819
+ ctmbstr word = textFromOneNode( doc, node->content);
820
+
821
+ if ((TY_(tmbstrcmp)(word,"d") == 0)||
822
+ (TY_(tmbstrcmp)(word,"D") == 0))
823
+ {
824
+ HasDLINK = yes;
825
+ }
826
+ }
827
+ }
828
+
829
+ /*
830
+ Special case check for dLINK. This will occur if there is
831
+ whitespace between the <img> and <a> elements. Ignores
832
+ whitespace and continues check for dLINK.
833
+ */
834
+
835
+ if ( node->next && !node->next->tag )
836
+ {
837
+ node = node->next;
838
+
839
+ if ( nodeIsA(node->next) )
840
+ {
841
+ node = node->next;
842
+
843
+ /*
844
+ Node following the ANCHOR must be a text node
845
+ for dLINK to exist
846
+ */
847
+ if (node->content != NULL && node->content->tag == NULL)
848
+ {
849
+ /* Number of characters found within the text node */
850
+ ctmbstr word = textFromOneNode( doc, node->content );
851
+
852
+ if ((TY_(tmbstrcmp)(word, "d") == 0)||
853
+ (TY_(tmbstrcmp)(word, "D") == 0))
854
+ {
855
+ HasDLINK = yes;
856
+ }
857
+ }
858
+ }
859
+ }
860
+
861
+ if ((HasAlt == no)&&
862
+ (HasValidWidthBullet == yes)&&
863
+ (HasValidHeight == yes))
864
+ {
865
+ }
866
+
867
+ if ((HasAlt == no)&&
868
+ (HasValidWidthHR == yes)&&
869
+ (HasValidHeight == yes))
870
+ {
871
+ }
872
+
873
+ if (HasAlt == no)
874
+ {
875
+ TY_(ReportAccessError)( doc, node, IMG_MISSING_ALT);
876
+ }
877
+
878
+ if ((HasLongDesc == no)&&
879
+ (HasValidHeight ==yes)&&
880
+ ((HasValidWidthHR == yes)||
881
+ (HasValidWidthBullet == yes)))
882
+ {
883
+ HasTriggeredMissingLongDesc = yes;
884
+ }
885
+
886
+ if (HasTriggeredMissingLongDesc == no)
887
+ {
888
+ if ((HasDLINK == yes)&&
889
+ (HasLongDesc == no))
890
+ {
891
+ TY_(ReportAccessWarning)( doc, node, IMG_MISSING_LONGDESC);
892
+ }
893
+
894
+ if ((HasLongDesc == yes)&&
895
+ (HasDLINK == no))
896
+ {
897
+ TY_(ReportAccessWarning)( doc, node, IMG_MISSING_DLINK);
898
+ }
899
+
900
+ if ((HasLongDesc == no)&&
901
+ (HasDLINK == no))
902
+ {
903
+ TY_(ReportAccessWarning)( doc, node, IMG_MISSING_LONGDESC_DLINK);
904
+ }
905
+ }
906
+
907
+ if (HasIsMap == yes)
908
+ {
909
+ TY_(ReportAccessError)( doc, node, IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION);
910
+
911
+ TY_(ReportAccessWarning)( doc, node, IMG_MAP_SERVER_REQUIRES_TEXT_LINKS);
912
+ }
913
+ }
914
+ }
915
+
916
+
917
+ /***********************************************************
918
+ * CheckApplet
919
+ *
920
+ * Checks APPLET element to check for validity pertaining
921
+ * the 'ALT' attribute. An appropriate warning message is
922
+ * displayed to indicate the error. An appropriate warning
923
+ * message is displayed to indicate the error. If no 'ALT'
924
+ * text is present, then there must be alternate content
925
+ * within the APPLET element.
926
+ ***********************************************************/
927
+
928
+ static void CheckApplet( TidyDocImpl* doc, Node* node )
929
+ {
930
+ Bool HasAlt = no;
931
+ Bool HasDescription = no;
932
+
933
+ AttVal* av;
934
+
935
+ if (Level1_Enabled( doc ))
936
+ {
937
+ /* Checks for attributes within the APPLET element */
938
+ for (av = node->attributes; av != NULL; av = av->next)
939
+ {
940
+ /*
941
+ Checks for valid ALT attribute.
942
+ The length of the alt text must be > 4 characters in length
943
+ but must be < 150 characters long.
944
+ */
945
+
946
+ if ( attrIsALT(av) )
947
+ {
948
+ if (av->value != NULL)
949
+ {
950
+ HasAlt = yes;
951
+ }
952
+ }
953
+ }
954
+
955
+ if (HasAlt == no)
956
+ {
957
+ /* Must have alternate text representation for that element */
958
+ if (node->content != NULL)
959
+ {
960
+ ctmbstr word = NULL;
961
+
962
+ if ( node->content->tag == NULL )
963
+ word = textFromOneNode( doc, node->content);
964
+
965
+ if ( node->content->content != NULL &&
966
+ node->content->content->tag == NULL )
967
+ {
968
+ word = textFromOneNode( doc, node->content->content);
969
+ }
970
+
971
+ if ( word != NULL && !IsWhitespace(word) )
972
+ HasDescription = yes;
973
+ }
974
+ }
975
+
976
+ if ( !HasDescription && !HasAlt )
977
+ {
978
+ TY_(ReportAccessError)( doc, node, APPLET_MISSING_ALT );
979
+ }
980
+ }
981
+ }
982
+
983
+
984
+ /*******************************************************************
985
+ * CheckObject
986
+ *
987
+ * Checks to verify whether the OBJECT element contains
988
+ * 'ALT' text, and to see that the sound file selected is
989
+ * of a valid sound file type. OBJECT must have an alternate text
990
+ * representation.
991
+ *******************************************************************/
992
+
993
+ static void CheckObject( TidyDocImpl* doc, Node* node )
994
+ {
995
+ Bool HasAlt = no;
996
+ Bool HasDescription = no;
997
+
998
+ if (Level1_Enabled( doc ))
999
+ {
1000
+ if ( node->content != NULL)
1001
+ {
1002
+ if ( node->content->type != TextNode )
1003
+ {
1004
+ Node* tnode = node->content;
1005
+ AttVal* av;
1006
+
1007
+ for ( av=tnode->attributes; av; av = av->next )
1008
+ {
1009
+ if ( attrIsALT(av) )
1010
+ {
1011
+ HasAlt = yes;
1012
+ break;
1013
+ }
1014
+ }
1015
+ }
1016
+
1017
+ /* Must have alternate text representation for that element */
1018
+ if ( !HasAlt )
1019
+ {
1020
+ ctmbstr word = NULL;
1021
+
1022
+ if ( TY_(nodeIsText)(node->content) )
1023
+ word = textFromOneNode( doc, node->content );
1024
+
1025
+ if ( word == NULL &&
1026
+ TY_(nodeIsText)(node->content->content) )
1027
+ {
1028
+ word = textFromOneNode( doc, node->content->content );
1029
+ }
1030
+
1031
+ if ( word != NULL && !IsWhitespace(word) )
1032
+ HasDescription = yes;
1033
+ }
1034
+ }
1035
+
1036
+ if ( !HasAlt && !HasDescription )
1037
+ {
1038
+ TY_(ReportAccessError)( doc, node, OBJECT_MISSING_ALT );
1039
+ }
1040
+ }
1041
+ }
1042
+
1043
+
1044
+ /***************************************************************
1045
+ * CheckMissingStyleSheets
1046
+ *
1047
+ * Ensures that stylesheets are used to control the presentation.
1048
+ ***************************************************************/
1049
+
1050
+ static Bool CheckMissingStyleSheets( TidyDocImpl* doc, Node* node )
1051
+ {
1052
+ AttVal* av;
1053
+ Node* content;
1054
+ Bool sspresent = no;
1055
+
1056
+ for ( content = node->content;
1057
+ !sspresent && content != NULL;
1058
+ content = content->next )
1059
+ {
1060
+ sspresent = ( nodeIsLINK(content) ||
1061
+ nodeIsSTYLE(content) ||
1062
+ nodeIsFONT(content) ||
1063
+ nodeIsBASEFONT(content) );
1064
+
1065
+ for ( av = content->attributes;
1066
+ !sspresent && av != NULL;
1067
+ av = av->next )
1068
+ {
1069
+ sspresent = ( attrIsSTYLE(av) || attrIsTEXT(av) ||
1070
+ attrIsVLINK(av) || attrIsALINK(av) ||
1071
+ attrIsLINK(av) );
1072
+
1073
+ if ( !sspresent && attrIsREL(av) )
1074
+ {
1075
+ sspresent = AttrValueIs(av, "stylesheet");
1076
+ }
1077
+ }
1078
+
1079
+ if ( ! sspresent )
1080
+ sspresent = CheckMissingStyleSheets( doc, content );
1081
+ }
1082
+ return sspresent;
1083
+ }
1084
+
1085
+
1086
+ /*******************************************************************
1087
+ * CheckFrame
1088
+ *
1089
+ * Checks if the URL is valid and to check if a 'LONGDESC' is needed
1090
+ * within the FRAME element. If a 'LONGDESC' is needed, the value must
1091
+ * be valid. The URL must end with the file extension, htm, or html.
1092
+ * Also, checks to ensure that the 'SRC' and 'TITLE' values are valid.
1093
+ *******************************************************************/
1094
+
1095
+ static void CheckFrame( TidyDocImpl* doc, Node* node )
1096
+ {
1097
+ Bool HasTitle = no;
1098
+ AttVal* av;
1099
+
1100
+ doc->access.numFrames++;
1101
+
1102
+ if (Level1_Enabled( doc ))
1103
+ {
1104
+ /* Checks for attributes within the FRAME element */
1105
+ for (av = node->attributes; av != NULL; av = av->next)
1106
+ {
1107
+ /* Checks if 'LONGDESC' value is valid only if present */
1108
+ if ( attrIsLONGDESC(av) )
1109
+ {
1110
+ if ( hasValue(av) && TY_(tmbstrlen)(av->value) > 1 )
1111
+ {
1112
+ doc->access.HasCheckedLongDesc++;
1113
+ }
1114
+ }
1115
+
1116
+ /* Checks for valid 'SRC' value within the frame element */
1117
+ else if ( attrIsSRC(av) )
1118
+ {
1119
+ if ( hasValue(av) && !IsValidSrcExtension(av->value) )
1120
+ {
1121
+ TY_(ReportAccessError)( doc, node, FRAME_SRC_INVALID );
1122
+ }
1123
+ }
1124
+
1125
+ /* Checks for valid 'TITLE' value within frame element */
1126
+ else if ( attrIsTITLE(av) )
1127
+ {
1128
+ if ( hasValue(av) )
1129
+ HasTitle = yes;
1130
+
1131
+ if ( !HasTitle )
1132
+ {
1133
+ if ( av->value == NULL || TY_(tmbstrlen)(av->value) == 0 )
1134
+ {
1135
+ HasTitle = yes;
1136
+ TY_(ReportAccessError)( doc, node, FRAME_TITLE_INVALID_NULL);
1137
+ }
1138
+ else
1139
+ {
1140
+ if ( IsWhitespace(av->value) && TY_(tmbstrlen)(av->value) > 0 )
1141
+ {
1142
+ HasTitle = yes;
1143
+ TY_(ReportAccessError)( doc, node, FRAME_TITLE_INVALID_SPACES );
1144
+ }
1145
+ }
1146
+ }
1147
+ }
1148
+ }
1149
+
1150
+ if ( !HasTitle )
1151
+ {
1152
+ TY_(ReportAccessError)( doc, node, FRAME_MISSING_TITLE);
1153
+ }
1154
+
1155
+ if ( doc->access.numFrames==3 && doc->access.HasCheckedLongDesc<3 )
1156
+ {
1157
+ doc->access.numFrames = 0;
1158
+ TY_(ReportAccessWarning)( doc, node, FRAME_MISSING_LONGDESC );
1159
+ }
1160
+ }
1161
+ }
1162
+
1163
+
1164
+ /****************************************************************
1165
+ * CheckIFrame
1166
+ *
1167
+ * Checks if 'SRC' value is valid. Must end in appropriate
1168
+ * file extension.
1169
+ ****************************************************************/
1170
+
1171
+ static void CheckIFrame( TidyDocImpl* doc, Node* node )
1172
+ {
1173
+ if (Level1_Enabled( doc ))
1174
+ {
1175
+ /* Checks for valid 'SRC' value within the IFRAME element */
1176
+ AttVal* av = attrGetSRC( node );
1177
+ if ( hasValue(av) )
1178
+ {
1179
+ if ( !IsValidSrcExtension(av->value) )
1180
+ TY_(ReportAccessError)( doc, node, FRAME_SRC_INVALID );
1181
+ }
1182
+ }
1183
+ }
1184
+
1185
+
1186
+ /**********************************************************************
1187
+ * CheckAnchorAccess
1188
+ *
1189
+ * Checks that the sound file is valid, and to ensure that
1190
+ * text transcript is present describing the 'HREF' within the
1191
+ * ANCHOR element. Also checks to see ensure that the 'TARGET' attribute
1192
+ * (if it exists) is not NULL and does not contain '_new' or '_blank'.
1193
+ **********************************************************************/
1194
+
1195
+ static void CheckAnchorAccess( TidyDocImpl* doc, Node* node )
1196
+ {
1197
+ AttVal* av;
1198
+ Bool HasDescription = no;
1199
+ Bool HasTriggeredLink = no;
1200
+
1201
+ /* Checks for attributes within the ANCHOR element */
1202
+ for ( av = node->attributes; av != NULL; av = av->next )
1203
+ {
1204
+ if (Level1_Enabled( doc ))
1205
+ {
1206
+ /* Must be of valid sound file type */
1207
+ if ( attrIsHREF(av) )
1208
+ {
1209
+ if ( hasValue(av) )
1210
+ {
1211
+ tmbchar ext[ 20 ];
1212
+ GetFileExtension (av->value, ext, sizeof(ext) );
1213
+
1214
+ /* Checks to see if multimedia is used */
1215
+ if ( IsValidMediaExtension(av->value) )
1216
+ {
1217
+ TY_(ReportAccessError)( doc, node, MULTIMEDIA_REQUIRES_TEXT );
1218
+ }
1219
+
1220
+ /*
1221
+ Checks for validity of sound file, and checks to see if
1222
+ the file is described within the document, or by a link
1223
+ that is present which gives the description.
1224
+ */
1225
+ if ( TY_(tmbstrlen)(ext) < 6 && TY_(tmbstrlen)(ext) > 0 )
1226
+ {
1227
+ int errcode = IsSoundFile( av->value );
1228
+ if ( errcode )
1229
+ {
1230
+ if (node->next != NULL)
1231
+ {
1232
+ if (node->next->tag == NULL)
1233
+ {
1234
+ ctmbstr word = textFromOneNode( doc, node->next);
1235
+
1236
+ /* Must contain at least one letter in the text */
1237
+ if (IsWhitespace (word) == no)
1238
+ {
1239
+ HasDescription = yes;
1240
+ }
1241
+ }
1242
+ }
1243
+
1244
+ /* Must contain text description of sound file */
1245
+ if ( !HasDescription )
1246
+ {
1247
+ TY_(ReportAccessError)( doc, node, errcode );
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+ }
1253
+ }
1254
+
1255
+ if (Level2_Enabled( doc ))
1256
+ {
1257
+ /* Checks 'TARGET' attribute for validity if it exists */
1258
+ if ( attrIsTARGET(av) )
1259
+ {
1260
+ if (AttrValueIs(av, "_new"))
1261
+ {
1262
+ TY_(ReportAccessWarning)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_NEW);
1263
+ }
1264
+ else if (AttrValueIs(av, "_blank"))
1265
+ {
1266
+ TY_(ReportAccessWarning)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_BLANK);
1267
+ }
1268
+ }
1269
+ }
1270
+ }
1271
+
1272
+ if (Level2_Enabled( doc ))
1273
+ {
1274
+ if ((node->content != NULL)&&
1275
+ (node->content->tag == NULL))
1276
+ {
1277
+ ctmbstr word = textFromOneNode( doc, node->content);
1278
+
1279
+ if ((word != NULL)&&
1280
+ (IsWhitespace (word) == no))
1281
+ {
1282
+ if (TY_(tmbstrcmp) (word, "more") == 0)
1283
+ {
1284
+ HasTriggeredLink = yes;
1285
+ }
1286
+
1287
+ if (TY_(tmbstrcmp) (word, "click here") == 0)
1288
+ {
1289
+ TY_(ReportAccessWarning)( doc, node, LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE);
1290
+ }
1291
+
1292
+ if (HasTriggeredLink == no)
1293
+ {
1294
+ if (TY_(tmbstrlen)(word) < 6)
1295
+ {
1296
+ TY_(ReportAccessWarning)( doc, node, LINK_TEXT_NOT_MEANINGFUL);
1297
+ }
1298
+ }
1299
+
1300
+ if (TY_(tmbstrlen)(word) > 60)
1301
+ {
1302
+ TY_(ReportAccessWarning)( doc, node, LINK_TEXT_TOO_LONG);
1303
+ }
1304
+
1305
+ }
1306
+ }
1307
+
1308
+ if (node->content == NULL)
1309
+ {
1310
+ TY_(ReportAccessWarning)( doc, node, LINK_TEXT_MISSING);
1311
+ }
1312
+ }
1313
+ }
1314
+
1315
+
1316
+ /************************************************************
1317
+ * CheckArea
1318
+ *
1319
+ * Checks attributes within the AREA element to
1320
+ * determine if the 'ALT' text and 'HREF' values are valid.
1321
+ * Also checks to see ensure that the 'TARGET' attribute
1322
+ * (if it exists) is not NULL and does not contain '_new'
1323
+ * or '_blank'.
1324
+ ************************************************************/
1325
+
1326
+ static void CheckArea( TidyDocImpl* doc, Node* node )
1327
+ {
1328
+ Bool HasAlt = no;
1329
+ AttVal* av;
1330
+
1331
+ /* Checks all attributes within the AREA element */
1332
+ for (av = node->attributes; av != NULL; av = av->next)
1333
+ {
1334
+ if (Level1_Enabled( doc ))
1335
+ {
1336
+ /*
1337
+ Checks for valid ALT attribute.
1338
+ The length of the alt text must be > 4 characters long
1339
+ but must be less than 150 characters long.
1340
+ */
1341
+
1342
+ if ( attrIsALT(av) )
1343
+ {
1344
+ /* The check for validity */
1345
+ if (av->value != NULL)
1346
+ {
1347
+ HasAlt = yes;
1348
+ }
1349
+ }
1350
+ }
1351
+
1352
+ if (Level2_Enabled( doc ))
1353
+ {
1354
+ if ( attrIsTARGET(av) )
1355
+ {
1356
+ if (AttrValueIs(av, "_new"))
1357
+ {
1358
+ TY_(ReportAccessWarning)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_NEW);
1359
+ }
1360
+ else if (AttrValueIs(av, "_blank"))
1361
+ {
1362
+ TY_(ReportAccessWarning)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_BLANK);
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+
1368
+ if (Level1_Enabled( doc ))
1369
+ {
1370
+ /* AREA must contain alt text */
1371
+ if (HasAlt == no)
1372
+ {
1373
+ TY_(ReportAccessError)( doc, node, AREA_MISSING_ALT);
1374
+ }
1375
+ }
1376
+ }
1377
+
1378
+
1379
+ /***************************************************
1380
+ * CheckScript
1381
+ *
1382
+ * Checks the SCRIPT element to ensure that a
1383
+ * NOSCRIPT section follows the SCRIPT.
1384
+ ***************************************************/
1385
+
1386
+ static void CheckScriptAcc( TidyDocImpl* doc, Node* node )
1387
+ {
1388
+ if (Level1_Enabled( doc ))
1389
+ {
1390
+ /* NOSCRIPT element must appear immediately following SCRIPT element */
1391
+ if ( node->next == NULL || !nodeIsNOSCRIPT(node->next) )
1392
+ {
1393
+ TY_(ReportAccessError)( doc, node, SCRIPT_MISSING_NOSCRIPT);
1394
+ }
1395
+ }
1396
+ }
1397
+
1398
+
1399
+ /**********************************************************
1400
+ * CheckRows
1401
+ *
1402
+ * Check to see that each table has a row of headers if
1403
+ * a column of columns doesn't exist.
1404
+ **********************************************************/
1405
+
1406
+ static void CheckRows( TidyDocImpl* doc, Node* node )
1407
+ {
1408
+ int numTR = 0;
1409
+ int numValidTH = 0;
1410
+
1411
+ doc->access.CheckedHeaders++;
1412
+
1413
+ for (; node != NULL; node = node->next )
1414
+ {
1415
+ numTR++;
1416
+ if ( nodeIsTH(node->content) )
1417
+ {
1418
+ doc->access.HasTH = yes;
1419
+ if ( TY_(nodeIsText)(node->content->content) )
1420
+ {
1421
+ ctmbstr word = textFromOneNode( doc, node->content->content);
1422
+ if ( !IsWhitespace(word) )
1423
+ numValidTH++;
1424
+ }
1425
+ }
1426
+ }
1427
+
1428
+ if (numTR == numValidTH)
1429
+ doc->access.HasValidRowHeaders = yes;
1430
+
1431
+ if ( numTR >= 2 &&
1432
+ numTR > numValidTH &&
1433
+ numValidTH >= 2 &&
1434
+ doc->access.HasTH == yes )
1435
+ doc->access.HasInvalidRowHeader = yes;
1436
+ }
1437
+
1438
+
1439
+ /**********************************************************
1440
+ * CheckColumns
1441
+ *
1442
+ * Check to see that each table has a column of headers if
1443
+ * a row of columns doesn't exist.
1444
+ **********************************************************/
1445
+
1446
+ static void CheckColumns( TidyDocImpl* doc, Node* node )
1447
+ {
1448
+ Node* tnode;
1449
+ int numTH = 0;
1450
+ Bool isMissingHeader = no;
1451
+
1452
+ doc->access.CheckedHeaders++;
1453
+
1454
+ /* Table must have row of headers if headers for columns don't exist */
1455
+ if ( nodeIsTH(node->content) )
1456
+ {
1457
+ doc->access.HasTH = yes;
1458
+
1459
+ for ( tnode = node->content; tnode; tnode = tnode->next )
1460
+ {
1461
+ if ( nodeIsTH(tnode) )
1462
+ {
1463
+ if ( TY_(nodeIsText)(tnode->content) )
1464
+ {
1465
+ ctmbstr word = textFromOneNode( doc, tnode->content);
1466
+ if ( !IsWhitespace(word) )
1467
+ numTH++;
1468
+ }
1469
+ }
1470
+ else
1471
+ {
1472
+ isMissingHeader = yes;
1473
+ }
1474
+ }
1475
+ }
1476
+
1477
+ if ( !isMissingHeader && numTH > 0 )
1478
+ doc->access.HasValidColumnHeaders = yes;
1479
+
1480
+ if ( isMissingHeader && numTH >= 2 )
1481
+ doc->access.HasInvalidColumnHeader = yes;
1482
+ }
1483
+
1484
+
1485
+ /*****************************************************
1486
+ * CheckTH
1487
+ *
1488
+ * Checks to see if the header provided for a table
1489
+ * requires an abbreviation. (only required if the
1490
+ * length of the header is greater than 15 characters)
1491
+ *****************************************************/
1492
+
1493
+ static void CheckTH( TidyDocImpl* doc, Node* node )
1494
+ {
1495
+ Bool HasAbbr = no;
1496
+ ctmbstr word = NULL;
1497
+ AttVal* av;
1498
+
1499
+ if (Level3_Enabled( doc ))
1500
+ {
1501
+ /* Checks TH element for 'ABBR' attribute */
1502
+ for (av = node->attributes; av != NULL; av = av->next)
1503
+ {
1504
+ if ( attrIsABBR(av) )
1505
+ {
1506
+ /* Value must not be NULL and must be less than 15 characters */
1507
+ if ((av->value != NULL)&&
1508
+ (IsWhitespace (av->value) == no))
1509
+ {
1510
+ HasAbbr = yes;
1511
+ }
1512
+
1513
+ if ((av->value == NULL)||
1514
+ (TY_(tmbstrlen)(av->value) == 0))
1515
+ {
1516
+ HasAbbr = yes;
1517
+ TY_(ReportAccessWarning)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR_NULL);
1518
+ }
1519
+
1520
+ if ((IsWhitespace (av->value) == yes)&&
1521
+ (TY_(tmbstrlen)(av->value) > 0))
1522
+ {
1523
+ HasAbbr = yes;
1524
+ TY_(ReportAccessWarning)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES);
1525
+ }
1526
+ }
1527
+ }
1528
+
1529
+ /* If the header is greater than 15 characters, an abbreviation is needed */
1530
+ word = textFromOneNode( doc, node->content);
1531
+
1532
+ if ((word != NULL)&&
1533
+ (IsWhitespace (word) == no))
1534
+ {
1535
+ /* Must have 'ABBR' attribute if header is > 15 characters */
1536
+ if ((TY_(tmbstrlen)(word) > 15)&&
1537
+ (HasAbbr == no))
1538
+ {
1539
+ TY_(ReportAccessWarning)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR);
1540
+ }
1541
+ }
1542
+ }
1543
+ }
1544
+
1545
+
1546
+ /*****************************************************************
1547
+ * CheckMultiHeaders
1548
+ *
1549
+ * Layout tables should make sense when linearized.
1550
+ * TABLE must contain at least one TH element.
1551
+ * This technique applies only to tables used for layout purposes,
1552
+ * not to data tables. Checks for column of multiple headers.
1553
+ *****************************************************************/
1554
+
1555
+ static void CheckMultiHeaders( TidyDocImpl* doc, Node* node )
1556
+ {
1557
+ Node* TNode;
1558
+ Node* temp;
1559
+
1560
+ Bool validColSpanRows = yes;
1561
+ Bool validColSpanColumns = yes;
1562
+
1563
+ int flag = 0;
1564
+
1565
+ if (Level1_Enabled( doc ))
1566
+ {
1567
+ if (node->content != NULL)
1568
+ {
1569
+ TNode = node->content;
1570
+
1571
+ /*
1572
+ Checks for column of multiple headers found
1573
+ within a data table.
1574
+ */
1575
+ while (TNode != NULL)
1576
+ {
1577
+ if ( nodeIsTR(TNode) )
1578
+ {
1579
+ if (TNode->content != NULL)
1580
+ {
1581
+ temp = TNode->content;
1582
+
1583
+ /* The number of TH elements found within TR element */
1584
+ if (flag == 0)
1585
+ {
1586
+ while (temp != NULL)
1587
+ {
1588
+ /*
1589
+ Must contain at least one TH element
1590
+ within in the TR element
1591
+ */
1592
+ if ( nodeIsTH(temp) )
1593
+ {
1594
+ AttVal* av;
1595
+ for (av = temp->attributes; av != NULL; av = av->next)
1596
+ {
1597
+ if ( attrIsCOLSPAN(av)
1598
+ && (atoi(av->value) > 1) )
1599
+ validColSpanColumns = no;
1600
+
1601
+ if ( attrIsROWSPAN(av)
1602
+ && (atoi(av->value) > 1) )
1603
+ validColSpanRows = no;
1604
+ }
1605
+ }
1606
+
1607
+ temp = temp->next;
1608
+ }
1609
+
1610
+ flag = 1;
1611
+ }
1612
+ }
1613
+ }
1614
+
1615
+ TNode = TNode->next;
1616
+ }
1617
+
1618
+ /* Displays HTML 4 Table Algorithm when multiple column of headers used */
1619
+ if (validColSpanRows == no)
1620
+ {
1621
+ TY_(ReportAccessWarning)( doc, node, DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS );
1622
+ TY_(DisplayHTMLTableAlgorithm)( doc );
1623
+ }
1624
+
1625
+ if (validColSpanColumns == no)
1626
+ {
1627
+ TY_(ReportAccessWarning)( doc, node, DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS );
1628
+ TY_(DisplayHTMLTableAlgorithm)( doc );
1629
+ }
1630
+ }
1631
+ }
1632
+ }
1633
+
1634
+
1635
+ /****************************************************
1636
+ * CheckTable
1637
+ *
1638
+ * Checks the TABLE element to ensure that the
1639
+ * table is not missing any headers. Must have either
1640
+ * a row or column of headers.
1641
+ ****************************************************/
1642
+
1643
+ static void CheckTable( TidyDocImpl* doc, Node* node )
1644
+ {
1645
+ Node* TNode;
1646
+ Node* temp;
1647
+
1648
+ tmbstr word = NULL;
1649
+
1650
+ int numTR = 0;
1651
+
1652
+ Bool HasSummary = no;
1653
+ Bool HasCaption = no;
1654
+
1655
+ if (Level3_Enabled( doc ))
1656
+ {
1657
+ AttVal* av;
1658
+ /* Table must have a 'SUMMARY' describing the purpose of the table */
1659
+ for (av = node->attributes; av != NULL; av = av->next)
1660
+ {
1661
+ if ( attrIsSUMMARY(av) )
1662
+ {
1663
+ if ( hasValue(av) )
1664
+ {
1665
+ HasSummary = yes;
1666
+
1667
+ if (AttrContains(av, "summary") &&
1668
+ AttrContains(av, "table"))
1669
+ {
1670
+ TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_PLACEHOLDER );
1671
+ }
1672
+ }
1673
+
1674
+ if ( av->value == NULL || TY_(tmbstrlen)(av->value) == 0 )
1675
+ {
1676
+ HasSummary = yes;
1677
+ TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_NULL );
1678
+ }
1679
+ else if ( IsWhitespace(av->value) && TY_(tmbstrlen)(av->value) > 0 )
1680
+ {
1681
+ HasSummary = yes;
1682
+ TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_SPACES );
1683
+ }
1684
+ }
1685
+ }
1686
+
1687
+ /* TABLE must have content. */
1688
+ if (node->content == NULL)
1689
+ {
1690
+ TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS);
1691
+
1692
+ return;
1693
+ }
1694
+ }
1695
+
1696
+ if (Level1_Enabled( doc ))
1697
+ {
1698
+ /* Checks for multiple headers */
1699
+ CheckMultiHeaders( doc, node );
1700
+ }
1701
+
1702
+ if (Level2_Enabled( doc ))
1703
+ {
1704
+ /* Table must have a CAPTION describing the purpose of the table */
1705
+ if ( nodeIsCAPTION(node->content) )
1706
+ {
1707
+ TNode = node->content;
1708
+
1709
+ if (TNode->content && TNode->content->tag == NULL)
1710
+ {
1711
+ word = getTextNodeClear( doc, TNode);
1712
+ }
1713
+
1714
+ if ( !IsWhitespace(word) )
1715
+ {
1716
+ HasCaption = yes;
1717
+ }
1718
+ }
1719
+
1720
+ if (HasCaption == no)
1721
+ {
1722
+ TY_(ReportAccessError)( doc, node, TABLE_MISSING_CAPTION);
1723
+ }
1724
+ }
1725
+
1726
+
1727
+ if (node->content != NULL)
1728
+ {
1729
+ if ( nodeIsCAPTION(node->content) && nodeIsTR(node->content->next) )
1730
+ {
1731
+ CheckColumns( doc, node->content->next );
1732
+ }
1733
+ else if ( nodeIsTR(node->content) )
1734
+ {
1735
+ CheckColumns( doc, node->content );
1736
+ }
1737
+ }
1738
+
1739
+ if ( ! doc->access.HasValidColumnHeaders )
1740
+ {
1741
+ if (node->content != NULL)
1742
+ {
1743
+ if ( nodeIsCAPTION(node->content) && nodeIsTR(node->content->next) )
1744
+ {
1745
+ CheckRows( doc, node->content->next);
1746
+ }
1747
+ else if ( nodeIsTR(node->content) )
1748
+ {
1749
+ CheckRows( doc, node->content);
1750
+ }
1751
+ }
1752
+ }
1753
+
1754
+
1755
+ if (Level3_Enabled( doc ))
1756
+ {
1757
+ /* Suppress warning for missing 'SUMMARY for HTML 2.0 and HTML 3.2 */
1758
+ if (HasSummary == no)
1759
+ {
1760
+ TY_(ReportAccessError)( doc, node, TABLE_MISSING_SUMMARY);
1761
+ }
1762
+ }
1763
+
1764
+ if (Level2_Enabled( doc ))
1765
+ {
1766
+ if (node->content != NULL)
1767
+ {
1768
+ temp = node->content;
1769
+
1770
+ while (temp != NULL)
1771
+ {
1772
+ if ( nodeIsTR(temp) )
1773
+ {
1774
+ numTR++;
1775
+ }
1776
+
1777
+ temp = temp->next;
1778
+ }
1779
+
1780
+ if (numTR == 1)
1781
+ {
1782
+ TY_(ReportAccessWarning)( doc, node, LAYOUT_TABLES_LINEARIZE_PROPERLY);
1783
+ }
1784
+ }
1785
+
1786
+ if ( doc->access.HasTH )
1787
+ {
1788
+ TY_(ReportAccessWarning)( doc, node, LAYOUT_TABLE_INVALID_MARKUP);
1789
+ }
1790
+ }
1791
+
1792
+ if (Level1_Enabled( doc ))
1793
+ {
1794
+ if ( doc->access.CheckedHeaders == 2 )
1795
+ {
1796
+ if ( !doc->access.HasValidRowHeaders &&
1797
+ !doc->access.HasValidColumnHeaders &&
1798
+ !doc->access.HasInvalidRowHeader &&
1799
+ !doc->access.HasInvalidColumnHeader )
1800
+ {
1801
+ TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS);
1802
+ }
1803
+
1804
+ if ( !doc->access.HasValidRowHeaders &&
1805
+ doc->access.HasInvalidRowHeader )
1806
+ {
1807
+ TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS_ROW);
1808
+ }
1809
+
1810
+ if ( !doc->access.HasValidColumnHeaders &&
1811
+ doc->access.HasInvalidColumnHeader )
1812
+ {
1813
+ TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS_COLUMN);
1814
+ }
1815
+ }
1816
+ }
1817
+ }
1818
+
1819
+
1820
+ /***************************************************
1821
+ * CheckASCII
1822
+ *
1823
+ * Checks for valid text equivalents for XMP and PRE
1824
+ * elements for ASCII art. Ensures that there is
1825
+ * a skip over link to skip multi-lined ASCII art.
1826
+ ***************************************************/
1827
+
1828
+ static void CheckASCII( TidyDocImpl* doc, Node* node )
1829
+ {
1830
+ Node* temp1;
1831
+ Node* temp2;
1832
+
1833
+ tmbstr skipOver = NULL;
1834
+ Bool IsAscii = no;
1835
+ int HasSkipOverLink = 0;
1836
+
1837
+ uint i, x;
1838
+ int newLines = -1;
1839
+ tmbchar compareLetter;
1840
+ int matchingCount = 0;
1841
+ AttVal* av;
1842
+
1843
+ if (Level1_Enabled( doc ) && node->content)
1844
+ {
1845
+ /*
1846
+ Checks the text within the PRE and XMP tags to see if ascii
1847
+ art is present
1848
+ */
1849
+ for (i = node->content->start + 1; i < node->content->end; i++)
1850
+ {
1851
+ matchingCount = 0;
1852
+
1853
+ /* Counts the number of lines of text */
1854
+ if (doc->lexer->lexbuf[i] == '\n')
1855
+ {
1856
+ newLines++;
1857
+ }
1858
+
1859
+ compareLetter = doc->lexer->lexbuf[i];
1860
+
1861
+ /* Counts consecutive character matches */
1862
+ for (x = i; x < i + 5; x++)
1863
+ {
1864
+ if (doc->lexer->lexbuf[x] == compareLetter)
1865
+ {
1866
+ matchingCount++;
1867
+ }
1868
+
1869
+ else
1870
+ {
1871
+ break;
1872
+ }
1873
+ }
1874
+
1875
+ /* Must have at least 5 consecutive character matches */
1876
+ if (matchingCount >= 5)
1877
+ {
1878
+ break;
1879
+ }
1880
+ }
1881
+
1882
+ /*
1883
+ Must have more than 6 lines of text OR 5 or more consecutive
1884
+ letters that are the same for there to be ascii art
1885
+ */
1886
+ if (newLines >= 6 || matchingCount >= 5)
1887
+ {
1888
+ IsAscii = yes;
1889
+ }
1890
+
1891
+ /* Checks for skip over link if ASCII art is present */
1892
+ if (IsAscii == yes)
1893
+ {
1894
+ if (node->prev != NULL && node->prev->prev != NULL)
1895
+ {
1896
+ temp1 = node->prev->prev;
1897
+
1898
+ /* Checks for 'HREF' attribute */
1899
+ for (av = temp1->attributes; av != NULL; av = av->next)
1900
+ {
1901
+ if ( attrIsHREF(av) && hasValue(av) )
1902
+ {
1903
+ skipOver = av->value;
1904
+ HasSkipOverLink++;
1905
+ }
1906
+ }
1907
+ }
1908
+ }
1909
+ }
1910
+
1911
+ if (Level2_Enabled( doc ))
1912
+ {
1913
+ /*
1914
+ Checks for A element following PRE to ensure proper skipover link
1915
+ only if there is an A element preceding PRE.
1916
+ */
1917
+ if (HasSkipOverLink == 1)
1918
+ {
1919
+ if ( nodeIsA(node->next) )
1920
+ {
1921
+ temp2 = node->next;
1922
+
1923
+ /* Checks for 'NAME' attribute */
1924
+ for (av = temp2->attributes; av != NULL; av = av->next)
1925
+ {
1926
+ if ( attrIsNAME(av) && hasValue(av) )
1927
+ {
1928
+ /*
1929
+ Value within the 'HREF' attribute must be the same
1930
+ as the value within the 'NAME' attribute for valid
1931
+ skipover.
1932
+ */
1933
+ if ( strstr(skipOver, av->value) != NULL )
1934
+ {
1935
+ HasSkipOverLink++;
1936
+ }
1937
+ }
1938
+ }
1939
+ }
1940
+ }
1941
+
1942
+ if (IsAscii == yes)
1943
+ {
1944
+ TY_(ReportAccessError)( doc, node, ASCII_REQUIRES_DESCRIPTION);
1945
+ if (Level3_Enabled( doc ) && (HasSkipOverLink < 2))
1946
+ TY_(ReportAccessError)( doc, node, SKIPOVER_ASCII_ART);
1947
+ }
1948
+
1949
+ }
1950
+ }
1951
+
1952
+
1953
+ /***********************************************************
1954
+ * CheckFormControls
1955
+ *
1956
+ * <form> must have valid 'FOR' attribute, and <label> must
1957
+ * have valid 'ID' attribute for valid form control.
1958
+ ***********************************************************/
1959
+
1960
+ static void CheckFormControls( TidyDocImpl* doc, Node* node )
1961
+ {
1962
+ if ( !doc->access.HasValidFor &&
1963
+ doc->access.HasValidId )
1964
+ {
1965
+ TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY_FOR);
1966
+ }
1967
+
1968
+ if ( !doc->access.HasValidId &&
1969
+ doc->access.HasValidFor )
1970
+ {
1971
+ TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY_ID);
1972
+ }
1973
+
1974
+ if ( !doc->access.HasValidId &&
1975
+ !doc->access.HasValidFor )
1976
+ {
1977
+ TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY);
1978
+ }
1979
+ }
1980
+
1981
+
1982
+ /************************************************************
1983
+ * CheckLabel
1984
+ *
1985
+ * Check for valid 'FOR' attribute within the LABEL element
1986
+ ************************************************************/
1987
+
1988
+ static void CheckLabel( TidyDocImpl* doc, Node* node )
1989
+ {
1990
+ if (Level2_Enabled( doc ))
1991
+ {
1992
+ /* Checks for valid 'FOR' attribute */
1993
+ AttVal* av = attrGetFOR( node );
1994
+ if ( hasValue(av) )
1995
+ doc->access.HasValidFor = yes;
1996
+
1997
+ if ( ++doc->access.ForID == 2 )
1998
+ {
1999
+ doc->access.ForID = 0;
2000
+ CheckFormControls( doc, node );
2001
+ }
2002
+ }
2003
+ }
2004
+
2005
+
2006
+ /************************************************************
2007
+ * CheckInputLabel
2008
+ *
2009
+ * Checks for valid 'ID' attribute within the INPUT element.
2010
+ * Checks to see if there is a LABEL directly before
2011
+ * or after the INPUT element determined by the 'TYPE'.
2012
+ * Each INPUT element must have a LABEL describing the form.
2013
+ ************************************************************/
2014
+
2015
+ static void CheckInputLabel( TidyDocImpl* doc, Node* node )
2016
+ {
2017
+ if (Level2_Enabled( doc ))
2018
+ {
2019
+ AttVal* av;
2020
+
2021
+ /* Checks attributes within the INPUT element */
2022
+ for (av = node->attributes; av != NULL; av = av->next)
2023
+ {
2024
+ /* Must have valid 'ID' value */
2025
+ if ( attrIsID(av) && hasValue(av) )
2026
+ doc->access.HasValidId = yes;
2027
+ }
2028
+
2029
+ if ( ++doc->access.ForID == 2 )
2030
+ {
2031
+ doc->access.ForID = 0;
2032
+ CheckFormControls( doc, node );
2033
+ }
2034
+ }
2035
+ }
2036
+
2037
+
2038
+ /***************************************************************
2039
+ * CheckInputAttributes
2040
+ *
2041
+ * INPUT element must have a valid 'ALT' attribute if the
2042
+ * 'VALUE' attribute is present.
2043
+ ***************************************************************/
2044
+
2045
+ static void CheckInputAttributes( TidyDocImpl* doc, Node* node )
2046
+ {
2047
+ Bool HasAlt = no;
2048
+ Bool MustHaveAlt = no;
2049
+ AttVal* av;
2050
+
2051
+ /* Checks attributes within the INPUT element */
2052
+ for (av = node->attributes; av != NULL; av = av->next)
2053
+ {
2054
+ /* 'VALUE' must be found if the 'TYPE' is 'text' or 'checkbox' */
2055
+ if ( attrIsTYPE(av) && hasValue(av) )
2056
+ {
2057
+ if (Level1_Enabled( doc ))
2058
+ {
2059
+ if (AttrValueIs(av, "image"))
2060
+ {
2061
+ MustHaveAlt = yes;
2062
+ }
2063
+ }
2064
+
2065
+ }
2066
+
2067
+ if ( attrIsALT(av) && hasValue(av) )
2068
+ {
2069
+ HasAlt = yes;
2070
+ }
2071
+ }
2072
+
2073
+ if ( MustHaveAlt && !HasAlt )
2074
+ {
2075
+ TY_(ReportAccessError)( doc, node, IMG_BUTTON_MISSING_ALT );
2076
+ }
2077
+
2078
+ }
2079
+
2080
+
2081
+ /***************************************************************
2082
+ * CheckFrameSet
2083
+ *
2084
+ * Frameset must have valid NOFRAME section. Must contain some
2085
+ * text but must not contain information telling user to update
2086
+ * browsers,
2087
+ ***************************************************************/
2088
+
2089
+ static void CheckFrameSet( TidyDocImpl* doc, Node* node )
2090
+ {
2091
+ Node* temp;
2092
+ Bool HasNoFrames = no;
2093
+
2094
+ if (Level1_Enabled( doc ))
2095
+ {
2096
+ if ( doc->badAccess & BA_INVALID_LINK_NOFRAMES )
2097
+ {
2098
+ TY_(ReportAccessError)( doc, node, NOFRAMES_INVALID_LINK);
2099
+ doc->badAccess &= ~BA_INVALID_LINK_NOFRAMES; /* emit only once */
2100
+ }
2101
+ for ( temp = node->content; temp != NULL ; temp = temp->next )
2102
+ {
2103
+ if ( nodeIsNOFRAMES(temp) )
2104
+ {
2105
+ HasNoFrames = yes;
2106
+
2107
+ if ( temp->content && nodeIsP(temp->content->content) )
2108
+ {
2109
+ Node* para = temp->content->content;
2110
+ if ( TY_(nodeIsText)(para->content) )
2111
+ {
2112
+ ctmbstr word = textFromOneNode( doc, para->content );
2113
+ if ( word && strstr(word, "browser") != NULL )
2114
+ TY_(ReportAccessError)( doc, para, NOFRAMES_INVALID_CONTENT );
2115
+ }
2116
+ }
2117
+ else if (temp->content == NULL)
2118
+ TY_(ReportAccessError)( doc, temp, NOFRAMES_INVALID_NO_VALUE);
2119
+ else if ( temp->content &&
2120
+ IsWhitespace(textFromOneNode(doc, temp->content)) )
2121
+ TY_(ReportAccessError)( doc, temp, NOFRAMES_INVALID_NO_VALUE);
2122
+ }
2123
+ }
2124
+
2125
+ if (HasNoFrames == no)
2126
+ TY_(ReportAccessError)( doc, node, FRAME_MISSING_NOFRAMES);
2127
+ }
2128
+ }
2129
+
2130
+
2131
+ /***********************************************************
2132
+ * CheckHeaderNesting
2133
+ *
2134
+ * Checks for heading increases and decreases. Headings must
2135
+ * not increase by more than one header level, but may
2136
+ * decrease at from any level to any level. Text within
2137
+ * headers must not be more than 20 words in length.
2138
+ ***********************************************************/
2139
+
2140
+ static void CheckHeaderNesting( TidyDocImpl* doc, Node* node )
2141
+ {
2142
+ Node* temp;
2143
+ uint i;
2144
+ int numWords = 1;
2145
+
2146
+ Bool IsValidIncrease = no;
2147
+ Bool NeedsDescription = no;
2148
+
2149
+ if (Level2_Enabled( doc ))
2150
+ {
2151
+ /*
2152
+ Text within header element cannot contain more than 20 words without
2153
+ a separate description
2154
+ */
2155
+ if (node->content != NULL && node->content->tag == NULL)
2156
+ {
2157
+ ctmbstr word = textFromOneNode( doc, node->content);
2158
+
2159
+ for (i = 0; i < TY_(tmbstrlen)(word); i++)
2160
+ {
2161
+ if (word[i] == ' ')
2162
+ {
2163
+ numWords++;
2164
+ }
2165
+ }
2166
+
2167
+ if (numWords > 20)
2168
+ {
2169
+ NeedsDescription = yes;
2170
+ }
2171
+ }
2172
+
2173
+ /* Header following must be same level or same plus 1 for
2174
+ ** valid heading increase size. E.g. H1 -> H1, H2. H3 -> H3, H4
2175
+ */
2176
+ if ( TY_(nodeIsHeader)(node) )
2177
+ {
2178
+ uint level = TY_(nodeHeaderLevel)( node );
2179
+ IsValidIncrease = yes;
2180
+
2181
+ for ( temp = node->next; temp != NULL; temp = temp->next )
2182
+ {
2183
+ uint nested = TY_(nodeHeaderLevel)( temp );
2184
+ if ( nested >= level )
2185
+ {
2186
+ IsValidIncrease = ( nested <= level + 1 );
2187
+ break;
2188
+ }
2189
+ }
2190
+ }
2191
+
2192
+ if ( !IsValidIncrease )
2193
+ TY_(ReportAccessWarning)( doc, node, HEADERS_IMPROPERLY_NESTED );
2194
+
2195
+ if ( NeedsDescription )
2196
+ TY_(ReportAccessWarning)( doc, node, HEADER_USED_FORMAT_TEXT );
2197
+ }
2198
+ }
2199
+
2200
+
2201
+ /*************************************************************
2202
+ * CheckParagraphHeader
2203
+ *
2204
+ * Checks to ensure that P elements are not headings. Must be
2205
+ * greater than 10 words in length, and they must not be in bold,
2206
+ * or italics, or underlined, etc.
2207
+ *************************************************************/
2208
+
2209
+ static void CheckParagraphHeader( TidyDocImpl* doc, Node* node )
2210
+ {
2211
+ Bool IsNotHeader = no;
2212
+ Node* temp;
2213
+
2214
+ if (Level2_Enabled( doc ))
2215
+ {
2216
+ /* Cannot contain text formatting elements */
2217
+ if (node->content != NULL)
2218
+ {
2219
+ if (node->content->tag != NULL)
2220
+ {
2221
+ temp = node->content;
2222
+
2223
+ while (temp != NULL)
2224
+ {
2225
+ if (temp->tag == NULL)
2226
+ {
2227
+ IsNotHeader = yes;
2228
+ break;
2229
+ }
2230
+
2231
+ temp = temp->next;
2232
+ }
2233
+ }
2234
+
2235
+ if ( !IsNotHeader )
2236
+ {
2237
+ if ( nodeIsSTRONG(node->content) )
2238
+ {
2239
+ TY_(ReportAccessWarning)( doc, node, POTENTIAL_HEADER_BOLD);
2240
+ }
2241
+
2242
+ if ( nodeIsU(node->content) )
2243
+ {
2244
+ TY_(ReportAccessWarning)( doc, node, POTENTIAL_HEADER_UNDERLINE);
2245
+ }
2246
+
2247
+ if ( nodeIsEM(node->content) )
2248
+ {
2249
+ TY_(ReportAccessWarning)( doc, node, POTENTIAL_HEADER_ITALICS);
2250
+ }
2251
+ }
2252
+ }
2253
+ }
2254
+ }
2255
+
2256
+
2257
+ /****************************************************************
2258
+ * CheckEmbed
2259
+ *
2260
+ * Checks to see if 'SRC' is a multimedia type. Must have
2261
+ * syncronized captions if used.
2262
+ ****************************************************************/
2263
+
2264
+ static void CheckEmbed( TidyDocImpl* doc, Node* node )
2265
+ {
2266
+ if (Level1_Enabled( doc ))
2267
+ {
2268
+ AttVal* av = attrGetSRC( node );
2269
+ if ( hasValue(av) && IsValidMediaExtension(av->value) )
2270
+ {
2271
+ TY_(ReportAccessError)( doc, node, MULTIMEDIA_REQUIRES_TEXT );
2272
+ }
2273
+ }
2274
+ }
2275
+
2276
+
2277
+ /*********************************************************************
2278
+ * CheckHTMLAccess
2279
+ *
2280
+ * Checks HTML element for valid 'LANG' attribute. Must be a valid
2281
+ * language. ie. 'fr' or 'en'
2282
+ ********************************************************************/
2283
+
2284
+ static void CheckHTMLAccess( TidyDocImpl* doc, Node* node )
2285
+ {
2286
+ Bool ValidLang = no;
2287
+
2288
+ if (Level3_Enabled( doc ))
2289
+ {
2290
+ AttVal* av = attrGetLANG( node );
2291
+ if ( av )
2292
+ {
2293
+ ValidLang = yes;
2294
+ if ( !hasValue(av) )
2295
+ TY_(ReportAccessError)( doc, node, LANGUAGE_INVALID );
2296
+ }
2297
+ if ( !ValidLang )
2298
+ TY_(ReportAccessError)( doc, node, LANGUAGE_NOT_IDENTIFIED );
2299
+ }
2300
+ }
2301
+
2302
+
2303
+ /********************************************************
2304
+ * CheckBlink
2305
+ *
2306
+ * Document must not contain the BLINK element.
2307
+ * It is invalid HTML/XHTML.
2308
+ *********************************************************/
2309
+
2310
+ static void CheckBlink( TidyDocImpl* doc, Node* node )
2311
+ {
2312
+
2313
+ if (Level2_Enabled( doc ))
2314
+ {
2315
+ /* Checks to see if text is found within the BLINK element. */
2316
+ if ( TY_(nodeIsText)(node->content) )
2317
+ {
2318
+ ctmbstr word = textFromOneNode( doc, node->content );
2319
+ if ( !IsWhitespace(word) )
2320
+ {
2321
+ TY_(ReportAccessError)( doc, node, REMOVE_BLINK_MARQUEE );
2322
+ }
2323
+ }
2324
+ }
2325
+ }
2326
+
2327
+
2328
+ /********************************************************
2329
+ * CheckMarquee
2330
+ *
2331
+ * Document must not contain the MARQUEE element.
2332
+ * It is invalid HTML/XHTML.
2333
+ ********************************************************/
2334
+
2335
+
2336
+ static void CheckMarquee( TidyDocImpl* doc, Node* node )
2337
+ {
2338
+ if (Level2_Enabled( doc ))
2339
+ {
2340
+ /* Checks to see if there is text in between the MARQUEE element */
2341
+ if ( TY_(nodeIsText)(node) )
2342
+ {
2343
+ ctmbstr word = textFromOneNode( doc, node->content);
2344
+ if ( !IsWhitespace(word) )
2345
+ {
2346
+ TY_(ReportAccessError)( doc, node, REMOVE_BLINK_MARQUEE );
2347
+ }
2348
+ }
2349
+ }
2350
+ }
2351
+
2352
+
2353
+ /**********************************************************
2354
+ * CheckLink
2355
+ *
2356
+ * 'REL' attribute within the LINK element must not contain
2357
+ * 'stylesheet'. HTML/XHTML document is unreadable when
2358
+ * style sheets are applied. -- CPR huh?
2359
+ **********************************************************/
2360
+
2361
+ static void CheckLink( TidyDocImpl* doc, Node* node )
2362
+ {
2363
+ Bool HasRel = no;
2364
+ Bool HasType = no;
2365
+
2366
+ if (Level1_Enabled( doc ))
2367
+ {
2368
+ AttVal* av;
2369
+ /* Check for valid 'REL' and 'TYPE' attribute */
2370
+ for (av = node->attributes; av != NULL; av = av->next)
2371
+ {
2372
+ if ( attrIsREL(av) && hasValue(av) )
2373
+ {
2374
+ if (AttrContains(av, "stylesheet"))
2375
+ HasRel = yes;
2376
+ }
2377
+
2378
+ if ( attrIsTYPE(av) && hasValue(av) )
2379
+ {
2380
+ HasType = yes;
2381
+ }
2382
+ }
2383
+
2384
+ if (HasRel && HasType)
2385
+ TY_(ReportAccessWarning)( doc, node, STYLESHEETS_REQUIRE_TESTING_LINK );
2386
+ }
2387
+ }
2388
+
2389
+
2390
+ /*******************************************************
2391
+ * CheckStyle
2392
+ *
2393
+ * Document must not contain STYLE element. HTML/XHTML
2394
+ * document is unreadable when style sheets are applied.
2395
+ *******************************************************/
2396
+
2397
+ static void CheckStyle( TidyDocImpl* doc, Node* node )
2398
+ {
2399
+ if (Level1_Enabled( doc ))
2400
+ {
2401
+ TY_(ReportAccessWarning)( doc, node, STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT );
2402
+ }
2403
+ }
2404
+
2405
+
2406
+ /*************************************************************
2407
+ * DynamicContent
2408
+ *
2409
+ * Verify that equivalents of dynamic content are updated and
2410
+ * available as often as the dynamic content.
2411
+ *************************************************************/
2412
+
2413
+
2414
+ static void DynamicContent( TidyDocImpl* doc, Node* node )
2415
+ {
2416
+ if (Level1_Enabled( doc ))
2417
+ {
2418
+ uint msgcode = 0;
2419
+ if ( nodeIsAPPLET(node) )
2420
+ msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET;
2421
+ else if ( nodeIsSCRIPT(node) )
2422
+ msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT;
2423
+ else if ( nodeIsOBJECT(node) )
2424
+ msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT;
2425
+
2426
+ if ( msgcode )
2427
+ TY_(ReportAccessWarning)( doc, node, msgcode );
2428
+ }
2429
+ }
2430
+
2431
+
2432
+ /*************************************************************
2433
+ * ProgrammaticObjects
2434
+ *
2435
+ * Verify that the page is usable when programmatic objects
2436
+ * are disabled.
2437
+ *************************************************************/
2438
+
2439
+ static void ProgrammaticObjects( TidyDocImpl* doc, Node* node )
2440
+ {
2441
+ if (Level1_Enabled( doc ))
2442
+ {
2443
+ int msgcode = 0;
2444
+ if ( nodeIsSCRIPT(node) )
2445
+ msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT;
2446
+ else if ( nodeIsOBJECT(node) )
2447
+ msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT;
2448
+ else if ( nodeIsEMBED(node) )
2449
+ msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED;
2450
+ else if ( nodeIsAPPLET(node) )
2451
+ msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET;
2452
+
2453
+ if ( msgcode )
2454
+ TY_(ReportAccessWarning)( doc, node, msgcode );
2455
+ }
2456
+ }
2457
+
2458
+
2459
+ /*************************************************************
2460
+ * AccessibleCompatible
2461
+ *
2462
+ * Verify that programmatic objects are directly accessible.
2463
+ *************************************************************/
2464
+
2465
+ static void AccessibleCompatible( TidyDocImpl* doc, Node* node )
2466
+ {
2467
+ if (Level1_Enabled( doc ))
2468
+ {
2469
+ int msgcode = 0;
2470
+ if ( nodeIsSCRIPT(node) )
2471
+ msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT;
2472
+ else if ( nodeIsOBJECT(node) )
2473
+ msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT;
2474
+ else if ( nodeIsEMBED(node) )
2475
+ msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED;
2476
+ else if ( nodeIsAPPLET(node) )
2477
+ msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET;
2478
+
2479
+ if ( msgcode )
2480
+ TY_(ReportAccessWarning)( doc, node, msgcode );
2481
+ }
2482
+ }
2483
+
2484
+
2485
+ /********************************************************
2486
+ * WordCount
2487
+ *
2488
+ * Counts the number of words in the document. Must have
2489
+ * more than 3 words to verify changes in natural
2490
+ * language of document.
2491
+ *
2492
+ * CPR - Not sure what intent is here, but this
2493
+ * routine has nothing to do with changes in language.
2494
+ * It seems like a bad idea to emit this message for
2495
+ * every document with _more_ than 3 words!
2496
+ ********************************************************/
2497
+ #if 0
2498
+ static int WordCount( TidyDocImpl* doc, Node* node )
2499
+ {
2500
+ int wc = 0;
2501
+
2502
+ if (Level1_Enabled( doc ))
2503
+ {
2504
+ /* Count the number of words found within a text node */
2505
+ if ( TY_(nodeIsText)( node ) )
2506
+ {
2507
+ tmbchar ch;
2508
+ ctmbstr word = textFromOneNode( doc, node );
2509
+ if ( !IsWhitespace(word) )
2510
+ {
2511
+ ++wc;
2512
+ while ( (ch = *word++) && wc < 5 )
2513
+ {
2514
+ if ( ch == ' ')
2515
+ ++wc;
2516
+ }
2517
+ }
2518
+ }
2519
+
2520
+ for ( node = node->content; wc < 5 && node; node = node->next )
2521
+ {
2522
+ wc += WordCount( doc, node );
2523
+ }
2524
+ }
2525
+ return wc;
2526
+ }
2527
+ #endif
2528
+
2529
+ /**************************************************
2530
+ * CheckFlicker
2531
+ *
2532
+ * Verify that the page does not cause flicker.
2533
+ **************************************************/
2534
+
2535
+ static void CheckFlicker( TidyDocImpl* doc, Node* node )
2536
+ {
2537
+ if (Level1_Enabled( doc ))
2538
+ {
2539
+ int msgcode = 0;
2540
+ if ( nodeIsSCRIPT(node) )
2541
+ msgcode = REMOVE_FLICKER_SCRIPT;
2542
+ else if ( nodeIsOBJECT(node) )
2543
+ msgcode = REMOVE_FLICKER_OBJECT;
2544
+ else if ( nodeIsEMBED(node) )
2545
+ msgcode = REMOVE_FLICKER_EMBED;
2546
+ else if ( nodeIsAPPLET(node) )
2547
+ msgcode = REMOVE_FLICKER_APPLET;
2548
+
2549
+ /* Checks for animated gif within the <img> tag. */
2550
+ else if ( nodeIsIMG(node) )
2551
+ {
2552
+ AttVal* av = attrGetSRC( node );
2553
+ if ( hasValue(av) )
2554
+ {
2555
+ tmbchar ext[20];
2556
+ GetFileExtension( av->value, ext, sizeof(ext) );
2557
+ if ( TY_(tmbstrcasecmp)(ext, ".gif") == 0 )
2558
+ msgcode = REMOVE_FLICKER_ANIMATED_GIF;
2559
+ }
2560
+ }
2561
+
2562
+ if ( msgcode )
2563
+ TY_(ReportAccessWarning)( doc, node, msgcode );
2564
+ }
2565
+ }
2566
+
2567
+
2568
+ /**********************************************************
2569
+ * CheckDeprecated
2570
+ *
2571
+ * APPLET, BASEFONT, CENTER, FONT, ISINDEX,
2572
+ * S, STRIKE, and U should not be used. Becomes deprecated
2573
+ * HTML if any of the above are used.
2574
+ **********************************************************/
2575
+
2576
+ static void CheckDeprecated( TidyDocImpl* doc, Node* node )
2577
+ {
2578
+ if (Level2_Enabled( doc ))
2579
+ {
2580
+ int msgcode = 0;
2581
+ if ( nodeIsAPPLET(node) )
2582
+ msgcode = REPLACE_DEPRECATED_HTML_APPLET;
2583
+ else if ( nodeIsBASEFONT(node) )
2584
+ msgcode = REPLACE_DEPRECATED_HTML_BASEFONT;
2585
+ else if ( nodeIsCENTER(node) )
2586
+ msgcode = REPLACE_DEPRECATED_HTML_CENTER;
2587
+ else if ( nodeIsDIR(node) )
2588
+ msgcode = REPLACE_DEPRECATED_HTML_DIR;
2589
+ else if ( nodeIsFONT(node) )
2590
+ msgcode = REPLACE_DEPRECATED_HTML_FONT;
2591
+ else if ( nodeIsISINDEX(node) )
2592
+ msgcode = REPLACE_DEPRECATED_HTML_ISINDEX;
2593
+ else if ( nodeIsMENU(node) )
2594
+ msgcode = REPLACE_DEPRECATED_HTML_MENU;
2595
+ else if ( nodeIsS(node) )
2596
+ msgcode = REPLACE_DEPRECATED_HTML_S;
2597
+ else if ( nodeIsSTRIKE(node) )
2598
+ msgcode = REPLACE_DEPRECATED_HTML_STRIKE;
2599
+ else if ( nodeIsU(node) )
2600
+ msgcode = REPLACE_DEPRECATED_HTML_U;
2601
+
2602
+ if ( msgcode )
2603
+ TY_(ReportAccessError)( doc, node, msgcode );
2604
+ }
2605
+ }
2606
+
2607
+
2608
+ /************************************************************
2609
+ * CheckScriptKeyboardAccessible
2610
+ *
2611
+ * Elements must have a device independent event handler if
2612
+ * they have any of the following device dependent event
2613
+ * handlers.
2614
+ ************************************************************/
2615
+
2616
+ static void CheckScriptKeyboardAccessible( TidyDocImpl* doc, Node* node )
2617
+ {
2618
+ Node* content;
2619
+ int HasOnMouseDown = 0;
2620
+ int HasOnMouseUp = 0;
2621
+ int HasOnClick = 0;
2622
+ int HasOnMouseOut = 0;
2623
+ int HasOnMouseOver = 0;
2624
+ int HasOnMouseMove = 0;
2625
+
2626
+ if (Level2_Enabled( doc ))
2627
+ {
2628
+ AttVal* av;
2629
+ /* Checks all elements for their attributes */
2630
+ for (av = node->attributes; av != NULL; av = av->next)
2631
+ {
2632
+ /* Must also have 'ONKEYDOWN' attribute with 'ONMOUSEDOWN' */
2633
+ if ( attrIsOnMOUSEDOWN(av) )
2634
+ HasOnMouseDown++;
2635
+
2636
+ /* Must also have 'ONKEYUP' attribute with 'ONMOUSEUP' */
2637
+ if ( attrIsOnMOUSEUP(av) )
2638
+ HasOnMouseUp++;
2639
+
2640
+ /* Must also have 'ONKEYPRESS' attribute with 'ONCLICK' */
2641
+ if ( attrIsOnCLICK(av) )
2642
+ HasOnClick++;
2643
+
2644
+ /* Must also have 'ONBLUR' attribute with 'ONMOUSEOUT' */
2645
+ if ( attrIsOnMOUSEOUT(av) )
2646
+ HasOnMouseOut++;
2647
+
2648
+ if ( attrIsOnMOUSEOVER(av) )
2649
+ HasOnMouseOver++;
2650
+
2651
+ if ( attrIsOnMOUSEMOVE(av) )
2652
+ HasOnMouseMove++;
2653
+
2654
+ if ( attrIsOnKEYDOWN(av) )
2655
+ HasOnMouseDown++;
2656
+
2657
+ if ( attrIsOnKEYUP(av) )
2658
+ HasOnMouseUp++;
2659
+
2660
+ if ( attrIsOnKEYPRESS(av) )
2661
+ HasOnClick++;
2662
+
2663
+ if ( attrIsOnBLUR(av) )
2664
+ HasOnMouseOut++;
2665
+ }
2666
+
2667
+ if ( HasOnMouseDown == 1 )
2668
+ TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN);
2669
+
2670
+ if ( HasOnMouseUp == 1 )
2671
+ TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP);
2672
+
2673
+ if ( HasOnClick == 1 )
2674
+ TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK);
2675
+ if ( HasOnMouseOut == 1 )
2676
+ TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT);
2677
+
2678
+ if ( HasOnMouseOver == 1 )
2679
+ TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER);
2680
+
2681
+ if ( HasOnMouseMove == 1 )
2682
+ TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE);
2683
+
2684
+ /* Recursively check all child nodes.
2685
+ */
2686
+ for ( content = node->content; content != NULL; content = content->next )
2687
+ CheckScriptKeyboardAccessible( doc, content );
2688
+ }
2689
+ }
2690
+
2691
+
2692
+ /**********************************************************
2693
+ * CheckMetaData
2694
+ *
2695
+ * Must have at least one of these elements in the document.
2696
+ * META, LINK, TITLE or ADDRESS. <meta> must contain
2697
+ * a "content" attribute that doesn't contain a URL, and
2698
+ * an "http-Equiv" attribute that doesn't contain 'refresh'.
2699
+ **********************************************************/
2700
+
2701
+
2702
+ static Bool CheckMetaData( TidyDocImpl* doc, Node* node, Bool HasMetaData )
2703
+ {
2704
+ Bool HasHttpEquiv = no;
2705
+ Bool HasContent = no;
2706
+ Bool ContainsAttr = no;
2707
+
2708
+ if (Level2_Enabled( doc ))
2709
+ {
2710
+ if ( nodeIsMETA(node) )
2711
+ {
2712
+ AttVal* av;
2713
+ for (av = node->attributes; av != NULL; av = av->next)
2714
+ {
2715
+ if ( attrIsHTTP_EQUIV(av) && hasValue(av) )
2716
+ {
2717
+ ContainsAttr = yes;
2718
+
2719
+ /* Must not have an auto-refresh */
2720
+ if (AttrValueIs(av, "refresh"))
2721
+ {
2722
+ HasHttpEquiv = yes;
2723
+ TY_(ReportAccessError)( doc, node, REMOVE_AUTO_REFRESH );
2724
+ }
2725
+ }
2726
+
2727
+ if ( attrIsCONTENT(av) && hasValue(av) )
2728
+ {
2729
+ ContainsAttr = yes;
2730
+
2731
+ /* If the value is not an integer, then it must not be a URL */
2732
+ if ( TY_(tmbstrncmp)(av->value, "http:", 5) == 0)
2733
+ {
2734
+ HasContent = yes;
2735
+ TY_(ReportAccessError)( doc, node, REMOVE_AUTO_REDIRECT);
2736
+ }
2737
+ }
2738
+ }
2739
+
2740
+ if ( HasContent || HasHttpEquiv )
2741
+ {
2742
+ HasMetaData = yes;
2743
+ TY_(ReportAccessError)( doc, node, METADATA_MISSING_REDIRECT_AUTOREFRESH);
2744
+ }
2745
+ else
2746
+ {
2747
+ if ( ContainsAttr && !HasContent && !HasHttpEquiv )
2748
+ HasMetaData = yes;
2749
+ }
2750
+ }
2751
+
2752
+ if ( !HasMetaData &&
2753
+ nodeIsADDRESS(node) &&
2754
+ nodeIsA(node->content) )
2755
+ {
2756
+ HasMetaData = yes;
2757
+ }
2758
+
2759
+ if ( !HasMetaData &&
2760
+ !nodeIsTITLE(node) &&
2761
+ TY_(nodeIsText)(node->content) )
2762
+ {
2763
+ ctmbstr word = textFromOneNode( doc, node->content );
2764
+ if ( !IsWhitespace(word) )
2765
+ HasMetaData = yes;
2766
+ }
2767
+
2768
+ if( !HasMetaData && nodeIsLINK(node) )
2769
+ {
2770
+ AttVal* av = attrGetREL(node);
2771
+ if( !AttrContains(av, "stylesheet") )
2772
+ HasMetaData = yes;
2773
+ }
2774
+
2775
+ /* Check for MetaData */
2776
+ for ( node = node->content; node; node = node->next )
2777
+ {
2778
+ HasMetaData = CheckMetaData( doc, node, HasMetaData );
2779
+ }
2780
+ }
2781
+ return HasMetaData;
2782
+ }
2783
+
2784
+
2785
+ /*******************************************************
2786
+ * MetaDataPresent
2787
+ *
2788
+ * Determines if MetaData is present in document
2789
+ *******************************************************/
2790
+
2791
+ static void MetaDataPresent( TidyDocImpl* doc, Node* node )
2792
+ {
2793
+ if (Level2_Enabled( doc ))
2794
+ {
2795
+ TY_(ReportAccessError)( doc, node, METADATA_MISSING );
2796
+ }
2797
+ }
2798
+
2799
+
2800
+ /*****************************************************
2801
+ * CheckDocType
2802
+ *
2803
+ * Checks that every HTML/XHTML document contains a
2804
+ * '!DOCTYPE' before the root node. ie. <HTML>
2805
+ *****************************************************/
2806
+
2807
+ static void CheckDocType( TidyDocImpl* doc )
2808
+ {
2809
+ if (Level2_Enabled( doc ))
2810
+ {
2811
+ Node* DTnode = TY_(FindDocType)(doc);
2812
+
2813
+ /* If the doctype has been added by tidy, DTnode->end will be 0. */
2814
+ if (DTnode && DTnode->end != 0)
2815
+ {
2816
+ ctmbstr word = textFromOneNode( doc, DTnode);
2817
+ if ((strstr (word, "HTML PUBLIC") == NULL) &&
2818
+ (strstr (word, "html PUBLIC") == NULL))
2819
+ DTnode = NULL;
2820
+ }
2821
+ if (!DTnode)
2822
+ TY_(ReportAccessError)( doc, &doc->root, DOCTYPE_MISSING);
2823
+ }
2824
+ }
2825
+
2826
+
2827
+
2828
+ /********************************************************
2829
+ * CheckMapLinks
2830
+ *
2831
+ * Checks to see if an HREF for A element matches HREF
2832
+ * for AREA element. There must be an HREF attribute
2833
+ * of an A element for every HREF of an AREA element.
2834
+ ********************************************************/
2835
+
2836
+ static Bool urlMatch( ctmbstr url1, ctmbstr url2 )
2837
+ {
2838
+ /* TODO: Make host part case-insensitive and
2839
+ ** remainder case-sensitive.
2840
+ */
2841
+ return ( TY_(tmbstrcmp)( url1, url2 ) == 0 );
2842
+ }
2843
+
2844
+ static Bool FindLinkA( TidyDocImpl* doc, Node* node, ctmbstr url )
2845
+ {
2846
+ Bool found = no;
2847
+ for ( node = node->content; !found && node; node = node->next )
2848
+ {
2849
+ if ( nodeIsA(node) )
2850
+ {
2851
+ AttVal* href = attrGetHREF( node );
2852
+ found = ( hasValue(href) && urlMatch(url, href->value) );
2853
+ }
2854
+ else
2855
+ found = FindLinkA( doc, node, url );
2856
+ }
2857
+ return found;
2858
+ }
2859
+
2860
+ static void CheckMapLinks( TidyDocImpl* doc, Node* node )
2861
+ {
2862
+ Node* child;
2863
+
2864
+ if (!Level3_Enabled( doc ))
2865
+ return;
2866
+
2867
+ /* Stores the 'HREF' link of an AREA element within a MAP element */
2868
+ for ( child = node->content; child != NULL; child = child->next )
2869
+ {
2870
+ if ( nodeIsAREA(child) )
2871
+ {
2872
+ /* Checks for 'HREF' attribute */
2873
+ AttVal* href = attrGetHREF( child );
2874
+ if ( hasValue(href) &&
2875
+ !FindLinkA( doc, &doc->root, href->value ) )
2876
+ {
2877
+ TY_(ReportAccessError)( doc, node, IMG_MAP_CLIENT_MISSING_TEXT_LINKS );
2878
+ }
2879
+ }
2880
+ }
2881
+ }
2882
+
2883
+
2884
+ /****************************************************
2885
+ * CheckForStyleAttribute
2886
+ *
2887
+ * Checks all elements within the document to check
2888
+ * for the use of 'STYLE' attribute.
2889
+ ****************************************************/
2890
+
2891
+ static void CheckForStyleAttribute( TidyDocImpl* doc, Node* node )
2892
+ {
2893
+ Node* content;
2894
+ if (Level1_Enabled( doc ))
2895
+ {
2896
+ /* Must not contain 'STYLE' attribute */
2897
+ AttVal* style = attrGetSTYLE( node );
2898
+ if ( hasValue(style) )
2899
+ {
2900
+ TY_(ReportAccessWarning)( doc, node, STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR );
2901
+ }
2902
+ }
2903
+
2904
+ /* Recursively check all child nodes.
2905
+ */
2906
+ for ( content = node->content; content != NULL; content = content->next )
2907
+ CheckForStyleAttribute( doc, content );
2908
+ }
2909
+
2910
+
2911
+ /*****************************************************
2912
+ * CheckForListElements
2913
+ *
2914
+ * Checks document for list elements (<ol>, <ul>, <li>)
2915
+ *****************************************************/
2916
+
2917
+ static void CheckForListElements( TidyDocImpl* doc, Node* node )
2918
+ {
2919
+ if ( nodeIsLI(node) )
2920
+ {
2921
+ doc->access.ListElements++;
2922
+ }
2923
+ else if ( nodeIsOL(node) || nodeIsUL(node) )
2924
+ {
2925
+ doc->access.OtherListElements++;
2926
+ }
2927
+
2928
+ for ( node = node->content; node != NULL; node = node->next )
2929
+ {
2930
+ CheckForListElements( doc, node );
2931
+ }
2932
+ }
2933
+
2934
+
2935
+ /******************************************************
2936
+ * CheckListUsage
2937
+ *
2938
+ * Ensures that lists are properly used. <ol> and <ul>
2939
+ * must contain <li> within itself, and <li> must not be
2940
+ * by itself.
2941
+ ******************************************************/
2942
+
2943
+ static void CheckListUsage( TidyDocImpl* doc, Node* node )
2944
+ {
2945
+ int msgcode = 0;
2946
+
2947
+ if (!Level2_Enabled( doc ))
2948
+ return;
2949
+
2950
+ if ( nodeIsOL(node) )
2951
+ msgcode = LIST_USAGE_INVALID_OL;
2952
+ else if ( nodeIsUL(node) )
2953
+ msgcode = LIST_USAGE_INVALID_UL;
2954
+
2955
+ if ( msgcode )
2956
+ {
2957
+ /*
2958
+ ** Check that OL/UL
2959
+ ** a) has LI child,
2960
+ ** b) was not added by Tidy parser
2961
+ ** IFF OL/UL node is implicit
2962
+ */
2963
+ if ( !nodeIsLI(node->content) ) {
2964
+ TY_(ReportAccessWarning)( doc, node, msgcode );
2965
+ } else if ( node->implicit ) { /* if a tidy added node */
2966
+ TY_(ReportAccessWarning)( doc, node, LIST_USAGE_INVALID_LI );
2967
+ }
2968
+ }
2969
+ else if ( nodeIsLI(node) )
2970
+ {
2971
+ /* Check that LI parent
2972
+ ** a) exists,
2973
+ ** b) is either OL or UL
2974
+ ** IFF the LI parent was added by Tidy
2975
+ ** ie, if it is marked 'implicit', then
2976
+ ** emit warnings LIST_USAGE_INVALID_UL or
2977
+ ** warning LIST_USAGE_INVALID_OL tests
2978
+ */
2979
+ if ( node->parent == NULL ||
2980
+ ( !nodeIsOL(node->parent) && !nodeIsUL(node->parent) ) )
2981
+ {
2982
+ TY_(ReportAccessWarning)( doc, node, LIST_USAGE_INVALID_LI );
2983
+ } else if ( node->implicit && node->parent &&
2984
+ ( nodeIsOL(node->parent) || nodeIsUL(node->parent) ) ) {
2985
+ /* if tidy added LI node, then */
2986
+ msgcode = nodeIsUL(node->parent) ?
2987
+ LIST_USAGE_INVALID_UL : LIST_USAGE_INVALID_OL;
2988
+ TY_(ReportAccessWarning)( doc, node, msgcode );
2989
+ }
2990
+ }
2991
+ }
2992
+
2993
+ /************************************************************
2994
+ * InitAccessibilityChecks
2995
+ *
2996
+ * Initializes the AccessibilityChecks variables as necessary
2997
+ ************************************************************/
2998
+
2999
+ static void InitAccessibilityChecks( TidyDocImpl* doc, int level123 )
3000
+ {
3001
+ TidyClearMemory( &doc->access, sizeof(doc->access) );
3002
+ doc->access.PRIORITYCHK = level123;
3003
+ }
3004
+
3005
+ /************************************************************
3006
+ * CleanupAccessibilityChecks
3007
+ *
3008
+ * Cleans up the AccessibilityChecks variables as necessary
3009
+ ************************************************************/
3010
+
3011
+
3012
+ static void FreeAccessibilityChecks( TidyDocImpl* ARG_UNUSED(doc) )
3013
+ {
3014
+ /* free any memory allocated for the lists
3015
+
3016
+ Linked List of Links not used. Just search document as
3017
+ AREA tags are encountered. Same algorithm, but no
3018
+ data structures necessary.
3019
+
3020
+ current = start;
3021
+ while (current)
3022
+ {
3023
+ void *templink = (void *)current;
3024
+
3025
+ current = current->next;
3026
+ TidyDocFree(doc, templink);
3027
+ }
3028
+ start = NULL;
3029
+ */
3030
+ }
3031
+
3032
+ /************************************************************
3033
+ * AccessibilityChecks
3034
+ *
3035
+ * Traverses through the individual nodes of the tree
3036
+ * and checks attributes and elements for accessibility.
3037
+ * after the tree structure has been formed.
3038
+ ************************************************************/
3039
+
3040
+ static void AccessibilityCheckNode( TidyDocImpl* doc, Node* node )
3041
+ {
3042
+ Node* content;
3043
+
3044
+ /* Check BODY for color contrast */
3045
+ if ( nodeIsBODY(node) )
3046
+ {
3047
+ CheckColorContrast( doc, node );
3048
+ }
3049
+
3050
+ /* Checks document for MetaData */
3051
+ else if ( nodeIsHEAD(node) )
3052
+ {
3053
+ if ( !CheckMetaData( doc, node, no ) )
3054
+ MetaDataPresent( doc, node );
3055
+ }
3056
+
3057
+ /* Check the ANCHOR tag */
3058
+ else if ( nodeIsA(node) )
3059
+ {
3060
+ CheckAnchorAccess( doc, node );
3061
+ }
3062
+
3063
+ /* Check the IMAGE tag */
3064
+ else if ( nodeIsIMG(node) )
3065
+ {
3066
+ CheckFlicker( doc, node );
3067
+ CheckColorAvailable( doc, node );
3068
+ CheckImage( doc, node );
3069
+ }
3070
+
3071
+ /* Checks MAP for client-side text links */
3072
+ else if ( nodeIsMAP(node) )
3073
+ {
3074
+ CheckMapLinks( doc, node );
3075
+ }
3076
+
3077
+ /* Check the AREA tag */
3078
+ else if ( nodeIsAREA(node) )
3079
+ {
3080
+ CheckArea( doc, node );
3081
+ }
3082
+
3083
+ /* Check the APPLET tag */
3084
+ else if ( nodeIsAPPLET(node) )
3085
+ {
3086
+ CheckDeprecated( doc, node );
3087
+ ProgrammaticObjects( doc, node );
3088
+ DynamicContent( doc, node );
3089
+ AccessibleCompatible( doc, node );
3090
+ CheckFlicker( doc, node );
3091
+ CheckColorAvailable( doc, node );
3092
+ CheckApplet(doc, node );
3093
+ }
3094
+
3095
+ /* Check the OBJECT tag */
3096
+ else if ( nodeIsOBJECT(node) )
3097
+ {
3098
+ ProgrammaticObjects( doc, node );
3099
+ DynamicContent( doc, node );
3100
+ AccessibleCompatible( doc, node );
3101
+ CheckFlicker( doc, node );
3102
+ CheckColorAvailable( doc, node );
3103
+ CheckObject( doc, node );
3104
+ }
3105
+
3106
+ /* Check the FRAME tag */
3107
+ else if ( nodeIsFRAME(node) )
3108
+ {
3109
+ CheckFrame( doc, node );
3110
+ }
3111
+
3112
+ /* Check the IFRAME tag */
3113
+ else if ( nodeIsIFRAME(node) )
3114
+ {
3115
+ CheckIFrame( doc, node );
3116
+ }
3117
+
3118
+ /* Check the SCRIPT tag */
3119
+ else if ( nodeIsSCRIPT(node) )
3120
+ {
3121
+ DynamicContent( doc, node );
3122
+ ProgrammaticObjects( doc, node );
3123
+ AccessibleCompatible( doc, node );
3124
+ CheckFlicker( doc, node );
3125
+ CheckColorAvailable( doc, node );
3126
+ CheckScriptAcc( doc, node );
3127
+ }
3128
+
3129
+ /* Check the TABLE tag */
3130
+ else if ( nodeIsTABLE(node) )
3131
+ {
3132
+ CheckColorContrast( doc, node );
3133
+ CheckTable( doc, node );
3134
+ }
3135
+
3136
+ /* Check the PRE for ASCII art */
3137
+ else if ( nodeIsPRE(node) || nodeIsXMP(node) )
3138
+ {
3139
+ CheckASCII( doc, node );
3140
+ }
3141
+
3142
+ /* Check the LABEL tag */
3143
+ else if ( nodeIsLABEL(node) )
3144
+ {
3145
+ CheckLabel( doc, node );
3146
+ }
3147
+
3148
+ /* Check INPUT tag for validity */
3149
+ else if ( nodeIsINPUT(node) )
3150
+ {
3151
+ CheckColorAvailable( doc, node );
3152
+ CheckInputLabel( doc, node );
3153
+ CheckInputAttributes( doc, node );
3154
+ }
3155
+
3156
+ /* Checks FRAMESET element for NOFRAME section */
3157
+ else if ( nodeIsFRAMESET(node) )
3158
+ {
3159
+ CheckFrameSet( doc, node );
3160
+ }
3161
+
3162
+ /* Checks for header elements for valid header increase */
3163
+ else if ( TY_(nodeIsHeader)(node) )
3164
+ {
3165
+ CheckHeaderNesting( doc, node );
3166
+ }
3167
+
3168
+ /* Checks P element to ensure that it is not a header */
3169
+ else if ( nodeIsP(node) )
3170
+ {
3171
+ CheckParagraphHeader( doc, node );
3172
+ }
3173
+
3174
+ /* Checks HTML elemnt for valid 'LANG' */
3175
+ else if ( nodeIsHTML(node) )
3176
+ {
3177
+ CheckHTMLAccess( doc, node );
3178
+ }
3179
+
3180
+ /* Checks BLINK for any blinking text */
3181
+ else if ( nodeIsBLINK(node) )
3182
+ {
3183
+ CheckBlink( doc, node );
3184
+ }
3185
+
3186
+ /* Checks MARQUEE for any MARQUEE text */
3187
+ else if ( nodeIsMARQUEE(node) )
3188
+ {
3189
+ CheckMarquee( doc, node );
3190
+ }
3191
+
3192
+ /* Checks LINK for 'REL' attribute */
3193
+ else if ( nodeIsLINK(node) )
3194
+ {
3195
+ CheckLink( doc, node );
3196
+ }
3197
+
3198
+ /* Checks to see if STYLE is used */
3199
+ else if ( nodeIsSTYLE(node) )
3200
+ {
3201
+ CheckColorContrast( doc, node );
3202
+ CheckStyle( doc, node );
3203
+ }
3204
+
3205
+ /* Checks to see if EMBED is used */
3206
+ else if ( nodeIsEMBED(node) )
3207
+ {
3208
+ CheckEmbed( doc, node );
3209
+ ProgrammaticObjects( doc, node );
3210
+ AccessibleCompatible( doc, node );
3211
+ CheckFlicker( doc, node );
3212
+ }
3213
+
3214
+ /* Deprecated HTML if the following tags are found in the document */
3215
+ else if ( nodeIsBASEFONT(node) ||
3216
+ nodeIsCENTER(node) ||
3217
+ nodeIsISINDEX(node) ||
3218
+ nodeIsU(node) ||
3219
+ nodeIsFONT(node) ||
3220
+ nodeIsDIR(node) ||
3221
+ nodeIsS(node) ||
3222
+ nodeIsSTRIKE(node) ||
3223
+ nodeIsMENU(node) )
3224
+ {
3225
+ CheckDeprecated( doc, node );
3226
+ }
3227
+
3228
+ /* Checks for 'ABBR' attribute if needed */
3229
+ else if ( nodeIsTH(node) )
3230
+ {
3231
+ CheckTH( doc, node );
3232
+ }
3233
+
3234
+ /* Ensures that lists are properly used */
3235
+ else if ( nodeIsLI(node) || nodeIsOL(node) || nodeIsUL(node) )
3236
+ {
3237
+ CheckListUsage( doc, node );
3238
+ }
3239
+
3240
+ /* Recursively check all child nodes.
3241
+ */
3242
+ for ( content = node->content; content != NULL; content = content->next )
3243
+ {
3244
+ AccessibilityCheckNode( doc, content );
3245
+ }
3246
+ }
3247
+
3248
+
3249
+ void TY_(AccessibilityChecks)( TidyDocImpl* doc )
3250
+ {
3251
+ /* Initialize */
3252
+ InitAccessibilityChecks( doc, cfg(doc, TidyAccessibilityCheckLevel) );
3253
+
3254
+ /* Hello there, ladies and gentlemen... */
3255
+ TY_(AccessibilityHelloMessage)( doc );
3256
+
3257
+ /* Checks all elements for script accessibility */
3258
+ CheckScriptKeyboardAccessible( doc, &doc->root );
3259
+
3260
+ /* Checks entire document for the use of 'STYLE' attribute */
3261
+ CheckForStyleAttribute( doc, &doc->root );
3262
+
3263
+ /* Checks for '!DOCTYPE' */
3264
+ CheckDocType( doc );
3265
+
3266
+
3267
+ /* Checks to see if stylesheets are used to control the layout */
3268
+ if ( Level2_Enabled( doc )
3269
+ && ! CheckMissingStyleSheets( doc, &doc->root ) )
3270
+ {
3271
+ TY_(ReportAccessWarning)( doc, &doc->root, STYLE_SHEET_CONTROL_PRESENTATION );
3272
+ }
3273
+
3274
+ /* Check to see if any list elements are found within the document */
3275
+ CheckForListElements( doc, &doc->root );
3276
+
3277
+ /* Checks for natural language change */
3278
+ /* Must contain more than 3 words of text in the document
3279
+ **
3280
+ ** CPR - Not sure what intent is here, but this
3281
+ ** routine has nothing to do with changes in language.
3282
+ ** It seems like a bad idea to emit this message for
3283
+ ** every document with _more_ than 3 words!
3284
+
3285
+ if ( WordCount(doc, &doc->root) > 3 )
3286
+ {
3287
+ TY_(ReportAccessWarning)( doc, node, INDICATE_CHANGES_IN_LANGUAGE);
3288
+ }
3289
+ */
3290
+
3291
+
3292
+ /* Recursively apply all remaining checks to
3293
+ ** each node in document.
3294
+ */
3295
+ AccessibilityCheckNode( doc, &doc->root );
3296
+
3297
+ /* Cleanup */
3298
+ FreeAccessibilityChecks( doc );
3299
+ }
3300
+
3301
+ #endif
3302
+
3303
+ /*
3304
+ * local variables:
3305
+ * mode: c
3306
+ * indent-tabs-mode: nil
3307
+ * c-basic-offset: 4
3308
+ * eval: (c-set-offset 'substatement-open 0)
3309
+ * end:
3310
+ */