accessible/atk/nsMaiHyperlink.cpp
author Gregory Szorc <gps@mozilla.com>
Thu, 01 Sep 2016 15:41:26 -0700
changeset 312507 568c0384b6b2303334b833cce9746cbdbc689869
parent 312307 448e4062cba4aecd5ce8c5e09b6b4f98f67e0dee
child 448947 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1298947 - Remove curl and jq from decision image; r=dustin curl and jq were previously used to fetch and parse the TC secret. We now use Python for that. So remove the unused packages. This reduces the Docker image size by ~10MB. MozReview-Commit-ID: Nl7fC1aG7w

/* -*- 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 "nsIURI.h"
#include "nsMaiHyperlink.h"
#include "mozilla/a11y/ProxyAccessible.h"

using namespace mozilla::a11y;

/* MaiAtkHyperlink */

#define MAI_TYPE_ATK_HYPERLINK      (mai_atk_hyperlink_get_type ())
#define MAI_ATK_HYPERLINK(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
                                     MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink))
#define MAI_ATK_HYPERLINK_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass),\
                                 MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
#define MAI_IS_ATK_HYPERLINK(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
                                        MAI_TYPE_ATK_HYPERLINK))
#define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
                                        MAI_TYPE_ATK_HYPERLINK))
#define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
                                 MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))

/**
 * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace,
 * for AtkHyperlink
 */

struct MaiAtkHyperlink
{
    AtkHyperlink parent;

    /*
     * The MaiHyperlink whose properties and features are exported via this
     * hyperlink instance.
     */
    MaiHyperlink *maiHyperlink;
};

struct MaiAtkHyperlinkClass
{
    AtkHyperlinkClass parent_class;
};

GType mai_atk_hyperlink_get_type(void);

G_BEGIN_DECLS
/* callbacks for AtkHyperlink */
static void classInitCB(AtkHyperlinkClass *aClass);
static void finalizeCB(GObject *aObj);

/* callbacks for AtkHyperlink virtual functions */
static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex);
static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex);
static gint getEndIndexCB(AtkHyperlink *aLink);
static gint getStartIndexCB(AtkHyperlink *aLink);
static gboolean isValidCB(AtkHyperlink *aLink);
static gint getAnchorCountCB(AtkHyperlink *aLink);
G_END_DECLS

static gpointer parent_class = nullptr;

static MaiHyperlink*
GetMaiHyperlink(AtkHyperlink *aHyperlink)
{
    NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr);
    MaiHyperlink * maiHyperlink =
        MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink;
    NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr);
    NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr);
    return maiHyperlink;
}

GType
mai_atk_hyperlink_get_type(void)
{
    static GType type = 0;

    if (!type) {
        static const GTypeInfo tinfo = {
            sizeof(MaiAtkHyperlinkClass),
            (GBaseInitFunc)nullptr,
            (GBaseFinalizeFunc)nullptr,
            (GClassInitFunc)classInitCB,
            (GClassFinalizeFunc)nullptr,
            nullptr, /* class data */
            sizeof(MaiAtkHyperlink), /* instance size */
            0, /* nb preallocs */
            (GInstanceInitFunc)nullptr,
            nullptr /* value table */
        };

        type = g_type_register_static(ATK_TYPE_HYPERLINK,
                                      "MaiAtkHyperlink",
                                      &tinfo, GTypeFlags(0));
    }
    return type;
}

MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) :
    mHyperlink(aHyperLink),
    mMaiAtkHyperlink(nullptr)
{
    mMaiAtkHyperlink =
        reinterpret_cast<AtkHyperlink *>
                        (g_object_new(mai_atk_hyperlink_get_type(), nullptr));
    NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
    if (!mMaiAtkHyperlink)
      return;

    MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this;
}

MaiHyperlink::~MaiHyperlink()
{
  if (mMaiAtkHyperlink) {
    MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr;
    g_object_unref(mMaiAtkHyperlink);
  }
}


/* static functions for ATK callbacks */

void
classInitCB(AtkHyperlinkClass *aClass)
{
    GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);

    parent_class = g_type_class_peek_parent(aClass);

    aClass->get_uri = getUriCB;
    aClass->get_object = getObjectCB;
    aClass->get_end_index = getEndIndexCB;
    aClass->get_start_index = getStartIndexCB;
    aClass->is_valid = isValidCB;
    aClass->get_n_anchors = getAnchorCountCB;

    gobject_class->finalize = finalizeCB;
}

void
finalizeCB(GObject *aObj)
{
    NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink");
    if (!MAI_IS_ATK_HYPERLINK(aObj))
        return;

    MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj);
    maiAtkHyperlink->maiHyperlink = nullptr;

    /* call parent finalize function */
    if (G_OBJECT_CLASS (parent_class)->finalize)
        G_OBJECT_CLASS (parent_class)->finalize(aObj);
}

gchar *
getUriCB(AtkHyperlink *aLink, gint aLinkIndex)
{
  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
  if (!maiLink)
    return nullptr;

  nsAutoCString cautoStr;
  if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
    nsCOMPtr<nsIURI> uri = hyperlink->AnchorURIAt(aLinkIndex);
    if (!uri)
      return nullptr;

    nsresult rv = uri->GetSpec(cautoStr);
    NS_ENSURE_SUCCESS(rv, nullptr);

    return g_strdup(cautoStr.get());
  }

  bool valid;
  maiLink->Proxy()->AnchorURIAt(aLinkIndex, cautoStr, &valid);
  if (!valid)
    return nullptr;

  return g_strdup(cautoStr.get());
}

AtkObject *
getObjectCB(AtkHyperlink *aLink, gint aLinkIndex)
{
  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
  if (!maiLink) {
    return nullptr;
  }

  if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
    Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
    NS_ENSURE_TRUE(anchor, nullptr);

    return AccessibleWrap::GetAtkObject(anchor);
  }

  ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
  return anchor ? GetWrapperFor(anchor) : nullptr;
}

gint
getEndIndexCB(AtkHyperlink *aLink)
{
  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
  if (!maiLink)
    return false;

  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
    return static_cast<gint>(hyperlink->EndOffset());

  bool valid = false;
  uint32_t endIdx = maiLink->Proxy()->EndOffset(&valid);
  return valid ? static_cast<gint>(endIdx) : -1;
}

gint
getStartIndexCB(AtkHyperlink *aLink)
{
  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
  if (!maiLink)
    return -1;

  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
    return static_cast<gint>(hyperlink->StartOffset());

  bool valid = false;
  uint32_t startIdx = maiLink->Proxy()->StartOffset(&valid);
  return valid ? static_cast<gint>(startIdx) : -1;
}

gboolean
isValidCB(AtkHyperlink *aLink)
{
  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
  if (!maiLink)
    return false;

  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
    return static_cast<gboolean>(hyperlink->IsLinkValid());

  return static_cast<gboolean>(maiLink->Proxy()->IsLinkValid());
}

gint
getAnchorCountCB(AtkHyperlink *aLink)
{
  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
  if (!maiLink)
    return -1;

  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
    return static_cast<gint>(hyperlink->AnchorCount());

  bool valid = false;
  uint32_t anchorCount = maiLink->Proxy()->AnchorCount(&valid);
  return valid ? static_cast<gint>(anchorCount) : -1;
}