[webkit-changes] [60774] trunk/WebCore

Oliver Hunt oliver at apple.com
Tue Jun 8 16:40:05 PDT 2010


Why do we need this?  why can't we just use the same logic used for postMessage?  Having multiple different functions to do object serialisation seems unnecessary.

--Oliver


On Jun 7, 2010, at 4:33 AM, eric at webkit.org wrote:

> Revision
> 60774
> Author
> eric at webkit.org
> Date
> 2010-06-07 04:33:11 -0700 (Mon, 07 Jun 2010)
> Log Message
> 
> 2010-06-07  Pavel Podivilov  <podivilov at chromium.org>
> 
>         Reviewed by Pavel Feldman.
> 
>         Web Inspector: Implement JSON parsing for InspectorValue.
>         https://bugs.webkit.org/show_bug.cgi?id=40064
> 
>         * inspector/InspectorValues.cpp:
>         (WebCore::):
>         (WebCore::InspectorValue::asBool):
>         (WebCore::InspectorValue::asNumber):
>         (WebCore::InspectorValue::asString):
>         (WebCore::InspectorValue::asObject):
>         (WebCore::InspectorValue::asArray):
>         (WebCore::InspectorValue::readJSON):
>         (WebCore::InspectorValue::writeJSON):
>         (WebCore::InspectorBasicValue::asBool):
>         (WebCore::InspectorBasicValue::asNumber):
>         (WebCore::InspectorBasicValue::writeJSON):
>         (WebCore::InspectorString::asString):
>         (WebCore::InspectorObject::asObject):
>         (WebCore::InspectorObject::getBool):
>         (WebCore::InspectorObject::getNumber):
>         (WebCore::InspectorObject::getString):
>         (WebCore::InspectorObject::getObject):
>         (WebCore::InspectorObject::getArray):
>         (WebCore::InspectorObject::get):
>         (WebCore::InspectorArray::asArray):
>         * inspector/InspectorValues.h:
>         (WebCore::InspectorObject::begin):
>         (WebCore::InspectorObject::end):
> Modified Paths
> 
> trunk/WebCore/ChangeLog
> trunk/WebCore/inspector/InspectorValues.cpp
> trunk/WebCore/inspector/InspectorValues.h
> Diff
> 
> Modified: trunk/WebCore/ChangeLog (60773 => 60774)
> 
> --- trunk/WebCore/ChangeLog	2010-06-07 11:24:14 UTC (rev 60773)
> +++ trunk/WebCore/ChangeLog	2010-06-07 11:33:11 UTC (rev 60774)
> @@ -1,3 +1,35 @@
> +2010-06-07  Pavel Podivilov  <podivilov at chromium.org>
> +
> +        Reviewed by Pavel Feldman.
> +
> +        Web Inspector: Implement JSON parsing for InspectorValue.
> +        https://bugs.webkit.org/show_bug.cgi?id=40064
> +
> +        * inspector/InspectorValues.cpp:
> +        (WebCore::):
> +        (WebCore::InspectorValue::asBool):
> +        (WebCore::InspectorValue::asNumber):
> +        (WebCore::InspectorValue::asString):
> +        (WebCore::InspectorValue::asObject):
> +        (WebCore::InspectorValue::asArray):
> +        (WebCore::InspectorValue::readJSON):
> +        (WebCore::InspectorValue::writeJSON):
> +        (WebCore::InspectorBasicValue::asBool):
> +        (WebCore::InspectorBasicValue::asNumber):
> +        (WebCore::InspectorBasicValue::writeJSON):
> +        (WebCore::InspectorString::asString):
> +        (WebCore::InspectorObject::asObject):
> +        (WebCore::InspectorObject::getBool):
> +        (WebCore::InspectorObject::getNumber):
> +        (WebCore::InspectorObject::getString):
> +        (WebCore::InspectorObject::getObject):
> +        (WebCore::InspectorObject::getArray):
> +        (WebCore::InspectorObject::get):
> +        (WebCore::InspectorArray::asArray):
> +        * inspector/InspectorValues.h:
> +        (WebCore::InspectorObject::begin):
> +        (WebCore::InspectorObject::end):
> +
>  2010-06-07  Jocelyn Turcotte  <jocelyn.turcotte at nokia.com>
>  
>          Reviewed by Simon Hausmann.
> Modified: trunk/WebCore/inspector/InspectorValues.cpp (60773 => 60774)
> 
> --- trunk/WebCore/inspector/InspectorValues.cpp	2010-06-07 11:24:14 UTC (rev 60773)
> +++ trunk/WebCore/inspector/InspectorValues.cpp	2010-06-07 11:33:11 UTC (rev 60774)
> @@ -35,6 +35,407 @@
>  
>  namespace WebCore {
>  
> +namespace {
> +
> +static const int stackLimit = 1000;
> +
> +enum Token {
> +    OBJECT_BEGIN,
> +    OBJECT_END,
> +    ARRAY_BEGIN,
> +    ARRAY_END,
> +    STRING,
> +    NUMBER,
> +    BOOL_TRUE,
> +    BOOL_FALSE,
> +    NULL_TOKEN,
> +    LIST_SEPARATOR,
> +    OBJECT_PAIR_SEPARATOR,
> +    INVALID_TOKEN,
> +};
> +    
> +const char* const nullString = "null";
> +const char* const trueString = "true";
> +const char* const falseString = "false";
> +
> +bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token)
> +{
> +    while (start < end && *token != '\0' && *start++ == *token++) { }
> +    if (*token != '\0')
> +        return false;
> +    *tokenEnd = start;
> +    return true;
> +}
> +
> +bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros)
> +{
> +    if (start == end)
> +        return false;
> +    bool haveLeadingZero = '0' == *start;
> +    int length = 0;
> +    while (start < end && '0' <= *start && *start <= '9') {
> +        ++start;
> +        ++length;
> +    }
> +    if (!length)
> +        return false;
> +    if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
> +        return false;
> +    *tokenEnd = start;
> +    return true;
> +}
> +
> +bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
> +{
> +    // We just grab the number here.  We validate the size in DecodeNumber.
> +    // According   to RFC4627, a valid number is: [minus] int [frac] [exp]
> +    if (start == end)
> +        return false;
> +    UChar c = *start;
> +    if ('-' == c)
> +        ++start;
> +
> +    if (!readInt(start, end, &start, false))
> +        return false;
> +    if (start == end) {
> +        *tokenEnd = start;
> +        return true;
> +    }
> +
> +    // Optional fraction part
> +    c = *start;
> +    if ('.' == c) {
> +        ++start;
> +        if (!readInt(start, end, &start, true))
> +            return false;
> +        if (start == end) {
> +            *tokenEnd = start;
> +            return true;
> +        }
> +        c = *start;
> +    }
> +
> +    // Optional exponent part
> +    if ('e' == c || 'E' == c) {
> +        ++start;
> +        if (start == end)
> +            return false;
> +        c = *start;
> +        if ('-' == c || '+' == c) {
> +            ++start;
> +            if (start == end)
> +                return false;
> +        }
> +        if (!readInt(start, end, &start, true))
> +            return false;
> +    }
> +
> +    *tokenEnd = start;
> +    return true;
> +}
> +
> +bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits)
> +{
> +    if (end - start < digits)
> +        return false;
> +    for (int i = 0; i < digits; ++i) {
> +        UChar c = *start++;
> +        if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
> +            return false;
> +    }
> +    *tokenEnd = start;
> +    return true;
> +}
> +
> +bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
> +{
> +    while (start < end) {
> +        UChar c = *start++;
> +        if ('\\' == c) {
> +            c = *start++;
> +            // Make sure the escaped char is valid.
> +            switch (c) {
> +            case 'x':
> +                if (!readHexDigits(start, end, &start, 2))
> +                    return false;
> +                break;
> +            case 'u':
> +                if (!readHexDigits(start, end, &start, 4))
> +                    return false;
> +                break;
> +            case '\\':
> +            case '/':
> +            case 'b':
> +            case 'f':
> +            case 'n':
> +            case 'r':
> +            case 't':
> +            case 'v':
> +            case '"':
> +                break;
> +            default:
> +                return false;
> +            }
> +        } else if ('"' == c) {
> +            *tokenEnd = start;
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +Token parseToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
> +{
> +    if (start == end)
> +        return INVALID_TOKEN;
> +
> +    switch (*start) {
> +    case 'n':
> +        if (parseConstToken(start, end, tokenEnd, nullString))
> +            return NULL_TOKEN;
> +        break;
> +    case 't':
> +        if (parseConstToken(start, end, tokenEnd, trueString))
> +            return BOOL_TRUE;
> +        break;
> +    case 'f':
> +        if (parseConstToken(start, end, tokenEnd, falseString))
> +            return BOOL_FALSE;
> +        break;
> +    case '[':
> +        *tokenEnd = start + 1;
> +        return ARRAY_BEGIN;
> +    case ']':
> +        *tokenEnd = start + 1;
> +        return ARRAY_END;
> +    case ',':
> +        *tokenEnd = start + 1;
> +        return LIST_SEPARATOR;
> +    case '{':
> +        *tokenEnd = start + 1;
> +        return OBJECT_BEGIN;
> +    case '}':
> +        *tokenEnd = start + 1;
> +        return OBJECT_END;
> +    case ':':
> +        *tokenEnd = start + 1;
> +        return OBJECT_PAIR_SEPARATOR;
> +    case '0':
> +    case '1':
> +    case '2':
> +    case '3':
> +    case '4':
> +    case '5':
> +    case '6':
> +    case '7':
> +    case '8':
> +    case '9':
> +    case '-':
> +        if (parseNumberToken(start, end, tokenEnd)) 
> +            return NUMBER;
> +        break;            
> +    case '"':
> +        if (parseStringToken(start + 1, end, tokenEnd)) 
> +            return STRING;
> +        break;
> +    }
> +    return INVALID_TOKEN;
> +}
> +
> +inline int hexToInt(UChar c)
> +{
> +    if ('0' <= c && c <= '9')
> +        return c - '0';
> +    if ('A' <= c && c <= 'F')
> +        return c - 'A' + 10;
> +    if ('a' <= c && c <= 'f')
> +        return c - 'a' + 10;
> +    ASSERT_NOT_REACHED();
> +    return 0;
> +}
> +
> +bool decodeString(const UChar* start, const UChar* end, Vector<UChar>* output)
> +{
> +    while (start < end) {
> +        UChar c = *start++;
> +        if ('\\' != c) {
> +            output->append(c);
> +            continue;
> +        }
> +        c = *start++;
> +        switch (c) {
> +        case '"':
> +        case '/':
> +        case '\\':
> +            break;
> +        case 'b':
> +            c = '\b';
> +            break;
> +        case 'f':
> +            c = '\f';
> +            break;
> +        case 'n':
> +            c = '\n';
> +            break;
> +        case 'r':
> +            c = '\r';
> +            break;
> +        case 't':
> +            c = '\t';
> +            break;
> +        case 'v':
> +            c = '\v';
> +            break;
> +        case 'x':
> +            c = (hexToInt(*start) << 4) +
> +                hexToInt(*(start + 1));
> +            start += 2;
> +            break;
> +        case 'u':
> +            c = (hexToInt(*start) << 12) +
> +                (hexToInt(*(start + 1)) << 8) +
> +                (hexToInt(*(start + 2)) << 4) +
> +                hexToInt(*(start + 3));
> +            start += 4;
> +            break;
> +        default:
> +            return false;
> +        }
> +        output->append(c);
> +    }
> +    return true;
> +}
> +
> +bool decodeString(const UChar* start, const UChar* end, String* output)
> +{
> +    if (start == end) {
> +        *output = "";
> +        return true;
> +    }
> +    if (start > end)
> +        return false;
> +    Vector<UChar> buffer;
> +    buffer.reserveCapacity(end - start);
> +    if (!decodeString(start, end, &buffer))
> +        return false;
> +    *output = String(buffer.data(), buffer.size());    
> +    return true;
> +}
> +
> +PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth)
> +{
> +    if (depth > stackLimit)
> +        return 0;
> +
> +    RefPtr<InspectorValue> result;
> +    const UChar* tokenEnd;
> +    Token token = parseToken(start, end, &tokenEnd);
> +    switch (token) {
> +    case INVALID_TOKEN:
> +        return 0;
> +    case NULL_TOKEN:
> +        result = InspectorValue::null();
> +        break;
> +    case BOOL_TRUE:
> +        result = InspectorBasicValue::create(true);
> +        break;
> +    case BOOL_FALSE:
> +        result = InspectorBasicValue::create(false);
> +        break;
> +    case NUMBER: {
> +        bool ok;
> +        double value = charactersToDouble(start, tokenEnd - start, &ok);
> +        if (!ok)
> +            return 0;
> +        result = InspectorBasicValue::create(value);
> +        break;
> +    }
> +    case STRING: {
> +        String value;
> +        bool ok = decodeString(start + 1, tokenEnd - 1, &value);
> +        if (!ok)
> +            return 0;
> +        result = InspectorString::create(value);
> +        break;
> +    }
> +    case ARRAY_BEGIN: {
> +        RefPtr<InspectorArray> array = InspectorArray::create();
> +        start = tokenEnd;
> +        token = parseToken(start, end, &tokenEnd);
> +        while (token != ARRAY_END) {
> +            RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
> +            if (!arrayNode)
> +                return 0;
> +            array->push(arrayNode);
> +
> +            // After a list value, we expect a comma or the end of the list.
> +            start = tokenEnd;
> +            token = parseToken(start, end, &tokenEnd);
> +            if (token == LIST_SEPARATOR) {
> +                start = tokenEnd;
> +                token = parseToken(start, end, &tokenEnd);
> +                if (token == ARRAY_END)
> +                    return 0;
> +            } else if (token != ARRAY_END) {
> +                // Unexpected value after list value.  Bail out.
> +                return 0;
> +            }
> +        }
> +        if (token != ARRAY_END)
> +            return 0;
> +        result = array.release();
> +        break;
> +    }
> +    case OBJECT_BEGIN: {
> +        RefPtr<InspectorObject> object = InspectorObject::create();
> +        start = tokenEnd;
> +        token = parseToken(start, end, &tokenEnd);
> +        while (token != OBJECT_END) {
> +            if (token != STRING)
> +                return 0;
> +            String key;
> +            if (!decodeString(start + 1, tokenEnd - 1, &key))
> +                return 0;
> +            start = tokenEnd;
> +
> +            token = parseToken(start, end, &tokenEnd);
> +            if (token != OBJECT_PAIR_SEPARATOR)
> +                return 0;
> +            start = tokenEnd;
> +
> +            RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1);
> +            if (!value)
> +                return 0;
> +            object->set(key, value);
> +            start = tokenEnd;
> +
> +            // After a key/value pair, we expect a comma or the end of the
> +            // object.
> +            token = parseToken(start, end, &tokenEnd);
> +            if (token == LIST_SEPARATOR) {
> +                start = tokenEnd;
> +                token = parseToken(start, end, &tokenEnd);
> +                 if (token == OBJECT_END)
> +                    return 0;
> +            } else if (token != OBJECT_END) {
> +                // Unexpected value after last object value.  Bail out.
> +                return 0;
> +            }
> +        }
> +        if (token != OBJECT_END)
> +            return 0;
> +        result = object.release();
> +        break;
> +    }
> +
> +    default:
> +        // We got a token that's not a value.
> +        return 0;
> +    }
> +    *valueTokenEnd = tokenEnd;
> +    return result.release();
> +}
> +
>  inline bool escapeChar(UChar c, Vector<UChar>* dst)
>  {
>      switch (c) {
> @@ -71,6 +472,44 @@
>      dst->append('"');
>  }
>  
> +} // anonymous namespace
> +
> +bool InspectorValue::asBool(bool*) const
> +{
> +    return false;
> +}
> +
> +bool InspectorValue::asNumber(double*) const
> +{
> +    return false;
> +}
> +
> +bool InspectorValue::asString(String*) const
> +{
> +    return false;
> +}
> +
> +PassRefPtr<InspectorObject> InspectorValue::asObject()
> +{
> +    return 0;
> +}
> +
> +PassRefPtr<InspectorArray> InspectorValue::asArray()
> +{
> +    return 0;
> +}
> +
> +PassRefPtr<InspectorValue> InspectorValue::readJSON(const String& json)
> +{
> +    const UChar* start = json.characters();
> +    const UChar* end = json.characters() + json.length();
> +    const UChar *tokenEnd;
> +    RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
> +    if (!value || tokenEnd != end)
> +        return 0;
> +    return value.release();
> +}
> +
>  String InspectorValue::toJSONString() const
>  {
>      Vector<UChar> result;
> @@ -82,29 +521,104 @@
>  void InspectorValue::writeJSON(Vector<UChar>* output) const
>  {
>      ASSERT(m_type == TypeNull);
> -    output->append("null", 4);
> +    output->append(nullString, 4);
>  }
>  
> +bool InspectorBasicValue::asBool(bool* output) const
> +{
> +    if (type() != TypeBoolean)
> +        return false;
> +    *output = m_boolValue;
> +    return true;
> +}
> +
> +bool InspectorBasicValue::asNumber(double* output) const
> +{
> +    if (type() != TypeDouble)
> +        return false;
> +    *output = m_doubleValue;
> +    return true;
> +}
> +
>  void InspectorBasicValue::writeJSON(Vector<UChar>* output) const
>  {
>      ASSERT(type() == TypeBoolean || type() == TypeDouble);
>      if (type() == TypeBoolean) {
>          if (m_boolValue)
> -            output->append("true", 4);
> +            output->append(trueString, 4);
>          else
> -            output->append("false", 5);
> +            output->append(falseString, 5);
>      } else if (type() == TypeDouble) {
>          String value = String::format("%f", m_doubleValue);
>          output->append(value.characters(), value.length());
>      }
>  }
>  
> +bool InspectorString::asString(String* output) const
> +{
> +    *output = m_stringValue;
> +    return true;
> +}
> +
>  void InspectorString::writeJSON(Vector<UChar>* output) const
>  {
>      ASSERT(type() == TypeString);
>      doubleQuoteString(m_stringValue, output);
>  }
>  
> +PassRefPtr<InspectorObject> InspectorObject::asObject()
> +{
> +    return this;
> +}
> +
> +bool InspectorObject::getBool(const String& name, bool* output) const
> +{
> +    RefPtr<InspectorValue> value = get(name);
> +    if (!value)
> +        return false;
> +    return value->asBool(output);
> +}
> +
> +bool InspectorObject::getNumber(const String& name, double* output) const
> +{
> +    RefPtr<InspectorValue> value = get(name);
> +    if (!value)
> +        return false;
> +    return value->asNumber(output);
> +}
> +
> +bool InspectorObject::getString(const String& name, String* output) const
> +{
> +    RefPtr<InspectorValue> value = get(name);
> +    if (!value)
> +        return false;
> +    return value->asString(output);
> +}
> +
> +PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const
> +{
> +    PassRefPtr<InspectorValue> value = get(name);
> +    if (!value)
> +        return false;
> +    return value->asObject();
> +}
> +
> +PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const
> +{
> +    PassRefPtr<InspectorValue> value = get(name);
> +    if (!value)
> +        return false;
> +    return value->asArray();
> +}
> +
> +PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
> +{
> +    Dictionary::const_iterator it = m_data.find(name);
> +    if (it == m_data.end())
> +        return 0;
> +    return it->second;
> +}
> +
>  void InspectorObject::writeJSON(Vector<UChar>* output) const
>  {
>      output->append('{');
> @@ -120,6 +634,11 @@
>      output->append('}');
>  }
>  
> +PassRefPtr<InspectorArray> InspectorArray::asArray()
> +{
> +    return this;
> +}
> +
>  void InspectorArray::writeJSON(Vector<UChar>* output) const
>  {
>      output->append('[');
> Modified: trunk/WebCore/inspector/InspectorValues.h (60773 => 60774)
> 
> --- trunk/WebCore/inspector/InspectorValues.h	2010-06-07 11:24:14 UTC (rev 60773)
> +++ trunk/WebCore/inspector/InspectorValues.h	2010-06-07 11:33:11 UTC (rev 60774)
> @@ -42,6 +42,8 @@
>  
>  namespace WebCore {
>  
> +class InspectorArray;
> +class InspectorObject;
>  class String;
>  
>  class InspectorValue : public RefCounted<InspectorValue> {
> @@ -65,6 +67,14 @@
>  
>      Type type() const { return m_type; }
>  
> +    virtual bool asBool(bool* output) const;
> +    virtual bool asNumber(double* output) const;
> +    virtual bool asString(String* output) const;
> +    virtual PassRefPtr<InspectorObject> asObject();
> +    virtual PassRefPtr<InspectorArray> asArray();
> +
> +    static PassRefPtr<InspectorValue> readJSON(const String& json);
> +
>      String toJSONString() const;
>      virtual void writeJSON(Vector<UChar>* output) const;
>  
> @@ -93,6 +103,9 @@
>          return adoptRef(new InspectorBasicValue(value));
>      }
>  
> +    virtual bool asBool(bool* output) const;
> +    virtual bool asNumber(double* output) const;
> +
>      virtual void writeJSON(Vector<UChar>* output) const;
>  
>  private:
> @@ -117,6 +130,9 @@
>      {
>          return adoptRef(new InspectorString(value));
>      }
> +
> +    virtual bool asString(String* output) const;    
> +
>      virtual void writeJSON(Vector<UChar>* output) const;
>  
>  private:
> @@ -127,23 +143,43 @@
>  };
>  
>  class InspectorObject : public InspectorValue {
> +private:
> +    typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
> +
>  public:
> +    typedef Dictionary::iterator iterator;
> +    typedef Dictionary::const_iterator const_iterator;
> +
> +public:
>      static PassRefPtr<InspectorObject> create()
>      {
>          return adoptRef(new InspectorObject());
>      }
>      ~InspectorObject() { }
>  
> +    virtual PassRefPtr<InspectorObject> asObject();
> +
>      void setBool(const String& name, bool);
>      void setNumber(const String& name, double);
>      void setString(const String& name, const String&);
>      void set(const String& name, PassRefPtr<InspectorValue>);
>  
> +    bool getBool(const String& name, bool* output) const;
> +    bool getNumber(const String& name, double* output) const;
> +    bool getString(const String& name, String* output) const;
> +    PassRefPtr<InspectorObject> getObject(const String& name) const;
> +    PassRefPtr<InspectorArray> getArray(const String& name) const;
> +    PassRefPtr<InspectorValue> get(const String& name) const;
> +
>      virtual void writeJSON(Vector<UChar>* output) const;
>  
> +    iterator begin() { return m_data.begin(); }
> +    iterator end() { return m_data.end(); }
> +    const_iterator begin() const { return m_data.begin(); }
> +    const_iterator end() const { return m_data.end(); }
> +
>  private:
>      InspectorObject() : InspectorValue(TypeObject) { }
> -    typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
>      Dictionary m_data;
>      Vector<String> m_order;
>  };
> @@ -156,6 +192,8 @@
>      }
>      ~InspectorArray() { }
>  
> +    virtual PassRefPtr<InspectorArray> asArray();
> +
>      void pushBool(bool);
>      void pushNumber(double);
>      void pushString(const String&);
> @@ -214,4 +252,3 @@
>  
>  #endif // ENABLE(INSPECTOR)
>  #endif // !defined(InspectorValues_h)
> -
> _______________________________________________
> webkit-changes mailing list
> webkit-changes at lists.webkit.org
> http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-changes/attachments/20100608/83282bde/attachment-0001.html>


More information about the webkit-changes mailing list