Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "sdnTextAccessible.h"
#include "ISimpleDOM.h"
#include "nsCoreUtils.h"
#include "DocAccessible.h"
#include "nsIFrame.h"
#include "nsFontMetrics.h"
#include "nsPresContext.h"
#include "nsLayoutUtils.h"
#include "nsRange.h"
#include "gfxTextRun.h"
#include "nsIAccessibleTypes.h"
#include "mozilla/gfx/2D.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// sdnTextAccessible
////////////////////////////////////////////////////////////////////////////////
IMPL_IUNKNOWN_QUERY_HEAD(sdnTextAccessible)
IMPL_IUNKNOWN_QUERY_IFACE(ISimpleDOMText)
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mMsaa)
STDMETHODIMP
sdnTextAccessible::get_domText(BSTR __RPC_FAR* aText) {
if (!aText) return E_INVALIDARG;
*aText = nullptr;
AccessibleWrap* acc = mMsaa->LocalAcc();
if (!acc) return CO_E_OBJNOTCONNECTED;
nsAutoString nodeValue;
acc->GetContent()->GetNodeValue(nodeValue);
if (nodeValue.IsEmpty()) return S_FALSE;
*aText = ::SysAllocStringLen(nodeValue.get(), nodeValue.Length());
return *aText ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP
sdnTextAccessible::get_clippedSubstringBounds(
unsigned int aStartIndex, unsigned int aEndIndex, int __RPC_FAR* aX,
int __RPC_FAR* aY, int __RPC_FAR* aWidth, int __RPC_FAR* aHeight) {
nscoord x = 0, y = 0, width = 0, height = 0;
HRESULT rv = get_unclippedSubstringBounds(aStartIndex, aEndIndex, &x, &y,
&width, &height);
if (FAILED(rv)) return rv;
DocAccessible* document = mMsaa->LocalAcc()->Document();
NS_ASSERTION(
document,
"There must always be a doc accessible, but there isn't. Crash!");
LayoutDeviceIntRect docRect = document->Bounds();
LayoutDeviceIntRect unclippedRect(x, y, width, height);
LayoutDeviceIntRect clippedRect;
clippedRect.IntersectRect(unclippedRect, docRect);
*aX = clippedRect.X();
*aY = clippedRect.Y();
*aWidth = clippedRect.Width();
*aHeight = clippedRect.Height();
return S_OK;
}
STDMETHODIMP
sdnTextAccessible::get_unclippedSubstringBounds(
unsigned int aStartIndex, unsigned int aEndIndex, int __RPC_FAR* aX,
int __RPC_FAR* aY, int __RPC_FAR* aWidth, int __RPC_FAR* aHeight) {
if (!aX || !aY || !aWidth || !aHeight) return E_INVALIDARG;
*aX = *aY = *aWidth = *aHeight = 0;
AccessibleWrap* acc = mMsaa->LocalAcc();
if (!acc) return CO_E_OBJNOTCONNECTED;
nsIFrame* frame = acc->GetFrame();
NS_ENSURE_TRUE(frame, E_FAIL);
nsPoint startPoint, endPoint;
nsIFrame* startFrame =
GetPointFromOffset(frame, aStartIndex, true, startPoint);
nsIFrame* endFrame = GetPointFromOffset(frame, aEndIndex, false, endPoint);
if (!startFrame || !endFrame) return E_FAIL;
nsRect sum;
nsIFrame* iter = startFrame;
nsIFrame* stopLoopFrame = endFrame->GetNextContinuation();
for (; iter != stopLoopFrame; iter = iter->GetNextContinuation()) {
nsRect rect = iter->GetScreenRectInAppUnits();
nscoord start = (iter == startFrame) ? startPoint.x : 0;
nscoord end = (iter == endFrame) ? endPoint.x : rect.Width();
rect.MoveByX(start);
rect.SetWidth(end - start);
sum.UnionRect(sum, rect);
}
nsPresContext* presContext = acc->Document()->PresContext();
*aX = presContext->AppUnitsToDevPixels(sum.X());
*aY = presContext->AppUnitsToDevPixels(sum.Y());
*aWidth = presContext->AppUnitsToDevPixels(sum.Width());
*aHeight = presContext->AppUnitsToDevPixels(sum.Height());
return S_OK;
}
STDMETHODIMP
sdnTextAccessible::scrollToSubstring(unsigned int aStartIndex,
unsigned int aEndIndex) {
AccessibleWrap* acc = mMsaa->LocalAcc();
if (!acc) return CO_E_OBJNOTCONNECTED;
RefPtr<nsRange> range = nsRange::Create(acc->GetContent());
if (NS_FAILED(range->SetStart(acc->GetContent(), aStartIndex))) return E_FAIL;
if (NS_FAILED(range->SetEnd(acc->GetContent(), aEndIndex))) return E_FAIL;
nsresult rv = nsCoreUtils::ScrollSubstringTo(
acc->GetFrame(), range, nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
return GetHRESULT(rv);
}
STDMETHODIMP
sdnTextAccessible::get_fontFamily(BSTR __RPC_FAR* aFontFamily) {
if (!aFontFamily) return E_INVALIDARG;
*aFontFamily = nullptr;
AccessibleWrap* acc = mMsaa->LocalAcc();
if (!acc) return CO_E_OBJNOTCONNECTED;
nsIFrame* frame = acc->GetFrame();
if (!frame) return E_FAIL;
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForFrame(frame, 1.0f);
RefPtr<gfxFont> font = fm->GetThebesFontGroup()->GetFirstValidFont();
const nsCString& name = font->GetName();
if (name.IsEmpty()) return S_FALSE;
NS_ConvertUTF8toUTF16 str(name);
*aFontFamily = ::SysAllocStringLen(str.get(), str.Length());
return *aFontFamily ? S_OK : E_OUTOFMEMORY;
}
nsIFrame* sdnTextAccessible::GetPointFromOffset(nsIFrame* aContainingFrame,
int32_t aOffset,
bool aPreferNext,
nsPoint& aOutPoint) {
nsIFrame* textFrame = nullptr;
int32_t outOffset;
aContainingFrame->GetChildFrameContainingOffset(aOffset, aPreferNext,
&outOffset, &textFrame);
if (textFrame) textFrame->GetPointFromOffset(aOffset, &aOutPoint);
return textFrame;
}