|
1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Externalizes a DOM Document to a byte array. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.tools.themeinstaller.odtconverter; |
|
20 |
|
21 import java.awt.Color; |
|
22 import java.io.ByteArrayOutputStream; |
|
23 import java.io.IOException; |
|
24 |
|
25 import org.w3c.dom.Document; |
|
26 import org.w3c.dom.Element; |
|
27 import org.w3c.dom.NamedNodeMap; |
|
28 import org.w3c.dom.Node; |
|
29 import org.w3c.dom.NodeList; |
|
30 |
|
31 import com.nokia.tools.themeinstaller.cssparser.CSSDOMProcessor; |
|
32 import com.nokia.tools.themeinstaller.cssparser.CSSHandler; |
|
33 import com.nokia.tools.themeinstaller.cssparser.PseudoClassResolver; |
|
34 |
|
35 /** |
|
36 * Externalizes DOM Document to a byte array. |
|
37 */ |
|
38 public class DOMExternalizer |
|
39 { |
|
40 |
|
41 // CONSTANTS |
|
42 // Text elements according to CXnDomVisitor::KXnElementVisitorTable and |
|
43 // CXnODTParser |
|
44 private static final String TEXT_ELEMENT = "text"; |
|
45 private static final String DESC_ELEMENT = "desc"; |
|
46 private static final String MARQUEE_ELEMENT = "marquee"; |
|
47 private static final String OBJECT_ELEMENT = "object"; |
|
48 private static final String NEWSTICKER_ELEMENT = "newsticker"; |
|
49 |
|
50 // Attribute name if node is refnode |
|
51 private static final String REF_NODE = "ref"; |
|
52 |
|
53 // List types |
|
54 private static final int UNKNOWN = -1; |
|
55 private static final int NODE = 0; |
|
56 private static final int ATTRIBUTE = 1; |
|
57 private static final int PROPERTY = 2; |
|
58 |
|
59 // The Constant COLOR_TABLE_SIZE |
|
60 private static final int COLOR_TABLE_SIZE = 3; |
|
61 |
|
62 // Pseudo class resolver |
|
63 private PseudoClassResolver iPseudoResolver; |
|
64 |
|
65 // The value type resolver |
|
66 private ValueTypeResolver iValueTypeResolver; |
|
67 |
|
68 // String pool |
|
69 private StringPool iStringPool; |
|
70 |
|
71 // DOM Document |
|
72 private Document iDocument; |
|
73 |
|
74 // Byte output stream for delivering the externalized data |
|
75 private ByteArrayOutputStream iBaos; |
|
76 |
|
77 // Data output stream for writing to the baos |
|
78 private ODTDataOutputStream iODTDos; |
|
79 |
|
80 // Node id and counter |
|
81 private int iCurrentNodeId = 0; |
|
82 |
|
83 /** CSSDOMProsessor for checking property's inheritance value. */ |
|
84 private CSSDOMProcessor iCSSDOMProsessor; |
|
85 |
|
86 /** |
|
87 * Constructor. |
|
88 * @param aDocument DOM Document to externalize |
|
89 */ |
|
90 public DOMExternalizer( Document aDocument ) |
|
91 { |
|
92 iPseudoResolver = new PseudoClassResolver(); |
|
93 iValueTypeResolver = new ValueTypeResolver(); |
|
94 iCSSDOMProsessor = new CSSDOMProcessor(); |
|
95 iStringPool = new StringPool(); |
|
96 iDocument = aDocument; |
|
97 iBaos = new ByteArrayOutputStream(); |
|
98 iODTDos = new ODTDataOutputStream( iBaos ); |
|
99 } |
|
100 |
|
101 /* (non-Javadoc) |
|
102 * @see java.lang.Object#finalize() |
|
103 */ |
|
104 protected void finalize() throws Throwable |
|
105 { |
|
106 iODTDos.close(); |
|
107 iBaos.close(); |
|
108 } |
|
109 |
|
110 /** |
|
111 * Externalizes the DOM document and string pool to a byte array. |
|
112 * @return Byte array containing the document |
|
113 * @throws IOException if writing to a stream fails |
|
114 * @throws ODTException |
|
115 */ |
|
116 public byte[] getByteArray() throws IOException, ODTException |
|
117 { |
|
118 ByteArrayOutputStream result = new ByteArrayOutputStream(); |
|
119 byte[] resultArray = null; |
|
120 |
|
121 try |
|
122 { |
|
123 // Externalize the DOM |
|
124 doExternalize(); |
|
125 |
|
126 // Externalize the string pool |
|
127 result.write( iStringPool.toByteArray() ); |
|
128 |
|
129 // Write the dom contents to the result baos |
|
130 result.write( iBaos.toByteArray() ); |
|
131 |
|
132 resultArray = result.toByteArray(); |
|
133 } |
|
134 finally |
|
135 { |
|
136 if( result != null ) |
|
137 { |
|
138 result.close(); |
|
139 } |
|
140 } |
|
141 |
|
142 return resultArray; |
|
143 } |
|
144 |
|
145 /** |
|
146 * Do the externalization process. |
|
147 * @throws IOException if data output stream can not be written |
|
148 * @throws ODTException if there is an error with property value externalization |
|
149 */ |
|
150 private void doExternalize() throws IOException, ODTException |
|
151 { |
|
152 Node rootElement = iDocument.getDocumentElement(); |
|
153 |
|
154 if( rootElement != null ) |
|
155 { |
|
156 // Root node exists |
|
157 iODTDos.writeBoolean( true ); |
|
158 externalizeNode( ( Node )rootElement, true ); |
|
159 } |
|
160 else |
|
161 { |
|
162 // No root node |
|
163 iODTDos.writeBoolean( false ); |
|
164 } |
|
165 } |
|
166 |
|
167 /** |
|
168 * Externalizes a node in the DOM tree. |
|
169 * @param aNode Node to externalize |
|
170 * @param aRootNode true, if this is the root node of the tree |
|
171 * @throws IOException if data output stream can not be written |
|
172 * @throws ODTException if there is an error with property value externalization |
|
173 */ |
|
174 private void externalizeNode( Node aNode, boolean aRootNode ) |
|
175 throws IOException, ODTException |
|
176 { |
|
177 // Write name |
|
178 String name = aNode.getNodeName(); |
|
179 int nameRef = iStringPool.addString( name ); |
|
180 iODTDos.writeInt16( nameRef ); |
|
181 |
|
182 // Write name space |
|
183 String ns = aNode.getNamespaceURI(); |
|
184 int nsRef = iStringPool.addString( ns ); |
|
185 iODTDos.writeInt16( nsRef ); |
|
186 |
|
187 // Check and write refnode boolean |
|
188 iODTDos.writeBoolean( checkRefNode( aNode ) ); |
|
189 |
|
190 boolean textNodeFound = false; |
|
191 |
|
192 // Write parsed character data |
|
193 StringBuffer pcData = new StringBuffer(); |
|
194 if( TEXT_ELEMENT.equals( name ) || |
|
195 DESC_ELEMENT.equals( name ) || |
|
196 MARQUEE_ELEMENT.equals( name ) || |
|
197 OBJECT_ELEMENT.equals( name ) || |
|
198 NEWSTICKER_ELEMENT.equals( name ) ) |
|
199 { |
|
200 NodeList list = aNode.getChildNodes(); |
|
201 |
|
202 for( int i = 0; i < list.getLength() ; i++ ) |
|
203 { |
|
204 Node nod = list.item( i ); |
|
205 if( nod.getNodeType() == Node.TEXT_NODE ) |
|
206 { |
|
207 textNodeFound = true; |
|
208 String textNodeValue = nod.getNodeValue(); |
|
209 |
|
210 pcData.append( textNodeValue ); |
|
211 } |
|
212 } |
|
213 } |
|
214 |
|
215 // Write data length and the data |
|
216 iODTDos.writeBoolean( textNodeFound ); |
|
217 if( textNodeFound ) |
|
218 { |
|
219 // Write text length |
|
220 iODTDos.writeInt16( pcData.length() ); |
|
221 |
|
222 // Write text node value |
|
223 iODTDos.writeString8( pcData.toString() ); |
|
224 } |
|
225 // Update the counter and write node id |
|
226 iODTDos.writeInt32( iCurrentNodeId++ ); |
|
227 |
|
228 // Externalize the child list |
|
229 externalizeNodeList( aNode ); |
|
230 |
|
231 // Externalize the attribute list |
|
232 externalizeAttributeList( aNode ); |
|
233 |
|
234 // Externalize the property list |
|
235 externalizePropertyList( aNode ); |
|
236 } |
|
237 |
|
238 /** |
|
239 * Checks if node is refnode. |
|
240 * Node is refnode if some of node's attributes name is "ref". |
|
241 * @param aNode Node containing the attributes |
|
242 * @return boolean true if node is refnode, otherwise false |
|
243 */ |
|
244 private boolean checkRefNode( Node aNode ) |
|
245 { |
|
246 boolean refNode = false; |
|
247 NamedNodeMap list = aNode.getAttributes(); |
|
248 for ( int i = 0; i < list.getLength(); i++ ) |
|
249 { |
|
250 Node node = list.item( i ); |
|
251 if ( nodeType( node ) == ATTRIBUTE ) |
|
252 { |
|
253 if( node.getNodeName().equals( REF_NODE ) ) |
|
254 { |
|
255 refNode = true; |
|
256 } |
|
257 } |
|
258 } |
|
259 return refNode; |
|
260 } |
|
261 |
|
262 /** |
|
263 * Externalizes attributes of a node. |
|
264 * @param aNode Node containing the attributes |
|
265 * @throws IOException if writing to a stream fails |
|
266 * @throws ODTException |
|
267 */ |
|
268 private void externalizeAttributeNode( Node aNode ) |
|
269 throws IOException, ODTException |
|
270 { |
|
271 // Write name |
|
272 String name = aNode.getNodeName(); |
|
273 int nameRef = iStringPool.addString( name ); |
|
274 iODTDos.writeInt16( nameRef ); |
|
275 |
|
276 // Write value |
|
277 String value = aNode.getNodeValue(); |
|
278 int valueRef = iStringPool.addString( value ); |
|
279 iODTDos.writeInt16( valueRef ); |
|
280 } |
|
281 |
|
282 /** |
|
283 * Externalizes a property node. |
|
284 * |
|
285 * @param aNode Node containing the properties |
|
286 * @param aParentNode Node's parent node |
|
287 * |
|
288 * @throws IOException if data output stream can not be written |
|
289 * @throws ODTException if there is an error with property |
|
290 * value externalization |
|
291 */ |
|
292 private void externalizePropertyNode( Node aParentNode, Node aNode ) |
|
293 throws IOException, ODTException |
|
294 { |
|
295 // Get property node attributes: property name, values and pseudo class |
|
296 NamedNodeMap list = aNode.getAttributes(); |
|
297 |
|
298 // Property value list |
|
299 boolean isInherited = externalizePropertyValueList( aParentNode, list ); |
|
300 |
|
301 iODTDos.writeBoolean( isInherited ); |
|
302 |
|
303 // Resolve pseudo class |
|
304 int pseudoClass = PseudoClassResolver.NONE; |
|
305 |
|
306 int count = list.getLength(); |
|
307 for( int i = 0; i < count; i++ ) |
|
308 { |
|
309 // Browse through all attributes of the style property element and |
|
310 // seek for a pseudo class |
|
311 Node item = list.item( i ); |
|
312 if( item.getNodeName().equals( CSSDOMProcessor.STRING_PSEUDOCLASS ) ) |
|
313 { |
|
314 pseudoClass = iPseudoResolver.getKey( item.getNodeValue() ); |
|
315 if( pseudoClass == UNKNOWN ) |
|
316 { |
|
317 throw new ODTException( "Error externalizing ODT/styles: " + |
|
318 "unknown pseudo class" ); |
|
319 } |
|
320 break; |
|
321 } |
|
322 } |
|
323 |
|
324 // Pseudo class -> int8 |
|
325 iODTDos.writeByte( pseudoClass ); |
|
326 } |
|
327 |
|
328 /** |
|
329 * Externalize a list of nodes. |
|
330 * @param aParentNode Parent node |
|
331 * @throws IOException if data output stream can not be written |
|
332 * @throws ODTException if there is an error with property value externalization |
|
333 */ |
|
334 private void externalizeNodeList( Node aParentNode ) throws IOException, ODTException |
|
335 { |
|
336 // Write list type |
|
337 iODTDos.writeByte( NODE ); |
|
338 |
|
339 NodeList list = aParentNode.getChildNodes(); |
|
340 |
|
341 // Count element nodes |
|
342 int count = countNodes( list ); |
|
343 |
|
344 // Write element node count |
|
345 iODTDos.writeInt32( count ); |
|
346 |
|
347 for ( int i = 0; i < list.getLength(); i++ ) |
|
348 { |
|
349 Node node = list.item( i ); |
|
350 |
|
351 if ( nodeType( node ) == NODE ) |
|
352 { |
|
353 externalizeNode( node, false ); |
|
354 } |
|
355 } |
|
356 } |
|
357 |
|
358 /** |
|
359 * Externalize a list of attributes. |
|
360 * @param aParentNode Node containing the attributes. |
|
361 * @throws IOException if writing to a stream fails |
|
362 * @throws ODTException |
|
363 */ |
|
364 private void externalizeAttributeList( Node aParentNode ) |
|
365 throws IOException, ODTException |
|
366 { |
|
367 // Write list type |
|
368 iODTDos.writeByte( ATTRIBUTE ); |
|
369 |
|
370 NamedNodeMap list = aParentNode.getAttributes(); |
|
371 |
|
372 // Count element nodes |
|
373 int count = countAttributes( list ); |
|
374 |
|
375 // Write element node count |
|
376 iODTDos.writeInt32( count ); |
|
377 |
|
378 for ( int i = 0; i < list.getLength(); i++ ) |
|
379 { |
|
380 Node node = list.item( i ); |
|
381 |
|
382 if ( nodeType( node ) == ATTRIBUTE ) |
|
383 { |
|
384 externalizeAttributeNode( node ); |
|
385 } |
|
386 } |
|
387 } |
|
388 |
|
389 /** |
|
390 * Externalize a list of properties. |
|
391 * @param aParentNode Node containing the properties |
|
392 * @throws IOException if data output stream can not be written |
|
393 * @throws ODTException if there is an error with property value externalization |
|
394 */ |
|
395 private void externalizePropertyList( Node aParentNode ) throws IOException, ODTException |
|
396 { |
|
397 // Write list type |
|
398 iODTDos.writeByte( PROPERTY ); |
|
399 |
|
400 NodeList list = aParentNode.getChildNodes(); |
|
401 |
|
402 // Count element nodes |
|
403 int count = countProperties( list ); |
|
404 |
|
405 // Write element node count |
|
406 iODTDos.writeInt32( count ); |
|
407 |
|
408 for ( int i = 0; i < list.getLength(); i++ ) |
|
409 { |
|
410 Node node = list.item( i ); |
|
411 |
|
412 if ( nodeType( node ) == PROPERTY ) |
|
413 { |
|
414 externalizePropertyNode( aParentNode, node ); |
|
415 } |
|
416 } |
|
417 } |
|
418 |
|
419 /** |
|
420 * Parses a Color from string. |
|
421 * |
|
422 * @param aColor Color values in String made by CSSHandler |
|
423 * |
|
424 * @return The color |
|
425 * |
|
426 * @throws ODTException the ODT exception |
|
427 */ |
|
428 private Color parseColorFromString( String aColor ) throws ODTException |
|
429 { |
|
430 String sx[] = aColor.split( CSSHandler.COMMA ); |
|
431 int ix[] = new int[ sx.length ]; |
|
432 |
|
433 // LexicalUnit.SAC_RGBCOLOR knows color values with format |
|
434 // rgb(0, 0, 0) and #000. That is, with three parameters |
|
435 if ( sx.length != COLOR_TABLE_SIZE ) |
|
436 { |
|
437 throw new ODTException( "Error in DOM/style data externalization: " |
|
438 + "RGB Values: parameter amount" ); |
|
439 } |
|
440 |
|
441 for ( int i = 0; i < sx.length; i++ ) |
|
442 { |
|
443 if ( sx[ i ].contains( CSSHandler.SEPARATOR ) ) |
|
444 { |
|
445 // Check if single color's value is integer |
|
446 Short valueType = iValueTypeResolver.getValue( Short |
|
447 .valueOf( sx[ i ].substring( 0, sx[ i ] |
|
448 .indexOf( CSSHandler.SEPARATOR ) ) ) ); |
|
449 |
|
450 if ( valueType.intValue() != ValueTypeResolver.E_NUMBER ) |
|
451 { |
|
452 throw new ODTException( |
|
453 "Error in DOM/style data externalization: " |
|
454 + "RGB Values: R, G or B not interger" ); |
|
455 } |
|
456 String redGreenBlue = sx[ i ].substring( sx[ i ] |
|
457 .indexOf( CSSHandler.SEPARATOR ) + 1, sx[ i ] |
|
458 .length() ); |
|
459 Integer rgbValue = Integer.valueOf( redGreenBlue ); |
|
460 ix[ i ] = rgbValue.intValue(); |
|
461 } |
|
462 else |
|
463 { |
|
464 throw new ODTException( |
|
465 "Error in DOM/style data externalization: " |
|
466 + "RGB Values: can't resolve value type" ); |
|
467 } |
|
468 } |
|
469 return new Color( ix[ 0 ], ix[ 1 ], ix[ 2 ] ); |
|
470 } |
|
471 |
|
472 /** |
|
473 * Parses the Value Type from Value. |
|
474 * |
|
475 * @param aAttrValue The attribute value |
|
476 * |
|
477 * @return Parsed value as a string |
|
478 * |
|
479 * @throws IOException Signals that an I/O exception has occurred. |
|
480 * @throws ODTException |
|
481 */ |
|
482 private String parseAttrValue( String aAttrValue, PropertyValue aPropValue ) |
|
483 throws IOException, ODTException |
|
484 { |
|
485 if ( aAttrValue.length() > 0 ) |
|
486 { |
|
487 if ( aAttrValue.contains( "|" ) ) |
|
488 { |
|
489 String type = aAttrValue |
|
490 .substring( 0, aAttrValue.indexOf( '|' ) ); |
|
491 String value = aAttrValue.substring( |
|
492 aAttrValue.indexOf( '|' ) + 1, aAttrValue.length() ); |
|
493 |
|
494 Short lexicalUnit = Short.valueOf( type ); |
|
495 Short primitiveValueType = |
|
496 iValueTypeResolver.getValue( lexicalUnit ); |
|
497 |
|
498 switch ( primitiveValueType.intValue() ) |
|
499 { |
|
500 case ValueTypeResolver.E_NUMBER: |
|
501 double doubleValueInteger = Double.valueOf( value ).doubleValue(); |
|
502 aPropValue.setRealValue( doubleValueInteger, |
|
503 primitiveValueType.shortValue() ); |
|
504 break; |
|
505 case ValueTypeResolver.E_UNIT_VALUE: |
|
506 case ValueTypeResolver.E_PERCENTAGE: |
|
507 case ValueTypeResolver.E_EMS: |
|
508 case ValueTypeResolver.E_EXS: |
|
509 case ValueTypeResolver.E_PX: |
|
510 case ValueTypeResolver.E_CM: |
|
511 case ValueTypeResolver.E_MM: |
|
512 case ValueTypeResolver.E_IN: |
|
513 case ValueTypeResolver.E_PT: |
|
514 case ValueTypeResolver.E_PC: |
|
515 case ValueTypeResolver.E_DEG: |
|
516 case ValueTypeResolver.E_RAD: |
|
517 case ValueTypeResolver.E_GRAD: |
|
518 case ValueTypeResolver.E_MS: |
|
519 case ValueTypeResolver.E_S: |
|
520 case ValueTypeResolver.E_HZ: |
|
521 case ValueTypeResolver.E_KHZ: |
|
522 double doubleValuePercentage = Double.valueOf( value ).doubleValue(); |
|
523 aPropValue.setRealValue( doubleValuePercentage, |
|
524 primitiveValueType.shortValue() ); |
|
525 break; |
|
526 case ValueTypeResolver.E_IDENT: |
|
527 case ValueTypeResolver.E_STRING: |
|
528 case ValueTypeResolver.E_URI: |
|
529 case ValueTypeResolver.E_ATTR: |
|
530 aPropValue.setString( new String( value ), |
|
531 primitiveValueType.shortValue() ); |
|
532 break; |
|
533 case ValueTypeResolver.E_RGB_COLOR: |
|
534 Color color = parseColorFromString(value); |
|
535 aPropValue.setRgbValue( color ); |
|
536 break; |
|
537 default: |
|
538 break; |
|
539 } |
|
540 |
|
541 return value; |
|
542 } |
|
543 return aAttrValue; |
|
544 } |
|
545 return aAttrValue; |
|
546 } |
|
547 |
|
548 /** |
|
549 * Externalize a list of property values. |
|
550 * |
|
551 * @param aNode the a node |
|
552 * @param aAttrList the a attr list |
|
553 * |
|
554 * @return true, if property is inherited |
|
555 * |
|
556 * @throws IOException if data output stream can not be written |
|
557 * @throws ODTException if there is an error with externalizing property values |
|
558 */ |
|
559 private boolean externalizePropertyValueList( Node aNode, NamedNodeMap aAttrList ) |
|
560 throws IOException, ODTException |
|
561 { |
|
562 PropertyValueList valueList = new PropertyValueList( iStringPool ); |
|
563 |
|
564 boolean isInherited = false; |
|
565 String name = null; |
|
566 String value = null; |
|
567 |
|
568 for ( int i = 0; i < aAttrList.getLength(); i++ ) |
|
569 { |
|
570 Node node = aAttrList.item( i ); |
|
571 |
|
572 if ( nodeType( node ) == ATTRIBUTE && |
|
573 !node.getNodeName().equals( CSSDOMProcessor.STRING_PSEUDOCLASS ) ) |
|
574 { |
|
575 String attrName = node.getNodeName(); |
|
576 String attrValue = node.getNodeValue(); |
|
577 |
|
578 if( attrName.equals( CSSDOMProcessor.STRING_NAME ) && |
|
579 name == null ) |
|
580 { |
|
581 name = attrValue; |
|
582 } |
|
583 else if( attrName.startsWith( CSSDOMProcessor.STRING_VALUE ) ) |
|
584 { |
|
585 value = attrValue; |
|
586 |
|
587 // Checking if property is inherited. |
|
588 // This emulates the behavior of the Symbian side implementation |
|
589 // where this is true in following cases: |
|
590 // 1. Value equals "inherited" |
|
591 // 2. Property is inheritable and the element can inherit properties |
|
592 // |
|
593 // This means that also some properties that aren't actually |
|
594 // inherited, are also set with value isIherited == "true" |
|
595 isInherited = iCSSDOMProsessor.canInherit( (Element) aNode, name, value ); |
|
596 |
|
597 PropertyValue propValue = valueList.newItem(); |
|
598 parseAttrValue( value, propValue ); |
|
599 } |
|
600 else |
|
601 { |
|
602 throw new ODTException( "Error in DOM/style data externalization: " + |
|
603 "Property values" ); |
|
604 } |
|
605 } |
|
606 } |
|
607 |
|
608 if( name != null && |
|
609 value != null ) |
|
610 { |
|
611 // Write property name |
|
612 int nameRef = iStringPool.addString( name ); |
|
613 iODTDos.writeInt16( nameRef ); |
|
614 |
|
615 // Externalize the property value list to the stream |
|
616 valueList.externalize( iODTDos ); |
|
617 } |
|
618 else |
|
619 { |
|
620 throw new ODTException( "Error in DOM/style data externalization: " + |
|
621 "Property values" ); |
|
622 } |
|
623 return isInherited; |
|
624 } |
|
625 |
|
626 /** |
|
627 * Count element nodes in a node list. |
|
628 * @param aList Node list |
|
629 * @param aNodeType Node type to count |
|
630 * @return Count of found nodes |
|
631 */ |
|
632 private static int countNodes( NodeList aList ) |
|
633 { |
|
634 int count = 0; |
|
635 for( int i = 0; i < aList.getLength(); i++ ) |
|
636 { |
|
637 // Exclude elements that are style properties |
|
638 if( nodeType( aList.item( i ) ) == NODE ) |
|
639 { |
|
640 count++; |
|
641 } |
|
642 } |
|
643 |
|
644 return count; |
|
645 } |
|
646 |
|
647 /** |
|
648 * Count attributes in a named node map. |
|
649 * @param aList Node map |
|
650 * @param aNodeType Node type to count |
|
651 * @return Count of found nodes |
|
652 */ |
|
653 private static int countAttributes( NamedNodeMap aList ) |
|
654 { |
|
655 int count = 0; |
|
656 for( int i = 0; i < aList.getLength(); i++ ) |
|
657 { |
|
658 if( nodeType( aList.item( i ) ) == ATTRIBUTE ) |
|
659 { |
|
660 count++; |
|
661 } |
|
662 } |
|
663 |
|
664 return count; |
|
665 } |
|
666 |
|
667 /** |
|
668 * Count properties in a node list. |
|
669 * @param aList Node list |
|
670 * @param aNodeType Node type to count |
|
671 * @return Count of found nodes |
|
672 */ |
|
673 private static int countProperties( NodeList aList ) |
|
674 { |
|
675 int count = 0; |
|
676 for( int i = 0; i < aList.getLength(); i++ ) |
|
677 { |
|
678 // Include only elements that are style properties |
|
679 if( nodeType( aList.item( i ) ) == PROPERTY ) |
|
680 { |
|
681 count++; |
|
682 } |
|
683 } |
|
684 |
|
685 return count; |
|
686 } |
|
687 |
|
688 /** |
|
689 * Resolve node type. Possible types: NODE, ATTRIBUTE or PROPERTY |
|
690 * @param aItem Node to resolve |
|
691 * @return Type of the node. If the type can not be determined, UNKNOWN is returned |
|
692 */ |
|
693 private static int nodeType( Node aItem ) |
|
694 { |
|
695 int type = UNKNOWN; |
|
696 |
|
697 // Element that is not a style property element |
|
698 if( aItem.getNodeType() == Node.ELEMENT_NODE && |
|
699 !aItem.getNodeName().equals( CSSDOMProcessor.STRING_PROPERTY ) ) |
|
700 { |
|
701 type = NODE; |
|
702 } |
|
703 // Attribute nodes |
|
704 else if( aItem.getNodeType() == Node.ATTRIBUTE_NODE ) |
|
705 { |
|
706 type = ATTRIBUTE; |
|
707 } |
|
708 // Style property element |
|
709 else if( aItem.getNodeType() == Node.ELEMENT_NODE && |
|
710 aItem.getNodeName().equals( CSSDOMProcessor.STRING_PROPERTY ) ) |
|
711 { |
|
712 type = PROPERTY; |
|
713 } |
|
714 |
|
715 return type; |
|
716 } |
|
717 |
|
718 } |