EMMA Coverage Report (generated Mon Nov 01 16:48:29 PDT 2010)
[all classes][com.google.caja.render]

COVERAGE SUMMARY FOR SOURCE FILE [CssPrettyPrinter.java]

nameclass, %method, %block, %line, %
CssPrettyPrinter.java100% (2/2)100% (11/11)91%  (266/293)91%  (72.1/79)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class CssPrettyPrinter100% (1/1)100% (10/10)91%  (243/267)91%  (72.2/79)
CssPrettyPrinter (TokenConsumer): void 100% (1/1)100% (12/12)100% (4/4)
consume (String): void 100% (1/1)94%  (104/111)94%  (37.5/40)
emit (String): void 100% (1/1)83%  (30/36)80%  (8/10)
getIndentation (): int 100% (1/1)100% (17/17)100% (1/1)
indent (): void 100% (1/1)74%  (29/39)80%  (8/10)
mark (FilePosition): void 100% (1/1)100% (5/5)100% (1/1)
newLine (): void 100% (1/1)92%  (11/12)94%  (3.8/4)
popIndentStack (): void 100% (1/1)100% (14/14)100% (3/3)
pushIndent (int): void 100% (1/1)100% (7/7)100% (2/2)
space (): void 100% (1/1)100% (14/14)100% (4/4)
     
class CssPrettyPrinter$1100% (1/1)100% (1/1)88%  (23/26)88%  (0.9/1)
<static initializer> 100% (1/1)88%  (23/26)88%  (0.9/1)

1// Copyright (C) 2008 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14 
15package com.google.caja.render;
16 
17import com.google.caja.lexer.FilePosition;
18import com.google.caja.lexer.TokenConsumer;
19 
20import java.util.ArrayList;
21import java.util.List;
22 
23/**
24 * A formatter that indents code for CSS paying careful attention to where
25 * adding whitespace between tokens would change tokenization.
26 *
27 * @author mikesamuel@gmail.com
28 */
29public final class CssPrettyPrinter extends AbstractRenderer {
30  /**
31   * Stack of indentation positions.
32   * Curly brackets indent to two past the last stack position and
33   * parenthetical blocks indent to the open parenthesis.
34   *
35   * A non-negative number indicates a curly bracket indentation and a negative
36   * number a parenthetical indentation.
37   */
38  private List<Integer> indentStack = new ArrayList<Integer>();
39  /** Number of characters written to out since the last line-break. */
40  private int charInLine;
41 
42  /** True if the last token needs a following space. */
43  private char pendingSpace = '\0';
44 
45  /**
46   * @param out receives the rendered text.  Typically a {@link Concatenator}.
47   */
48  public CssPrettyPrinter(TokenConsumer out) {
49    super(out);
50  }
51 
52  public void mark(FilePosition pos) { out.mark(pos); }
53 
54  @Override
55  public void consume(String text) {
56    TokenClassification tClass = TokenClassification.classify(text);
57    if (tClass == null) { return; }
58    switch (tClass) {
59      case LINEBREAK:
60        // Allow external code to force line-breaks.
61        // This allows us to create a composite-renderer that renders
62        // original source code next to translated source code.
63        if (pendingSpace == '\n') { newLine(); }
64        pendingSpace = '\n';
65        return;
66      case SPACE:
67        if (pendingSpace != '\n') { pendingSpace = ' '; }
68        return;
69      case COMMENT:
70        emit(text);
71        return;
72      default: break;
73    }
74 
75    char spaceBefore = pendingSpace;
76    pendingSpace = '\0';
77    char spaceAfter = '\0';
78 
79    Integer nextIndent = null;
80    if (text.length() == 1) {
81      char ch0 = text.charAt(0);
82      switch (ch0) {
83        case '{':
84          if (spaceBefore != '\n') {
85            spaceBefore = ' ';
86          }
87          nextIndent = getIndentation() + 2;
88          spaceAfter = '\n';
89          break;
90        case '}':
91          spaceAfter = spaceBefore = '\n';
92          popIndentStack();
93          break;
94        case ',':
95          spaceBefore = '\0';
96          spaceAfter = ' ';
97          break;
98        case ';':
99          spaceBefore = '\0';
100          // If we're rendering a declaration group, e.g. inside an HTML style
101          // attribute, separate them with spaces, but if we're pretty printing
102          // a stylesheet, put newlines between declarations.
103          spaceAfter = indentStack.isEmpty() ? ' ' : '\n';
104          break;
105      }
106    }
107 
108    switch (spaceBefore) {
109      case '\n':
110        newLine();
111        break;
112      case ' ':
113        space();
114        break;
115    }
116 
117    indent();
118    emit(text);
119    if (nextIndent != null) {
120      pushIndent(nextIndent);
121    }
122 
123    pendingSpace = spaceAfter;
124  }
125 
126  private int getIndentation() {
127    return indentStack.isEmpty() ? 0 : indentStack.get(indentStack.size() - 1);
128  }
129 
130  private void pushIndent(int indent) {
131    indentStack.add(indent);
132  }
133 
134  private void popIndentStack() {
135    if (!indentStack.isEmpty()) {
136      indentStack.remove(indentStack.size() - 1);
137    }
138  }
139 
140  private void indent() {
141    if (charInLine != 0) { return; }
142    int indent = getIndentation();
143 
144    charInLine += indent;
145    String spaces = "                ";
146    while (indent >= spaces.length()) {
147      out.consume(spaces);
148      indent -= spaces.length();
149    }
150    if (indent != 0) {
151      out.consume(spaces.substring(0, indent));
152    }
153  }
154 
155  private void newLine() {
156    if (charInLine == 0) { return; }
157    charInLine = 0;
158    out.consume("\n");
159  }
160 
161  private void space() {
162    if (charInLine != 0) {
163      out.consume(" ");
164      ++charInLine;
165    }
166  }
167 
168  private void emit(String s) {
169    out.consume(s);
170    int n = s.length();
171    for (int i = n; --i >= 0;) {
172      char ch = s.charAt(i);
173      if (ch == '\r' || ch == '\n') {
174        charInLine = n - i;
175        break;
176      }
177    }
178    charInLine += n;
179  }
180}

[all classes][com.google.caja.render]
EMMA 2.0.5312 (C) Vladimir Roubtsov