Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/accessible/windows/msaa/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 9 kB image not shown  

Quelle  Platform.cpp   Sprache: C

 
/* -*- 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 "Platform.h"

#include "AccEvent.h"
#include "Compatibility.h"
#include "HyperTextAccessible.h"
#include "MsaaAccessible.h"
#include "nsWinUtils.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/a11y/RemoteAccessible.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/WinHeaderOnlyUtils.h"
#include "WinUtils.h"
#include "ia2AccessibleText.h"

#include <tuple>

#if defined(MOZ_TELEMETRY_REPORTING)
#  include "mozilla/glean/AccessibleMetrics.h"
#endif  // defined(MOZ_TELEMETRY_REPORTING)

using namespace mozilla;
using namespace mozilla::a11y;
using namespace mozilla::mscom;

static StaticRefPtr<nsIFile> gInstantiator;

void a11y::PlatformInit() {
  nsWinUtils::MaybeStartWindowEmulation();
  ia2AccessibleText::InitTextChangeData();
}

void a11y::PlatformShutdown() {
  ::DestroyCaret();

  nsWinUtils::ShutdownWindowEmulation();

  if (gInstantiator) {
    gInstantiator = nullptr;
  }
}

void a11y::ProxyCreated(RemoteAccessible* aProxy) {
  MsaaAccessible* msaa = MsaaAccessible::Create(aProxy);
  msaa->AddRef();
  aProxy->SetWrapper(reinterpret_cast<uintptr_t>(msaa));
}

void a11y::ProxyDestroyed(RemoteAccessible* aProxy) {
  MsaaAccessible* msaa =
      reinterpret_cast<MsaaAccessible*>(aProxy->GetWrapper());
  if (!msaa) {
    return;
  }
  msaa->MsaaShutdown();
  aProxy->SetWrapper(0);
  msaa->Release();

  if (aProxy->IsDoc() && nsWinUtils::IsWindowEmulationStarted()) {
    aProxy->AsDoc()->SetEmulatedWindowHandle(nullptr);
  }
}

void a11y::PlatformEvent(Accessible* aTarget, uint32_t aEventType) {
  Accessible* msaaTarget = aTarget;
  if (aEventType == nsIAccessibleEvent::EVENT_SCROLLING_START &&
      aTarget->IsTextLeaf()) {
    // For MSAA/IA2, this event should not be fired on text leaf Accessibles.
    msaaTarget = aTarget->Parent();
  }
  if (msaaTarget) {
    MsaaAccessible::FireWinEvent(msaaTarget, aEventType);
  }
  uiaRawElmProvider::RaiseUiaEventForGeckoEvent(aTarget, aEventType);
}

void a11y::PlatformStateChangeEvent(Accessible* aTarget, uint64_t aState,
                                    bool aEnabled) {
  MsaaAccessible::FireWinEvent(aTarget, nsIAccessibleEvent::EVENT_STATE_CHANGE);
  uiaRawElmProvider::RaiseUiaEventForStateChange(aTarget, aState, aEnabled);
}

void a11y::PlatformFocusEvent(Accessible* aTarget,
                              const LayoutDeviceIntRect& aCaretRect) {
  if (aTarget->IsRemote() && FocusMgr() &&
      FocusMgr()->FocusedLocalAccessible()) {
    // This is a focus event from a remote document, but focus has moved out
    // of that document into the chrome since that event was sent. For example,
    // this can happen when choosing File menu -> New Tab. See bug 1471466.
    // Note that this does not handle the case where a focus event is sent from
    // one remote document, but focus moved into a second remote document
    // since that event was sent. However, this isn't something anyone has been
    // able to trigger.
    return;
  }

  AccessibleWrap::UpdateSystemCaretFor(aTarget, aCaretRect);
  MsaaAccessible::FireWinEvent(aTarget, nsIAccessibleEvent::EVENT_FOCUS);
  uiaRawElmProvider::RaiseUiaEventForGeckoEvent(
      aTarget, nsIAccessibleEvent::EVENT_FOCUS);
}

void a11y::PlatformCaretMoveEvent(Accessible* aTarget, int32_t aOffset,
                                  bool aIsSelectionCollapsed,
                                  int32_t aGranularity,
                                  const LayoutDeviceIntRect& aCaretRect,
                                  bool aFromUser) {
  AccessibleWrap::UpdateSystemCaretFor(aTarget, aCaretRect);
  MsaaAccessible::FireWinEvent(aTarget,
                               nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED);
  uiaRawElmProvider::RaiseUiaEventForGeckoEvent(
      aTarget, nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED);
}

void a11y::PlatformTextChangeEvent(Accessible* aText, const nsAString& aStr,
                                   int32_t aStart, uint32_t aLen, bool aInsert,
                                   bool) {
  uint32_t eventType = aInsert ? nsIAccessibleEvent::EVENT_TEXT_INSERTED
                               : nsIAccessibleEvent::EVENT_TEXT_REMOVED;
  MOZ_ASSERT(aText->IsHyperText());
  ia2AccessibleText::UpdateTextChangeData(aText->AsHyperTextBase(), aInsert,
                                          aStr, aStart, aLen);
  MsaaAccessible::FireWinEvent(aText, eventType);
  uiaRawElmProvider::RaiseUiaEventForGeckoEvent(aText, eventType);
}

void a11y::PlatformShowHideEvent(Accessible* aTarget, Accessible*, bool aInsert,
                                 bool) {
  uint32_t event =
      aInsert ? nsIAccessibleEvent::EVENT_SHOW : nsIAccessibleEvent::EVENT_HIDE;
  MsaaAccessible::FireWinEvent(aTarget, event);
}

void a11y::PlatformSelectionEvent(Accessible* aTarget, Accessible*,
                                  uint32_t aType) {
  MsaaAccessible::FireWinEvent(aTarget, aType);
  uiaRawElmProvider::RaiseUiaEventForGeckoEvent(aTarget, aType);
}

static bool GetInstantiatorExecutable(const DWORD aPid,
                                      nsIFile** aOutClientExe) {
  nsAutoHandle callingProcess(
      ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, aPid));
  if (!callingProcess) {
    return false;
  }

  DWORD bufLen = MAX_PATH;
  UniquePtr<wchar_t[]> buf;

  while (true) {
    buf = MakeUnique<wchar_t[]>(bufLen);
    if (::QueryFullProcessImageName(callingProcess, 0, buf.get(), &bufLen)) {
      break;
    }

    DWORD lastError = ::GetLastError();
    MOZ_ASSERT(lastError == ERROR_INSUFFICIENT_BUFFER);
    if (lastError != ERROR_INSUFFICIENT_BUFFER) {
      return false;
    }

    bufLen *= 2;
  }

  nsCOMPtr<nsIFile> file;
  nsresult rv = NS_NewLocalFile(nsDependentString(buf.get(), bufLen),
                                getter_AddRefs(file));
  if (NS_FAILED(rv)) {
    return false;
  }

  file.forget(aOutClientExe);
  return NS_SUCCEEDED(rv);
}

/**
 * Appends version information in the format "|a.b.c.d".
 * If there is no version information, we append nothing.
 */

static void AppendVersionInfo(nsIFile* aClientExe, nsAString& aStrToAppend) {
  MOZ_ASSERT(!NS_IsMainThread());

  LauncherResult<ModuleVersion> version = GetModuleVersion(aClientExe);
  if (version.isErr()) {
    return;
  }

  auto [major, minor, patch, build] = version.unwrap().AsTuple();

  aStrToAppend.AppendLiteral(u"|");

  constexpr auto dot = u"."_ns;

  aStrToAppend.AppendInt(major);
  aStrToAppend.Append(dot);
  aStrToAppend.AppendInt(minor);
  aStrToAppend.Append(dot);
  aStrToAppend.AppendInt(patch);
  aStrToAppend.Append(dot);
  aStrToAppend.AppendInt(build);
}

static void AccumulateInstantiatorTelemetry(const nsAString& aValue) {
  MOZ_ASSERT(NS_IsMainThread());

  if (!aValue.IsEmpty()) {
#if defined(MOZ_TELEMETRY_REPORTING)
    glean::a11y::instantiators.Set(NS_ConvertUTF16toUTF8(aValue));
#endif  // defined(MOZ_TELEMETRY_REPORTING)
    CrashReporter::RecordAnnotationNSString(
        CrashReporter::Annotation::AccessibilityClient, aValue);
  }
}

static void GatherInstantiatorTelemetry(nsIFile* aClientExe) {
  MOZ_ASSERT(!NS_IsMainThread());

  nsString value;
  nsresult rv = aClientExe->GetLeafName(value);
  if (NS_SUCCEEDED(rv)) {
    AppendVersionInfo(aClientExe, value);
  }

  nsCOMPtr<nsIRunnable> runnable(
      NS_NewRunnableFunction("a11y::AccumulateInstantiatorTelemetry",
                             [value = std::move(value)]() -> void {
                               AccumulateInstantiatorTelemetry(value);
                             }));

  // Now that we've (possibly) obtained version info, send the resulting
  // string back to the main thread to accumulate in telemetry.
  NS_DispatchToMainThread(runnable.forget());
}

void a11y::SetInstantiator(const uint32_t aPid) {
  nsCOMPtr<nsIFile> clientExe;
  if (!GetInstantiatorExecutable(aPid, getter_AddRefs(clientExe))) {
    AccumulateInstantiatorTelemetry(
        u"(Failed to retrieve client image name)"_ns);
    return;
  }

  // Only record the instantiator if it is the first instantiator, or if it does
  // not match the previous one. Some blocked clients are repeatedly requesting
  // a11y over and over so we don't want to be spawning countless telemetry
  // threads.
  if (gInstantiator) {
    bool equal;
    nsresult rv = gInstantiator->Equals(clientExe, &equal);
    if (NS_SUCCEEDED(rv) && equal) {
      return;
    }
  }

  gInstantiator = clientExe;

  nsCOMPtr<nsIRunnable> runnable(
      NS_NewRunnableFunction("a11y::GatherInstantiatorTelemetry",
                             [clientExe = std::move(clientExe)]() -> void {
                               GatherInstantiatorTelemetry(clientExe);
                             }));

  DebugOnly<nsresult> rv =
      NS_DispatchBackgroundTask(runnable.forget(), NS_DISPATCH_EVENT_MAY_BLOCK);
  MOZ_ASSERT(NS_SUCCEEDED(rv));
}

bool a11y::GetInstantiator(nsIFile** aOutInstantiator) {
  if (!gInstantiator) {
    return false;
  }

  return NS_SUCCEEDED(gInstantiator->Clone(aOutInstantiator));
}

uint64_t a11y::GetCacheDomainsForKnownClients(uint64_t aCacheDomains) {
  // If we're instantiating because of a screen reader, enable all cache
  // domains. We expect that demanding ATs will need all information we have.
  if (Compatibility::IsKnownScreenReader()) {
    return CacheDomain::All;
  }
  return aCacheDomains;
}

Messung V0.5
C=92 H=97 G=94

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.