OSDN Git Service

Gecko vbuf backend: Gecko <= 1.9.2.9 (Firefox <= 3.6.9) crashes when we attempt to...
authorJames Teh <jamie@jantrid.net>
Tue, 14 Sep 2010 00:32:23 +0000 (10:32 +1000)
committerJames Teh <jamie@jantrid.net>
Tue, 14 Sep 2010 00:32:23 +0000 (10:32 +1000)
This is fixed in Gecko 1.9.2.10 (Firefox 3.6.10), which will be released soon.
Note that this crash also occurs in earlier Firefox 4 betas and nightlies. We don't protect against this for Firefox 4. Firefox 4 testers should use a recent nightly.
This required moving fillVBuf and fillTableCellInfo_IATable2 into the GeckoVBufBackend_t class. There is also a new method called versionSpecificInit which retrieves the version information and sets the flag to disable table headers.

Fixes #807.

source/NVDAHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp
source/NVDAHelper/vbufBackends/gecko_ia2/gecko_ia2.h

index 061308e..23ea737 100755 (executable)
@@ -141,7 +141,7 @@ inline void fillTableCellInfo_IATable(VBufStorage_controlFieldNode_t* node, IAcc
                DEBUG_MSG(L"IAccessibleTable::get_rowColumnExtentsAtIndex failed, result " << res);\r
 }\r
 \r
-inline void fillTableCellInfo_IATable2(VBufStorage_controlFieldNode_t* node, IAccessibleTableCell* paccTableCell) {\r
+inline void GeckoVBufBackend_t::fillTableCellInfo_IATable2(VBufStorage_controlFieldNode_t* node, IAccessibleTableCell* paccTableCell) {\r
        int res;\r
        wostringstream s;\r
 \r
@@ -166,6 +166,9 @@ inline void fillTableCellInfo_IATable2(VBufStorage_controlFieldNode_t* node, IAc
                }\r
        }\r
 \r
+       if (this->shouldDisableTableHeaders)\r
+               return;\r
+\r
        IUnknown** headerCells;\r
        long nHeaderCells;\r
        IAccessible2* headerCellPacc = NULL;\r
@@ -228,7 +231,47 @@ inline void fillTableCellInfo_IATable2(VBufStorage_controlFieldNode_t* node, IAc
        }\r
 }\r
 \r
-VBufStorage_fieldNode_t* fillVBuf(IAccessible2* pacc, VBufStorage_buffer_t* buffer, VBufStorage_controlFieldNode_t* parentNode, VBufStorage_fieldNode_t* previousNode, IAccessibleTable* paccTable=NULL, IAccessibleTable2* paccTable2=NULL, long tableID=0) {\r
+void GeckoVBufBackend_t::versionSpecificInit(IAccessible2* pacc) {\r
+       IServiceProvider* serv = NULL;\r
+       if (pacc->QueryInterface(IID_IServiceProvider, (void**)&serv) != S_OK)\r
+               return;\r
+       IAccessibleApplication* iaApp = NULL;\r
+       if (serv->QueryService(IID_IAccessibleApplication, IID_IAccessibleApplication, (void**)&iaApp) != S_OK) {\r
+               serv->Release();\r
+               return;\r
+       }\r
+       serv->Release();\r
+       serv = NULL;\r
+\r
+       BSTR toolkitName = NULL;\r
+       if (iaApp->get_toolkitName(&toolkitName) != S_OK) {\r
+               iaApp->Release();\r
+               return;\r
+       }\r
+       BSTR toolkitVersion = NULL;\r
+       if (iaApp->get_toolkitVersion(&toolkitVersion) != S_OK) {\r
+               iaApp->Release();\r
+               SysFreeString(toolkitName);\r
+               return;\r
+       }\r
+       iaApp->Release();\r
+       iaApp = NULL;\r
+\r
+       if (wcscmp(toolkitName, L"Gecko") == 0) {\r
+               // Gecko <= 1.9.2.9 will crash if we try to retrieve headers on some table cells, so disable them.\r
+               UINT toolkitVersionLen = SysStringLen(toolkitVersion);\r
+               this->shouldDisableTableHeaders = (toolkitVersionLen >= 7 &&\r
+                       wcsncmp(toolkitVersion, L"1.9.2.", 6) == 0 &&\r
+                       // If there is another digit after 1.9.2.n, this is >= 1.9.2.10.\r
+                       (toolkitVersionLen <= 7 || !iswdigit(toolkitVersion[7]))\r
+               );\r
+       }\r
+\r
+       SysFreeString(toolkitName);\r
+       SysFreeString(toolkitVersion);\r
+}\r
+\r
+VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc, VBufStorage_buffer_t* buffer, VBufStorage_controlFieldNode_t* parentNode, VBufStorage_fieldNode_t* previousNode, IAccessibleTable* paccTable, IAccessibleTable2* paccTable2, long tableID) {\r
        int res;\r
        DEBUG_MSG(L"Entered fillVBuf, with pacc at "<<pacc<<L", parentNode at "<<parentNode<<L", previousNode "<<previousNode);\r
        assert(buffer); //buffer can't be NULL\r
@@ -453,7 +496,7 @@ VBufStorage_fieldNode_t* fillVBuf(IAccessible2* pacc, VBufStorage_buffer_t* buff
                parentNode->addAttribute(L"table-id", s.str());\r
                if (res == S_OK) {\r
                        // IAccessibleTable2\r
-                       fillTableCellInfo_IATable2(parentNode, paccTableCell);\r
+                       this->fillTableCellInfo_IATable2(parentNode, paccTableCell);\r
                        paccTableCell->Release();\r
                        paccTableCell = NULL;\r
                } else // IAccessibleTable\r
@@ -652,7 +695,7 @@ VBufStorage_fieldNode_t* fillVBuf(IAccessible2* pacc, VBufStorage_buffer_t* buff
                                        if(childDefaction) SysFreeString(childDefaction);\r
                                        #endif\r
                                        DEBUG_MSG(L"calling fillVBuf with childPacc ");\r
-                                       if((tempNode=fillVBuf(childPacc,buffer,parentNode,previousNode,paccTable,paccTable2,tableID))!=NULL) {\r
+                                       if((tempNode=this->fillVBuf(childPacc,buffer,parentNode,previousNode,paccTable,paccTable2,tableID))!=NULL) {\r
                                                previousNode=tempNode;\r
                                        } else {\r
                                                DEBUG_MSG(L"Error in fillVBuf");\r
@@ -706,7 +749,7 @@ VBufStorage_fieldNode_t* fillVBuf(IAccessible2* pacc, VBufStorage_buffer_t* buff
                                                }\r
                                                if(childPacc) {\r
                                                        DEBUG_MSG(L"calling _filVBufHelper with child object ");\r
-                                                       if((tempNode=fillVBuf(childPacc,buffer,parentNode,previousNode,paccTable,paccTable2,tableID))!=NULL) {\r
+                                                       if((tempNode=this->fillVBuf(childPacc,buffer,parentNode,previousNode,paccTable,paccTable2,tableID))!=NULL) {\r
                                                                previousNode=tempNode;\r
                                                        } else {\r
                                                                DEBUG_MSG(L"Error in calling fillVBuf");\r
@@ -958,8 +1001,12 @@ void GeckoVBufBackend_t::render(VBufStorage_buffer_t* buffer, int docHandle, int
                DEBUG_MSG(L"Could not get IAccessible2, returning");\r
                return;\r
        }\r
+       if (!oldNode) {\r
+               // This is the root node.\r
+               this->versionSpecificInit(pacc);\r
+       }\r
        DEBUG_MSG(L"Calling fillVBuf");\r
-       fillVBuf(pacc, buffer, NULL, NULL);\r
+       this->fillVBuf(pacc, buffer, NULL, NULL);\r
        pacc->Release();\r
        DEBUG_MSG(L"Rendering done");\r
 }\r
index 16b01db..d6fcf7a 100755 (executable)
@@ -18,6 +18,16 @@ http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 #include <vbufBase/backend.h>\r
 \r
 class GeckoVBufBackend_t: public VBufBackend_t {\r
+       private:\r
+\r
+       VBufStorage_fieldNode_t* fillVBuf(IAccessible2* pacc, VBufStorage_buffer_t* buffer, VBufStorage_controlFieldNode_t* parentNode, VBufStorage_fieldNode_t* previousNode, IAccessibleTable* paccTable=NULL, IAccessibleTable2* paccTable2=NULL, long tableID=0);\r
+\r
+       void versionSpecificInit(IAccessible2* pacc);\r
+\r
+       void fillTableCellInfo_IATable2(VBufStorage_controlFieldNode_t* node, IAccessibleTableCell* paccTableCell);\r
+\r
+       bool shouldDisableTableHeaders;\r
+\r
        protected:\r
 \r
        static void CALLBACK renderThread_winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, long objectID, long childID, DWORD threadID, DWORD time);\r