Bug 1240198: Part 2. Handle file I/O (mostly I) for preference flags live/restart and set a few graphics preferences to the correct state. r=bsmedberg draft
authorMilan Sreckovic <milan@mozilla.com>
Mon, 02 May 2016 13:13:43 -0400
changeset 363425 cfdf07de80961888ab6888e0527a0ed70739f821
parent 363424 c16f896bb5de6dbd790ec9c124c202b9e35c2208
child 363426 71eed3e796035b499a04d1a39a05917ac05eea2b
push id17194
push usermsreckovic@mozilla.com
push dateWed, 04 May 2016 17:19:30 +0000
reviewersbsmedberg
bugs1240198
milestone49.0a1
Bug 1240198: Part 2. Handle file I/O (mostly I) for preference flags live/restart and set a few graphics preferences to the correct state. r=bsmedberg MozReview-Commit-ID: 2qLsiax28rm
modules/libpref/init/all.js
modules/libpref/prefapi.cpp
modules/libpref/prefapi.h
modules/libpref/prefread.cpp
modules/libpref/prefread.h
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -647,29 +647,29 @@ pref("gfx.layerscope.port", 23456);
 
 // Log severe performance warnings to the error console and profiles.
 // This should be use to quickly find which slow paths are used by test cases.
 pref("gfx.perf-warnings.enabled", false);
 
 // 0 = Off, 1 = Full, 2 = Tagged Images Only.
 // See eCMSMode in gfx/thebes/gfxPlatform.h
 pref("gfx.color_management.mode", 2);
-pref("gfx.color_management.display_profile", "");
+pref("gfx.color_management.display_profile", "", "restart");
 pref("gfx.color_management.rendering_intent", 0);
 pref("gfx.color_management.enablev4", false);
 
-pref("gfx.downloadable_fonts.enabled", true);
-pref("gfx.downloadable_fonts.fallback_delay", 3000);
-pref("gfx.downloadable_fonts.fallback_delay_short", 100);
+pref("gfx.downloadable_fonts.enabled", true, "live");
+pref("gfx.downloadable_fonts.fallback_delay", 3000, "live");
+pref("gfx.downloadable_fonts.fallback_delay_short", 100, "live");
 
 // disable downloadable font cache so that behavior is consistently
 // the uncached load behavior across pages (useful for testing reflow problems)
-pref("gfx.downloadable_fonts.disable_cache", false);
-
-pref("gfx.downloadable_fonts.woff2.enabled", true);
+pref("gfx.downloadable_fonts.disable_cache", false, "live");
+
+pref("gfx.downloadable_fonts.woff2.enabled", true, "live");
 
 #ifdef ANDROID
 pref("gfx.bundled_fonts.enabled", true);
 pref("gfx.bundled_fonts.force-enabled", false);
 #endif
 
 // Do we fire a notification about missing fonts, so the front-end can decide
 // whether to try and do something about it (e.g. download additional fonts)?
@@ -707,27 +707,27 @@ pref("gfx.font_rendering.directwrite.for
 pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
 #endif
 
 pref("gfx.font_rendering.opentype_svg.enabled", true);
 
 #ifdef XP_WIN
 // comma separated list of backends to use in order of preference
 // e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo");
-pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo");
-pref("gfx.content.azure.backends", "direct2d1.1,cairo");
+pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo", "restart");
+pref("gfx.content.azure.backends", "direct2d1.1,cairo", "restart");
 #else
 #ifdef XP_MACOSX
-pref("gfx.content.azure.backends", "skia,cg");
-pref("gfx.canvas.azure.backends", "skia");
+pref("gfx.content.azure.backends", "skia,cg", "restart");
+pref("gfx.canvas.azure.backends", "skia", "restart");
 // Accelerated cg canvas where available (10.7+)
 pref("gfx.canvas.azure.accelerated", true);
 #else
-pref("gfx.canvas.azure.backends", "skia");
-pref("gfx.content.azure.backends", "cairo");
+pref("gfx.canvas.azure.backends", "skia", "restart");
+pref("gfx.content.azure.backends", "cairo", "restart");
 #endif
 #endif
 
 pref("gfx.work-around-driver-bugs", true);
 pref("gfx.prefer-mesa-llvmpipe", false);
 
 pref("gfx.draw-color-bars", false);
 
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -354,16 +354,18 @@ pref_savePrefs(PLDHashTable* aTable)
 
         } else if (pref->prefFlags.IsTypeBool()) {
             prefValue = (sourcePref->boolVal) ? "true" : "false";
         }
 
         nsAutoCString prefName;
         str_escape(pref->key, prefName);
 
+        // Note that we don't need to (we have the information on creation),
+        // nor want to (versioning nightmare) save the option flags.
         savedPrefs[j++] = ToNewCString(prefPrefix +
                                        prefName +
                                        NS_LITERAL_CSTRING("\", ") +
                                        prefValue +
                                        NS_LITERAL_CSTRING(");"));
     }
 
     return savedPrefs;
@@ -992,22 +994,27 @@ static nsresult pref_DoCallback(const ch
     return rv;
 }
 
 void PREF_ReaderCallback(void       *closure,
                          const char *pref,
                          PrefValue   value,
                          PrefType    type,
                          bool        isDefault,
-                         bool        isStickyDefault)
-
+                         bool        isStickyDefault,
+                         PrefRestartType restartType)
 {
     uint32_t flags = 0;
     if (isDefault) {
         flags |= kPrefSetDefault;
         if (isStickyDefault) {
             flags |= kPrefStickyDefault;
         }
     } else {
         flags |= kPrefForceSet;
     }
+    if (restartType == PrefRestartType::Live) {
+        flags |= kPrefLive;
+    } else if (restartType == PrefRestartType::Restart) {
+        flags |= kPrefRestart;
+    }
     pref_HashPref(pref, value, type, flags);
 }
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -52,16 +52,23 @@ void        PREF_CleanupPrefs();
 
 enum class PrefType {
   Invalid = 0,
   String = 1,
   Int = 2,
   Bool = 3,
 };
 
+// Whether changing the preference needs a restart or not (if we know.)
+enum class PrefRestartType {
+  Unknown = 0,
+  Live = 1,
+  Restart = 2
+};
+
 // Keep the type of the preference, as well as the flags guiding its behaviour.
 class PrefTypeFlags
 {
 public:
   PrefTypeFlags() : mValue(AsInt(PrefType::Invalid)) {}
   explicit PrefTypeFlags(PrefType aType) : mValue(AsInt(aType)) {}
   PrefTypeFlags& Reset() { mValue = AsInt(PrefType::Invalid); return *this; }
 
@@ -272,14 +279,15 @@ nsresult PREF_UnregisterCallback(const c
 /*
  * Used by nsPrefService as the callback function of the 'pref' parser
  */
 void PREF_ReaderCallback( void *closure,
                           const char *pref,
                           PrefValue   value,
                           PrefType    type,
                           bool        isDefault,
-                          bool        isStickyDefault);
+                          bool        isStickyDefault,
+                          PrefRestartType restartType);
 
 #ifdef __cplusplus
 }
 #endif
 #endif
--- a/modules/libpref/prefread.cpp
+++ b/modules/libpref/prefread.cpp
@@ -1,36 +1,31 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include "prefread.h"
 #include "nsString.h"
 #include "nsUTF8Utils.h"
 
-#ifdef TEST_PREFREAD
-#include <stdio.h>
-#define NS_WARNING(_s) printf(">>> " _s "!\n")
-#define NS_NOTREACHED(_s) NS_WARNING(_s)
-#else
-#include "nsDebug.h" // for NS_WARNING
-#endif
-
 /* pref parser states */
 enum {
     PREF_PARSE_INIT,
     PREF_PARSE_MATCH_STRING,
     PREF_PARSE_UNTIL_NAME,
     PREF_PARSE_QUOTED_STRING,
     PREF_PARSE_UNTIL_COMMA,
     PREF_PARSE_UNTIL_VALUE,
     PREF_PARSE_INT_VALUE,
+    PREF_PARSE_FLAGS,
+    PREF_PARSE_FLAGS_STRING,
     PREF_PARSE_COMMENT_MAYBE_START,
     PREF_PARSE_COMMENT_BLOCK,
     PREF_PARSE_COMMENT_BLOCK_MAYBE_END,
     PREF_PARSE_ESC_SEQUENCE,
     PREF_PARSE_HEX_ESCAPE,
     PREF_PARSE_UTF16_LOW_SURROGATE,
     PREF_PARSE_UNTIL_OPEN_PAREN,
     PREF_PARSE_UNTIL_CLOSE_PAREN,
@@ -43,16 +38,19 @@ enum {
 #define BITS_PER_HEX_DIGIT      4
 
 static const char kUserPref[] = "user_pref";
 static const char kPref[] = "pref";
 static const char kPrefSticky[] = "sticky_pref";
 static const char kTrue[] = "true";
 static const char kFalse[] = "false";
 
+static const char kFlagLive[] = "live";
+static const char kFlagRestart[] = "restart";
+
 /**
  * pref_GrowBuf
  * 
  * this function will increase the size of the buffer owned
  * by the given pref parse state.  We currently use a simple
  * doubling algorithm, but the only hard requirement is that
  * it increase the buffer by at least the size of the ps->esctmp
  * buffer used for escape processing (currently 6 bytes).
@@ -77,20 +75,16 @@ pref_GrowBuf(PrefParseState *ps)
     curPos = ps->lbcur - ps->lb;
     valPos = ps->vb    - ps->lb;
 
     if (bufLen == 0)
         bufLen = 128;  /* default buffer size */
     else
         bufLen <<= 1;  /* double buffer size */
 
-#ifdef TEST_PREFREAD
-    fprintf(stderr, ">>> realloc(%d)\n", bufLen);
-#endif
-
     ps->lb = (char*) realloc(ps->lb, bufLen);
     if (!ps->lb)
         return false;
 
     ps->lbcur = ps->lb + curPos;
     ps->lbend = ps->lb + bufLen;
     ps->vb    = ps->lb + valPos;
 
@@ -141,17 +135,20 @@ pref_DoCallback(PrefParseState *ps)
         break;
     case PrefType::Bool:
         value.boolVal = (ps->vb == kTrue);
         break;
     default:
         break;
     }
     (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault,
-                  ps->fstickydefault);
+                  ps->fstickydefault,
+                  (ps->fflaglive ? PrefRestartType::Live :
+                                   (ps->fflagrestart ? PrefRestartType::Restart :
+                                                       PrefRestartType::Unknown)));
     return true;
 }
 
 void
 PREF_InitParseState(PrefParseState *ps, PrefReader reader,
                     PrefParseErrorReporter reporter, void *closure)
 {
     memset(ps, 0, sizeof(*ps));
@@ -167,19 +164,20 @@ PREF_FinalizeParseState(PrefParseState *
         free(ps->lb);
 }
 
 /**
  * Pseudo-BNF
  * ----------
  * function      = LJUNK function-name JUNK function-args
  * function-name = "user_pref" | "pref" | "sticky_pref"
- * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";"
+ * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value [, pref-flags] ")" JUNK ";"
  * pref-name     = quoted-string
  * pref-value    = quoted-string | "true" | "false" | integer-value
+ * pref-flags    = (optional) for now - L or R (live or restart)
  * JUNK          = *(WS | comment-block | comment-line)
  * LJUNK         = *(WS | comment-block | comment-line | bcomment-line)
  * WS            = SP | HT | LF | VT | FF | CR
  * SP            = <US-ASCII SP, space (32)>
  * HT            = <US-ASCII HT, horizontal-tab (9)>
  * LF            = <US-ASCII LF, linefeed (10)>
  * VT            = <US-ASCII HT, vertical-tab (11)>
  * FF            = <US-ASCII FF, form-feed (12)>
@@ -210,16 +208,18 @@ PREF_ParseBuf(PrefParseState *ps, const 
         /* initial state */
         case PREF_PARSE_INIT:
             if (ps->lbcur != ps->lb) { /* reset state */
                 ps->lbcur = ps->lb;
                 ps->vb    = nullptr;
                 ps->vtype = PrefType::Invalid;
                 ps->fdefault = false;
                 ps->fstickydefault = false;
+                ps->fflaglive = false;
+                ps->fflagrestart = false;
             }
             switch (c) {
             case '/':       /* begin comment block or line? */
                 state = PREF_PARSE_COMMENT_MAYBE_START;
                 break;
             case '#':       /* accept shell style comments */
                 state = PREF_PARSE_UNTIL_EOL;
                 break;
@@ -358,16 +358,19 @@ PREF_ParseBuf(PrefParseState *ps, const 
                 if (c == ')')
                     state = PREF_PARSE_UNTIL_SEMICOLON;
                 else if (c == '/') { /* allow embedded comment */
                     ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
                     state = PREF_PARSE_COMMENT_MAYBE_START;
                 }
                 else if (isspace(c))
                     state = PREF_PARSE_UNTIL_CLOSE_PAREN;
+                else if (c == ',') {
+                    state = PREF_PARSE_FLAGS;
+                }
                 else {
                     pref_ReportParseProblem(*ps, "while parsing integer", lineNum, true);
                     NS_WARNING("malformed pref file");
                     return false;
                 }
             }
             break;
 
@@ -546,22 +549,24 @@ PREF_ParseBuf(PrefParseState *ps, const 
             else if (!isspace(c)) {
                 pref_ReportParseProblem(*ps, "need space, comment or open parentheses",
                                         lineNum, true);
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
         case PREF_PARSE_UNTIL_CLOSE_PAREN:
-            /* tolerate only whitespace and embedded comments  */
+            /* tolerate only whitespace, embedded comments and optional flags  */
             if (c == ')') {
                 state = PREF_PARSE_UNTIL_SEMICOLON;
             } else if (c == '/') {
                 ps->nextstate = state; /* return here when done with comment */
                 state = PREF_PARSE_COMMENT_MAYBE_START;
+            } else if (c == ',') {
+                state = PREF_PARSE_FLAGS;
             } else if (!isspace(c)) {
                 pref_ReportParseProblem(*ps, "need space, comment or closing parentheses",
                                         lineNum, true);
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
 
@@ -580,78 +585,60 @@ PREF_ParseBuf(PrefParseState *ps, const 
             else if (!isspace(c)) {
                 pref_ReportParseProblem(*ps, "need space, comment or semicolon",
                                         lineNum, true);
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
 
+        case PREF_PARSE_FLAGS_STRING:
+            /* we assume that the initial quote has already been consumed */
+            if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) {
+                return false; /* out of memory */
+            }
+            if (!ps->fflaglive && !ps->fflagrestart && (c == 'l' || c == 'r')) {
+                if (c == kFlagLive[0]) {
+                    ps->fflaglive = true;
+                } else if (c == kFlagRestart[0]) {
+                    ps->fflagrestart = true;
+                }
+            } else if (c == ps->quotechar) {
+                state = PREF_PARSE_UNTIL_CLOSE_PAREN;
+            } else if (c == '\r' || c == '\n' || c == 0x1A) {
+                pref_ReportParseProblem(*ps, "runaway flag value", lineNum, true);
+                NS_WARNING("malformed pref file");
+            } else {
+                *ps->lbcur++ = c;
+            }
+            break;
+
+        case PREF_PARSE_FLAGS:
+            if (c == ')') {
+                state = PREF_PARSE_UNTIL_SEMICOLON;
+            } else if (c == ps->quotechar) {
+                state = PREF_PARSE_FLAGS_STRING;
+            } else if (c == '/') {
+                ps->nextstate = state; /* return here when done with comment */
+                state = PREF_PARSE_COMMENT_MAYBE_START;
+            } else if (!isspace(c)) {
+                pref_ReportParseProblem(*ps, "need flag, closed parentheses, space or comment",
+                                        lineNum, true);
+                NS_WARNING("malformed pref file");
+                return false;
+            }
+            break;
+
         /* eol parsing */
         case PREF_PARSE_UNTIL_EOL:
             /* need to handle mac, unix, or dos line endings.
              * PREF_PARSE_INIT will eat the next \n in case
              * we have \r\n. */
             if (c == '\r' || c == '\n' || c == 0x1A) {
                 state = ps->nextstate;
                 ps->nextstate = PREF_PARSE_INIT; /* reset next state */
             }
             break;
         }
     }
     ps->state = state;
     return true;
 }
-
-#ifdef TEST_PREFREAD
-
-static void
-pref_reader(void       *closure, 
-            const char *pref,
-            PrefValue   val,
-            PrefType    type,
-            bool        defPref)
-{
-    printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
-    switch (type) {
-    case PREF_STRING:
-        printf("\"%s\");\n", val.stringVal);
-        break;
-    case PREF_INT:
-        printf("%i);\n", val.intVal);
-        break;
-    case PREF_BOOL:
-        printf("%s);\n", val.boolVal == false ? "false" : "true");
-        break;
-    }
-}
-
-int
-main(int argc, char **argv)
-{
-    PrefParseState ps;
-    char buf[4096];     /* i/o buffer */
-    FILE *fp;
-    int n;
-
-    if (argc == 1) {
-        printf("usage: prefread file.js\n");
-        return -1;
-    }
-
-    fp = fopen(argv[1], "r");
-    if (!fp) {
-        printf("failed to open file\n");
-        return -1;
-    }
-
-    PREF_InitParseState(&ps, pref_reader, nullptr, nullptr);
-
-    while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
-        PREF_ParseBuf(&ps, buf, n);
-
-    PREF_FinalizeParseState(&ps);
-
-    fclose(fp);
-    return 0;
-}
-
-#endif /* TEST_PREFREAD */
--- a/modules/libpref/prefread.h
+++ b/modules/libpref/prefread.h
@@ -29,44 +29,47 @@ extern "C" {
  * @param stickyPref
  *        default preference marked as a "sticky" pref
  */
 typedef void (*PrefReader)(void       *closure,
                            const char *pref,
                            PrefValue   val,
                            PrefType    type,
                            bool        defPref,
-                           bool        stickyPref);
+                           bool        stickyPref,
+                           PrefRestartType restartType);
 
 /**
  * Report any errors or warnings we encounter during parsing.
  */
 typedef void (*PrefParseErrorReporter)(const char* message, int line, bool error);
 
 /* structure fields are private */
 typedef struct PrefParseState {
     PrefReader  reader;
     PrefParseErrorReporter reporter;
     void       *closure;
     int         state;      /* PREF_PARSE_...                */
     int         nextstate;  /* sometimes used...             */
     const char *smatch;     /* string to match               */
     int         sindex;     /* next char of smatch to check  */
                             /* also, counter in \u parsing   */
-    char16_t   utf16[2];   /* parsing UTF16  (\u) escape    */
+    char16_t    utf16[2];   /* parsing UTF16  (\u) escape    */
     int         esclen;     /* length in esctmp              */
     char        esctmp[6];  /* raw escape to put back if err */
     char        quotechar;  /* char delimiter for quotations */
     char       *lb;         /* line buffer (only allocation) */
     char       *lbcur;      /* line buffer cursor            */
     char       *lbend;      /* line buffer end               */
     char       *vb;         /* value buffer (ptr into lb)    */
     PrefType    vtype;      /* PREF_STRING,INT,BOOL          */
-    bool        fdefault;   /* true if (default) pref        */
-    bool        fstickydefault; /* true if (sticky) pref     */
+    bool        fdefault:1;      /* true if (default) pref    */
+    bool        fstickydefault:1;/* true if (sticky) pref     */
+    bool        fflaglive:1;     /* true if (live) pref       */
+    bool        fflagrestart:1;  /* true if (restart) pref    */
 } PrefParseState;
 
 /**
  * PREF_InitParseState
  *
  * Called to initialize a PrefParseState instance.
  *
  * @param ps
@@ -76,17 +79,17 @@ typedef struct PrefParseState {
  *        preference name value pair extracted.
  * @param reporter
  *        PrefParseErrorReporter callback function, which will be called if we
  *        encounter any errors (stop) or warnings (continue) during parsing.
  * @param closure
  *        PrefReader closure.
  */
 void PREF_InitParseState(PrefParseState *ps, PrefReader reader,
-			 PrefParseErrorReporter reporter, void *closure);
+                         PrefParseErrorReporter reporter, void *closure);
 
 /**
  * PREF_FinalizeParseState
  *
  * Called to release any memory in use by the PrefParseState instance.
  *
  * @param ps
  *        PrefParseState instance.