Revision: 6403
Author: rj...@google.com
Date: Fri Oct 16 15:58:05 2009
Log: Make StyleInjector use Scheduler API.

Patch by: bobv
Review by: bruce

http://gwt-code-reviews.appspot.com/78816
http://code.google.com/p/google-web-toolkit/source/detail?r=6403

Modified:
  /trunk/user/src/com/google/gwt/core/client/impl/SchedulerImpl.java
  /trunk/user/src/com/google/gwt/dom/client/StyleInjector.java
  /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
  /trunk/user/test/com/google/gwt/dom/client/StyleInjectorTest.java

=======================================
--- /trunk/user/src/com/google/gwt/core/client/impl/SchedulerImpl.java  Fri  
Oct 16 15:20:56 2009
+++ /trunk/user/src/com/google/gwt/core/client/impl/SchedulerImpl.java  Fri  
Oct 16 15:58:05 2009
@@ -177,7 +177,8 @@
    }-*/;

    public static void scheduleIncrementalImpl(RepeatingCommand cmd) {
-    INCREMENTAL_COMMANDS.push(Task.create(cmd));
+    // Push repeating commands onto the same initial queue for relative  
order
+    DEFERRED_COMMANDS.push(Task.create(cmd));
      maybeSchedulePostEventPumpCommands();
    }

=======================================
--- /trunk/user/src/com/google/gwt/dom/client/StyleInjector.java        Tue Sep 
 8  
07:17:09 2009
+++ /trunk/user/src/com/google/gwt/dom/client/StyleInjector.java        Fri Oct 
16  
15:58:05 2009
@@ -19,9 +19,15 @@
  import com.google.gwt.core.client.JavaScriptObject;
  import com.google.gwt.core.client.JsArray;
  import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;

  /**
- * Used to add stylesheets to the document.
+ * Used to add stylesheets to the document. The one-argument versions of
+ * {...@link #inject}, {...@link #injectAtEnd}, and {...@link #injectAtStart} 
use
+ * {...@link Scheduler#scheduleFinally} to minimize the number of individual  
style
+ * elements created.
   */
  public class StyleInjector {

@@ -120,8 +126,8 @@
           * This assertion can fail if the max number of style elements  
exist
           * before this module can inject any style elements, so  
STYLE_ELEMENTS
           * will be empty. However, the fix would degrade performance for  
the
-         * general case.
-         * TODO(jlabanca): Can we handle this scenario efficiently?
+         * general case. TODO(jlabanca): Can we handle this scenario
+         * efficiently?
           */
          assert shortestIdx != -1;

@@ -178,6 +184,93 @@
        return $doc.styleSheets.length;
      }-*/;
    }
+
+  private static final JsArrayString toInject =  
JavaScriptObject.createArray().cast();
+  private static final JsArrayString toInjectAtEnd =  
JavaScriptObject.createArray().cast();
+  private static final JsArrayString toInjectAtStart =  
JavaScriptObject.createArray().cast();
+
+  private static ScheduledCommand flusher = new ScheduledCommand() {
+    public void execute() {
+      if (needsInjection) {
+        flush(null);
+      }
+    }
+  };
+
+  private static boolean needsInjection = false;
+
+  /**
+   * Add a stylesheet to the document.
+   *
+   * @param css the CSS contents of the stylesheet
+   */
+  public static void inject(String css) {
+    inject(css, false);
+  }
+
+  /**
+   * Add a stylesheet to the document.
+   *
+   * @param css the CSS contents of the stylesheet
+   * @param immediate if <code>true</code> the DOM will be updated  
immediately
+   *          instead of just before returning to the event loop. Using  
this
+   *          option excessively will decrease performance, especially if  
used
+   *          with an inject-css-on-init coding pattern
+   */
+  public static void inject(String css, boolean immediate) {
+    toInject.push(css);
+    inject(immediate);
+  }
+
+  /**
+   * Add stylesheet data to the document as though it were declared after  
all
+   * stylesheets previously created by {...@link #inject(String)}.
+   *
+   * @param css the CSS contents of the stylesheet
+   */
+  public static void injectAtEnd(String css) {
+    injectAtEnd(css, false);
+  }
+
+  /**
+   * Add stylesheet data to the document as though it were declared after  
all
+   * stylesheets previously created by {...@link #inject(String)}.
+   *
+   * @param css the CSS contents of the stylesheet
+   * @param immediate if <code>true</code> the DOM will be updated  
immediately
+   *          instead of just before returning to the event loop. Using  
this
+   *          option excessively will decrease performance, especially if  
used
+   *          with an inject-css-on-init coding pattern
+   */
+  public static void injectAtEnd(String css, boolean immediate) {
+    toInjectAtEnd.push(css);
+    inject(immediate);
+  }
+
+  /**
+   * Add stylesheet data to the document as though it were declared before  
all
+   * stylesheets previously created by {...@link #inject(String)}.
+   *
+   * @param css the CSS contents of the stylesheet
+   */
+  public static void injectAtStart(String css) {
+    injectAtStart(css, false);
+  }
+
+  /**
+   * Add stylesheet data to the document as though it were declared before  
all
+   * stylesheets previously created by {...@link #inject(String)}.
+   *
+   * @param css the CSS contents of the stylesheet
+   * @param immediate if <code>true</code> the DOM will be updated  
immediately
+   *          instead of just before returning to the event loop. Using  
this
+   *          option excessively will decrease performance, especially if  
used
+   *          with an inject-css-on-init coding pattern
+   */
+  public static void injectAtStart(String css, boolean immediate) {
+    toInjectAtStart.unshift(css);
+    inject(immediate);
+  }

    /**
     * Add a stylesheet to the document. The StyleElement returned by this  
method
@@ -185,9 +278,13 @@
     *
     * @param contents the CSS contents of the stylesheet
     * @return the StyleElement that contains the newly-injected CSS
+   * @deprecated The returned StyleElement cannot be implemented  
consistently
+   *             across all browsers
     */
+  @Deprecated
    public static StyleElement injectStylesheet(String contents) {
-    return StyleInjectorImpl.IMPL.injectStyleSheet(contents);
+    toInject.push(contents);
+    return flush(toInject);
    }

    /**
@@ -197,9 +294,13 @@
     *
     * @param contents the CSS contents of the stylesheet
     * @return the StyleElement that contains the newly-injected CSS
+   * @deprecated The returned StyleElement cannot be implemented  
consistently
+   *             across all browsers
     */
+  @Deprecated
    public static StyleElement injectStylesheetAtEnd(String contents) {
-    return StyleInjectorImpl.IMPL.injectStyleSheetAtEnd(contents);
+    toInjectAtEnd.push(contents);
+    return flush(toInjectAtEnd);
    }

    /**
@@ -209,9 +310,13 @@
     *
     * @param contents the CSS contents of the stylesheet
     * @return the StyleElement that contains the newly-injected CSS
+   * @deprecated The returned StyleElement cannot be implemented  
consistently
+   *             across all browsers
     */
+  @Deprecated
    public static StyleElement injectStylesheetAtStart(String contents) {
-    return StyleInjectorImpl.IMPL.injectStyleSheetAtStart(contents);
+    toInjectAtStart.unshift(contents);
+    return flush(toInjectAtStart);
    }

    /**
@@ -224,10 +329,66 @@
     * @param style a StyleElement previously-returned from
     *          {...@link #injectStylesheet(String)}.
     * @param contents the new contents of the stylesheet.
+   * @deprecated The associated StyleElement cannot be implemented  
consistently
+   *             across all browsers
     */
+  @Deprecated
    public static void setContents(StyleElement style, String contents) {
      StyleInjectorImpl.IMPL.setContents(style, contents);
    }
+
+  /**
+   * The <code>which</code> parameter is used to support the deprecated  
API.
+   */
+  private static StyleElement flush(JavaScriptObject which) {
+    StyleElement toReturn = null;
+    StyleElement maybeReturn;
+
+    if (toInjectAtStart.length() != 0) {
+      String css = toInjectAtStart.join("");
+      maybeReturn = StyleInjectorImpl.IMPL.injectStyleSheetAtStart(css);
+      if (toInjectAtStart == which) {
+        toReturn = maybeReturn;
+      }
+      toInjectAtStart.setLength(0);
+    }
+
+    if (toInject.length() != 0) {
+      String css = toInject.join("");
+      maybeReturn = StyleInjectorImpl.IMPL.injectStyleSheet(css);
+      if (toInject == which) {
+        toReturn = maybeReturn;
+      }
+      toInject.setLength(0);
+    }
+
+    if (toInjectAtEnd.length() != 0) {
+      String css = toInjectAtEnd.join("");
+      maybeReturn = StyleInjectorImpl.IMPL.injectStyleSheetAtEnd(css);
+      if (toInjectAtEnd == which) {
+        toReturn = maybeReturn;
+      }
+      toInjectAtEnd.setLength(0);
+    }
+
+    needsInjection = false;
+    return toReturn;
+  }
+
+  private static void inject(boolean immediate) {
+    if (immediate) {
+      flush(null);
+    } else {
+      schedule();
+    }
+  }
+
+  private static void schedule() {
+    if (!needsInjection) {
+      needsInjection = true;
+      Scheduler.get().scheduleFinally(flusher);
+    }
+  }

    /**
     * Utility class.
=======================================
--- /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java       
 
Sat Oct 10 13:51:12 2009
+++ /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java       
 
Fri Oct 16 15:58:05 2009
@@ -902,7 +902,7 @@
      sw.indent();
      sw.println("if (!injected) {");
      sw.indentln("injected = true;");
-    sw.indentln(StyleInjector.class.getName()  
+ ".injectStylesheet(getText());");
+    sw.indentln(StyleInjector.class.getName() + ".inject(getText());");
      sw.indentln("return true;");
      sw.println("}");
      sw.println("return false;");
=======================================
--- /trunk/user/test/com/google/gwt/dom/client/StyleInjectorTest.java   Thu  
Jul 30 13:47:31 2009
+++ /trunk/user/test/com/google/gwt/dom/client/StyleInjectorTest.java   Fri  
Oct 16 15:58:05 2009
@@ -26,13 +26,16 @@
   */
  public class StyleInjectorTest extends GWTTestCase {

+  private static final int TEST_DELAY = 500;
+
    @Override
    public String getModuleName() {
      return "com.google.gwt.dom.DOMTest";
    }

-  @DoNotRunWith({Platform.Htmlunit})
-  public void testStyleInjector() {
+  @DoNotRunWith(value = {Platform.Htmlunit})
+  @SuppressWarnings("deprecation")
+  public void testOldMethods() {
      final DivElement elt = Document.get().createDivElement();
      elt.setId("styleInjectorTest");
      elt.setInnerHTML("Hello StyleInjector!");
@@ -43,7 +46,7 @@
      StyleInjector.injectStylesheetAtEnd("#styleInjectorTest {height:  
100px;}");

      // We need to allow the document to be redrawn
-    delayTestFinish(500);
+    delayTestFinish(TEST_DELAY);

      DeferredCommand.addCommand(new Command() {
        public void execute() {
@@ -59,8 +62,9 @@
    /**
     * Ensure that the IE createStyleSheet compatibility code is exercised.
     */
-  @DoNotRunWith({Platform.Htmlunit})
-  public void testLotsOfStyles() {
+  @DoNotRunWith(value = {Platform.Htmlunit})
+  @SuppressWarnings("deprecation")
+  public void testOldMethodsWithLotsOfStyles() {
      StyleElement[] elements = new StyleElement[100];
      for (int i = 0, j = elements.length; i < j; i++) {
        elements[i] = StyleInjector.injectStylesheet("#styleInjectorTest" + i
@@ -78,7 +82,7 @@
      Document.get().getBody().appendChild(elt);

      // We need to allow the document to be redrawn
-    delayTestFinish(500);
+    delayTestFinish(TEST_DELAY);

      DeferredCommand.addCommand(new Command() {
        public void execute() {
@@ -89,4 +93,49 @@
        }
      });
    }
-}
+
+  @DoNotRunWith(value = {Platform.Htmlunit})
+  public void testStyleInjectorBatched() {
+    testStyleInjector("testStyleInjectorBatched", false);
+  }
+
+  @DoNotRunWith(value = {Platform.Htmlunit})
+  public void testStyleInjectorImmediate() {
+    testStyleInjector("testStyleInjectorImmediate", true);
+  }
+
+  private void testStyleInjector(String testName, final boolean immediate)  
{
+
+    final DivElement elt = Document.get().createDivElement();
+    elt.setId(testName);
+    elt.setInnerHTML("Hello");
+    Document.get().getBody().appendChild(elt);
+
+    StyleInjector.inject("#" + testName
+        + " {position: absolute; left: 100px; width: 50px; height 50px;}",
+        immediate);
+    StyleInjector.injectAtStart("#" + testName
+        + " {left: 25px; width: 100px !important;}", immediate);
+    StyleInjector.injectAtEnd("#" + testName + " {height: 100px;}",  
immediate);
+
+    Command command = new Command() {
+      public void execute() {
+        assertEquals(100, elt.getOffsetLeft());
+        assertEquals(100, elt.getClientHeight());
+        assertEquals(100, elt.getClientWidth());
+
+        if (!immediate) {
+          finishTest();
+        }
+      }
+    };
+
+    if (immediate) {
+      command.execute();
+    } else {
+      DeferredCommand.addCommand(command);
+      // We need to allow the BatchedCommands to execute
+      delayTestFinish(TEST_DELAY);
+    }
+  }
+}

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to