1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "InterfaceInitFuncs.h"
8 
9 #include "LocalAccessible-inl.h"
10 #include "AccessibleWrap.h"
11 #include "DocAccessible.h"
12 #include "nsMai.h"
13 #include "RemoteAccessible.h"
14 #include "mozilla/Likely.h"
15 
16 using namespace mozilla::a11y;
17 
18 static const char* const kDocTypeName = "W3C-doctype";
19 static const char* const kDocUrlName = "DocURL";
20 static const char* const kMimeTypeName = "MimeType";
21 
22 // below functions are vfuncs on an ATK  interface so they need to be C call
23 extern "C" {
24 
25 static const gchar* getDocumentLocaleCB(AtkDocument* aDocument);
26 static AtkAttributeSet* getDocumentAttributesCB(AtkDocument* aDocument);
27 static const gchar* getDocumentAttributeValueCB(AtkDocument* aDocument,
28                                                 const gchar* aAttrName);
29 
documentInterfaceInitCB(AtkDocumentIface * aIface)30 void documentInterfaceInitCB(AtkDocumentIface* aIface) {
31   NS_ASSERTION(aIface, "Invalid Interface");
32   if (MOZ_UNLIKELY(!aIface)) return;
33 
34   /*
35    * We don't support get_document or set_attribute right now.
36    * get_document_type is deprecated, we return DocType in
37    * get_document_attribute_value and get_document_attributes instead.
38    */
39   aIface->get_document_attributes = getDocumentAttributesCB;
40   aIface->get_document_attribute_value = getDocumentAttributeValueCB;
41   aIface->get_document_locale = getDocumentLocaleCB;
42 }
43 
getDocumentLocaleCB(AtkDocument * aDocument)44 const gchar* getDocumentLocaleCB(AtkDocument* aDocument) {
45   nsAutoString locale;
46   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
47   if (accWrap) {
48     accWrap->Language(locale);
49   } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
50     proxy->Language(locale);
51   }
52 
53   return locale.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(locale);
54 }
55 
prependToList(GSList * aList,const char * const aName,const nsAutoString & aValue)56 static inline GSList* prependToList(GSList* aList, const char* const aName,
57                                     const nsAutoString& aValue) {
58   if (aValue.IsEmpty()) {
59     return aList;
60   }
61 
62   // libspi will free these
63   AtkAttribute* atkAttr = (AtkAttribute*)g_malloc(sizeof(AtkAttribute));
64   atkAttr->name = g_strdup(aName);
65   atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
66   return g_slist_prepend(aList, atkAttr);
67 }
68 
getDocumentAttributesCB(AtkDocument * aDocument)69 AtkAttributeSet* getDocumentAttributesCB(AtkDocument* aDocument) {
70   nsAutoString url;
71   nsAutoString w3cDocType;
72   nsAutoString mimeType;
73   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
74   if (accWrap) {
75     if (!accWrap->IsDoc()) {
76       return nullptr;
77     }
78 
79     DocAccessible* document = accWrap->AsDoc();
80     document->URL(url);
81     document->DocType(w3cDocType);
82     document->MimeType(mimeType);
83   } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
84     proxy->URLDocTypeMimeType(url, w3cDocType, mimeType);
85   } else {
86     return nullptr;
87   }
88 
89   // according to atkobject.h, AtkAttributeSet is a GSList
90   GSList* attributes = nullptr;
91   attributes = prependToList(attributes, kDocUrlName, url);
92   attributes = prependToList(attributes, kDocTypeName, w3cDocType);
93   attributes = prependToList(attributes, kMimeTypeName, mimeType);
94 
95   return attributes;
96 }
97 
getDocumentAttributeValueCB(AtkDocument * aDocument,const gchar * aAttrName)98 const gchar* getDocumentAttributeValueCB(AtkDocument* aDocument,
99                                          const gchar* aAttrName) {
100   RemoteAccessible* proxy = nullptr;
101   DocAccessible* document = nullptr;
102   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
103   if (accWrap) {
104     if (!accWrap->IsDoc()) {
105       return nullptr;
106     }
107 
108     document = accWrap->AsDoc();
109   } else {
110     proxy = GetProxy(ATK_OBJECT(aDocument));
111     if (!proxy) {
112       return nullptr;
113     }
114   }
115 
116   nsAutoString attrValue;
117   if (!strcasecmp(aAttrName, kDocTypeName)) {
118     if (document) {
119       document->DocType(attrValue);
120     } else {
121       proxy->DocType(attrValue);
122     }
123   } else if (!strcasecmp(aAttrName, kDocUrlName)) {
124     if (document) {
125       document->URL(attrValue);
126     } else {
127       proxy->URL(attrValue);
128     }
129   } else if (!strcasecmp(aAttrName, kMimeTypeName)) {
130     if (document) {
131       document->MimeType(attrValue);
132     } else {
133       proxy->MimeType(attrValue);
134     }
135   } else {
136     return nullptr;
137   }
138 
139   return attrValue.IsEmpty() ? nullptr
140                              : AccessibleWrap::ReturnString(attrValue);
141 }
142 }
143