[PATCH v10 2/5] mshtml: Fix setting and retrieving attributes in IE8 mode.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Nov 29 09:32:22 CST 2021


On 29/11/2021 16:15, Jacek Caban wrote:
> On 11/29/21 2:14 PM, Gabriel Ivăncescu wrote:
>> For non-builtin props, getAttribute retrieves the stringified value of 
>> the
>> prop. For builtins, however, getAttribute returns null unless they were
>> set to a string. setAttribute also stringifies the value if it's a 
>> builtin.
>>
>> Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
>> ---
>>
>> I'm testing for/htmlFor since prototype.js also uses it for translations,
>> but it doesn't seem to be affected here.
>>
>>   dlls/mshtml/htmlelem.c            | 193 ++++++++++++++++++++----------
>>   dlls/mshtml/tests/documentmode.js |  76 +++++++++---
>>   2 files changed, 188 insertions(+), 81 deletions(-)
>>
>> diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c
>> index 3f7c60b..bd9dc29 100644
>> --- a/dlls/mshtml/htmlelem.c
>> +++ b/dlls/mshtml/htmlelem.c
>> @@ -1067,6 +1067,15 @@ static HRESULT WINAPI 
>> HTMLElement_Invoke(IHTMLElement *iface, DISPID dispIdMembe
>>               wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
>>   }
>> +static inline WCHAR *translate_attr_name(WCHAR *attr_name, 
>> compat_mode_t compat_mode)
>> +{
>> +    WCHAR *ret = attr_name;
>> +
>> +    if(compat_mode >= COMPAT_MODE_IE8 && !wcsicmp(attr_name, L"class"))
>> +        ret = (WCHAR*)L"className";
>> +    return ret;
>> +}
>> +
>>   static HRESULT set_elem_attr_value_by_dispid(HTMLElement *elem, 
>> DISPID dispid, VARIANT *v)
>>   {
>>       DISPID propput_dispid = DISPID_PROPERTYPUT;
>> @@ -1086,34 +1095,62 @@ static HRESULT WINAPI 
>> HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr
>>                                                  VARIANT 
>> AttributeValue, LONG lFlags)
>>   {
>>       HTMLElement *This = impl_from_IHTMLElement(iface);
>> +    compat_mode_t compat_mode = 
>> dispex_compat_mode(&This->node.event_target.dispex);
>> +    nsAString name_str, value_str;
>> +    VARIANT val = AttributeValue;
>> +    BOOL needs_free = FALSE;
>> +    nsresult nsres;
>>       DISPID dispid;
>>       HRESULT hres;
>>       TRACE("(%p)->(%s %s %08x)\n", This, 
>> debugstr_w(strAttributeName), debugstr_variant(&AttributeValue), lFlags);
>> -    if(This->dom_element && 
>> dispex_compat_mode(&This->node.event_target.dispex) >= COMPAT_MODE_IE8) {
>> -        nsAString name_str, value_str;
>> -        nsresult nsres;
>> -
>> -        hres = variant_to_nsstr(&AttributeValue, FALSE, &value_str);
>> +    if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) {
> 
> 
> Why do you change IE9+ code path? Would changing the condition from IE8 
> to IE9 be enough for this code path?
> 

The code path is not changed, it's just restructured so that the 
GetDispID is at the top, because for IE8 case it has to "fallback" to 
IE9+ under certain conditions (for class and style) which are checked 
after GetDispID. Otherwise I'd have to use a goto which would be less 
than ideal, or duplicate the gecko get/setAttribute code.

Note that this special casing done for class is not a hack—javascript 
libraries that deal with browser quirks (prototype.js, jsquery, etc) 
have translation tables for this, so it's necessary.

Basically for IE8 it's like this:

1) Attributes have associated props, like in pre IE8 modes.

2) "class" changes className prop, while "className" doesn't change any 
prop but sets a separated attribute (same as IE9+, since "className" is 
a builtin prop which sets the "class" in the builtin). i.e. it needs 
special casing.

3) For attributes corresponding to builtin props, the value is 
stringified, but not for dynamic props. This is done after GetDispID.

4) When retrieving an attribute, if the attribute is a builtin and if 
the value is not a string, it returns null. For other attributes, the 
value is stringified.

Note that despite (3), it *is* possible to set a builtin attribute to a 
non-string: by setting the prop instead of using setAttribute. That's 
because attributes have corresponding props.

This also makes it possible to change the underlying prop's referenced 
value (such as an array element's value) to prove that getAttribute is 
what stringifies it, and it isn't just stringified when set, because it 
will return the new value, stringified.

This is in the tests already, of course, so it needs to pass.


Do you have some better idea how to structure the code then? Otherwise I 
think I'll just restructure it first on a no-op patch like this, and 
then add the fixed behavior.

> 
>>   static HRESULT WINAPI HTMLElement_put_className(IHTMLElement *iface, 
>> BSTR v)
>> @@ -6463,6 +6523,9 @@ static HRESULT 
>> HTMLElement_populate_props(DispatchEx *dispex)
>>       nsresult nsres;
>>       HRESULT hres;
>> +    if(dispex_compat_mode(dispex) >= COMPAT_MODE_IE9)
>> +        return S_OK;
> 
> 
> While the rest of the patch could be split as well, this part (while 
> probably correct) definitely doesn't belong to this patch.
> 
> 

I see, I remember having some troubles trying to split it by introducing 
new failures on existing tests, but I'll have a look again and see what 
can be done.

Thanks,
Gabriel



More information about the wine-devel mailing list