Bug 453883, ensure true/false marcos are available, r=joshmoz, sr=jst
[wine-gecko.git] / accessible / src / msaa / nsTextAccessibleWrap.cpp
blob63d4287fc74e32d5cd40dad458c17068bb98409e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Corp.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Aaron Leventhal
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 // NOTE: alphabetically ordered
40 #include "nsTextAccessibleWrap.h"
41 #include "ISimpleDOMText_i.c"
42 #include "nsIAccessibleDocument.h"
43 #include "nsIFontMetrics.h"
44 #include "nsIFrame.h"
45 #include "nsPresContext.h"
46 #include "nsIPresShell.h"
47 #include "nsIRenderingContext.h"
48 #include "nsIWidget.h"
49 #include "nsIComponentManager.h"
51 // --------------------------------------------------------
52 // nsTextAccessibleWrap Accessible
53 // --------------------------------------------------------
55 nsTextAccessibleWrap::nsTextAccessibleWrap(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
56 nsTextAccessible(aDOMNode, aShell)
60 STDMETHODIMP_(ULONG) nsTextAccessibleWrap::AddRef()
62 return nsAccessNode::AddRef();
65 STDMETHODIMP_(ULONG) nsTextAccessibleWrap::Release()
67 return nsAccessNode::Release();
70 STDMETHODIMP nsTextAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
72 *ppv = nsnull;
74 if (IID_IUnknown == iid || IID_ISimpleDOMText == iid)
75 *ppv = static_cast<ISimpleDOMText*>(this);
77 if (nsnull == *ppv)
78 return nsAccessibleWrap::QueryInterface(iid, ppv);
80 (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
81 return S_OK;
84 STDMETHODIMP nsTextAccessibleWrap::get_domText(
85 /* [retval][out] */ BSTR __RPC_FAR *aDomText)
87 __try {
88 *aDomText = NULL;
90 if (!mDOMNode) {
91 return E_FAIL; // Node already shut down
93 nsAutoString nodeValue;
95 mDOMNode->GetNodeValue(nodeValue);
96 if (nodeValue.IsEmpty())
97 return S_FALSE;
99 *aDomText = ::SysAllocStringLen(nodeValue.get(), nodeValue.Length());
100 if (!*aDomText)
101 return E_OUTOFMEMORY;
103 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
105 return S_OK;
108 STDMETHODIMP nsTextAccessibleWrap::get_clippedSubstringBounds(
109 /* [in] */ unsigned int aStartIndex,
110 /* [in] */ unsigned int aEndIndex,
111 /* [out] */ int __RPC_FAR *aX,
112 /* [out] */ int __RPC_FAR *aY,
113 /* [out] */ int __RPC_FAR *aWidth,
114 /* [out] */ int __RPC_FAR *aHeight)
116 __try {
117 *aX = *aY = *aWidth = *aHeight = 0;
118 nscoord x, y, width, height, docX, docY, docWidth, docHeight;
119 HRESULT rv = get_unclippedSubstringBounds(aStartIndex, aEndIndex, &x, &y, &width, &height);
120 if (FAILED(rv)) {
121 return rv;
124 nsCOMPtr<nsIAccessibleDocument> docAccessible(GetDocAccessible());
125 nsCOMPtr<nsIAccessible> accessible(do_QueryInterface(docAccessible));
126 NS_ASSERTION(accessible, "There must always be a doc accessible, but there isn't");
128 accessible->GetBounds(&docX, &docY, &docWidth, &docHeight);
130 nsRect unclippedRect(x, y, width, height);
131 nsRect docRect(docX, docY, docWidth, docHeight);
132 nsRect clippedRect;
134 clippedRect.IntersectRect(unclippedRect, docRect);
136 *aX = clippedRect.x;
137 *aY = clippedRect.y;
138 *aWidth = clippedRect.width;
139 *aHeight = clippedRect.height;
140 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
142 return S_OK;
145 STDMETHODIMP nsTextAccessibleWrap::get_unclippedSubstringBounds(
146 /* [in] */ unsigned int aStartIndex,
147 /* [in] */ unsigned int aEndIndex,
148 /* [out] */ int __RPC_FAR *aX,
149 /* [out] */ int __RPC_FAR *aY,
150 /* [out] */ int __RPC_FAR *aWidth,
151 /* [out] */ int __RPC_FAR *aHeight)
153 __try {
154 *aX = *aY = *aWidth = *aHeight = 0;
156 if (!mDOMNode) {
157 return E_FAIL; // Node already shut down
160 if (NS_FAILED(GetCharacterExtents(aStartIndex, aEndIndex,
161 aX, aY, aWidth, aHeight))) {
162 return NS_ERROR_FAILURE;
164 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
166 return S_OK;
170 STDMETHODIMP nsTextAccessibleWrap::scrollToSubstring(
171 /* [in] */ unsigned int aStartIndex,
172 /* [in] */ unsigned int aEndIndex)
174 __try {
175 nsresult rv = nsAccUtils::ScrollSubstringTo(GetFrame(), mDOMNode, aStartIndex,
176 mDOMNode, aEndIndex,
177 nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
178 if (NS_FAILED(rv))
179 return E_FAIL;
180 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
181 return S_OK;
184 nsIFrame* nsTextAccessibleWrap::GetPointFromOffset(nsIFrame *aContainingFrame,
185 PRInt32 aOffset,
186 PRBool aPreferNext,
187 nsPoint& aOutPoint)
189 nsIFrame *textFrame = nsnull;
190 PRInt32 outOffset;
191 aContainingFrame->GetChildFrameContainingOffset(aOffset, aPreferNext, &outOffset, &textFrame);
192 if (!textFrame) {
193 return nsnull;
196 textFrame->GetPointFromOffset(aOffset, &aOutPoint);
197 return textFrame;
201 * Given an offset, the x, y, width, and height values are filled appropriately.
203 nsresult nsTextAccessibleWrap::GetCharacterExtents(PRInt32 aStartOffset, PRInt32 aEndOffset,
204 PRInt32* aX, PRInt32* aY,
205 PRInt32* aWidth, PRInt32* aHeight)
207 *aX = *aY = *aWidth = *aHeight = 0;
208 nsPresContext *presContext = GetPresContext();
209 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
211 nsIFrame *frame = GetFrame();
212 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
214 nsIWidget *widget = frame->GetWindow();
215 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
217 nsPoint startPoint, endPoint;
218 nsIFrame *startFrame = GetPointFromOffset(frame, aStartOffset, PR_TRUE, startPoint);
219 nsIFrame *endFrame = GetPointFromOffset(frame, aEndOffset, PR_FALSE, endPoint);
220 if (!startFrame || !endFrame) {
221 return E_FAIL;
224 nsRect sum(0, 0, 0, 0);
225 nsIFrame *iter = startFrame;
226 nsIFrame *stopLoopFrame = endFrame->GetNextContinuation();
227 for (; iter != stopLoopFrame; iter = iter->GetNextContinuation()) {
228 nsRect rect = iter->GetScreenRectExternal();
229 nscoord start = (iter == startFrame) ? presContext->AppUnitsToDevPixels(startPoint.x) : 0;
230 nscoord end = (iter == endFrame) ? presContext->AppUnitsToDevPixels(endPoint.x) :
231 rect.width;
232 rect.x += start;
233 rect.width = end - start;
234 sum.UnionRect(sum, rect);
237 *aX = sum.x;
238 *aY = sum.y;
239 *aWidth = sum.width;
240 *aHeight = sum.height;
242 return NS_OK;
245 STDMETHODIMP nsTextAccessibleWrap::get_fontFamily(
246 /* [retval][out] */ BSTR __RPC_FAR *aFontFamily)
248 __try {
249 *aFontFamily = NULL;
251 nsIFrame *frame = GetFrame();
252 nsCOMPtr<nsIPresShell> presShell = GetPresShell();
253 if (!frame || !presShell) {
254 return E_FAIL;
257 nsCOMPtr<nsIRenderingContext> rc;
258 presShell->CreateRenderingContext(frame, getter_AddRefs(rc));
259 if (!rc) {
260 return E_FAIL;
263 const nsStyleFont *font = frame->GetStyleFont();
265 const nsStyleVisibility *visibility = frame->GetStyleVisibility();
267 if (NS_FAILED(rc->SetFont(font->mFont, visibility->mLangGroup))) {
268 return E_FAIL;
271 nsCOMPtr<nsIDeviceContext> deviceContext;
272 rc->GetDeviceContext(*getter_AddRefs(deviceContext));
273 if (!deviceContext) {
274 return E_FAIL;
277 nsIFontMetrics *fm;
278 rc->GetFontMetrics(fm);
279 if (!fm) {
280 return E_FAIL;
283 nsAutoString fontFamily;
284 deviceContext->FirstExistingFont(fm->Font(), fontFamily);
285 if (fontFamily.IsEmpty())
286 return S_FALSE;
288 *aFontFamily = ::SysAllocStringLen(fontFamily.get(), fontFamily.Length());
289 if (!*aFontFamily)
290 return E_OUTOFMEMORY;
292 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
294 return S_OK;