Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/unx/gtk4/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 10 kB image not shown  

Quelle  gtkaccessibletext.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 <vector>

#include <com/sun/star/accessibility/AccessibleTextType.hpp>
#include <com/sun/star/accessibility/TextSegment.hpp>
#include <com/sun/star/accessibility/XAccessibleText.hpp>
#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
#include <o3tl/any.hxx>
#include <sal/log.hxx>

#include "a11y.hxx"
#include "gtkaccessibletext.hxx"

#if GTK_CHECK_VERSION(4, 14, 0)

namespace
{
sal_Int16 lcl_GtkTextGranularityToUNOBoundaryType(GtkAccessibleTextGranularity eGranularity)
{
    switch (eGranularity)
    {
        case GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER:
            return css::accessibility::AccessibleTextType::CHARACTER;
        case GTK_ACCESSIBLE_TEXT_GRANULARITY_WORD:
            return css::accessibility::AccessibleTextType::WORD;
        case GTK_ACCESSIBLE_TEXT_GRANULARITY_SENTENCE:
            return css::accessibility::AccessibleTextType::SENTENCE;
        case GTK_ACCESSIBLE_TEXT_GRANULARITY_LINE:
            return css::accessibility::AccessibleTextType::LINE;
        case GTK_ACCESSIBLE_TEXT_GRANULARITY_PARAGRAPH:
            return css::accessibility::AccessibleTextType::PARAGRAPH;
        default:
            assert(false && "Unhandled GtkAccessibleTextGranularity.");
            return GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER;
    }
}

css::uno::Reference<css::accessibility::XAccessibleText> getXText(GtkAccessibleText* pGtkText)
{
    LoAccessible* pAccessible = LO_ACCESSIBLE(pGtkText);
    if (!pAccessible->uno_accessible)
        return nullptr;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        pAccessible->uno_accessible->getAccessibleContext());

    css::uno::Reference<css::accessibility::XAccessibleText> xText(xContext, css::uno::UNO_QUERY);
    return xText;
}
}

static GBytes* lo_accessible_text_get_contents(GtkAccessibleText* self, unsigned int start,
                                               unsigned int end)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return nullptr;

    // G_MAXUINT has special meaning: end of the text
    const sal_Int32 nEndIndex = (end == G_MAXUINT) ? xText->getCharacterCount() : end;

    const OString sText
        = rtl::OUStringToOString(xText->getTextRange(start, nEndIndex), RTL_TEXTENCODING_UTF8);
    return g_bytes_new(sText.getStr(), sText.getLength());
}

static GBytes* lo_accessible_text_get_contents_at(GtkAccessibleText* self, unsigned int offset,
                                                  GtkAccessibleTextGranularity eGranularity,
                                                  unsigned int* start, unsigned int* end)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return nullptr;

    if (offset > o3tl::make_unsigned(xText->getCharacterCount()))
    {
        SAL_WARN("vcl.gtk",
                 "lo_accessible_text_get_contents_at called with invalid offset: " << offset);
        return nullptr;
    }

    const sal_Int16 nUnoBoundaryType = lcl_GtkTextGranularityToUNOBoundaryType(eGranularity);
    const css::accessibility::TextSegment aSegment
        = xText->getTextAtIndex(offset, nUnoBoundaryType);
    *start = o3tl::make_unsigned(aSegment.SegmentStart);
    *end = o3tl::make_unsigned(aSegment.SegmentEnd);
    const OString sText = rtl::OUStringToOString(aSegment.SegmentText, RTL_TEXTENCODING_UTF8);
    return g_bytes_new(sText.getStr(), sText.getLength());
}

static unsigned int lo_accessible_text_get_caret_position(GtkAccessibleText* self)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return 0;

    return std::max(sal_Int32(0), xText->getCaretPosition());
}

static gboolean lo_accessible_text_get_selection(GtkAccessibleText* self, gsize* n_ranges,
                                                 GtkAccessibleTextRange** ranges)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return 0;

    if (xText->getSelectedText().isEmpty())
        return false;

    const sal_Int32 nSelectionStart = xText->getSelectionStart();
    const sal_Int32 nSelectionEnd = xText->getSelectionEnd();

    *n_ranges = 1;
    *ranges = g_new(GtkAccessibleTextRange, 1);
    (*ranges)[0].start = std::min(nSelectionStart, nSelectionEnd);
    (*ranges)[0].length = std::abs(nSelectionEnd - nSelectionStart);
    return true;
}

static int
convertUnoTextAttributesToGtk(const css::uno::Sequence<css::beans::PropertyValue>&&nbsp;rAttribs,
                              char*** attribute_names, char*** attribute_values)
{
    std::vector<std::pair<OString, OUString>> aNameValuePairs;
    for (const css::beans::PropertyValue& rAttribute : rAttribs)
    {
        if (rAttribute.Name == "CharFontName")
        {
            const OUString sValue = *o3tl::doAccess<OUString>(rAttribute.Value);
            aNameValuePairs.emplace_back(GTK_ACCESSIBLE_ATTRIBUTE_FAMILY, sValue);
        }
    }

    if (aNameValuePairs.empty())
        return 0;

    const int nCount = aNameValuePairs.size();
    *attribute_names = g_new(char*, nCount + 1);
    *attribute_values = g_new(char*, nCount + 1);
    for (int i = 0; i < nCount; i++)
    {
        (*attribute_names)[i] = g_strdup(aNameValuePairs[i].first.getStr());
        (*attribute_values)[i] = g_strdup(
            OUStringToOString(aNameValuePairs[i].second, RTL_TEXTENCODING_UTF8).getStr());
    }
    (*attribute_names)[nCount] = nullptr;
    (*attribute_values)[nCount] = nullptr;

    return nCount;
}

static gboolean lo_accessible_text_get_attributes(GtkAccessibleText* self, unsigned int offset,
                                                  gsize* n_ranges, GtkAccessibleTextRange** ranges,
                                                  char*** attribute_names, char*** attribute_values)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return false;

    const unsigned int nTextLength = o3tl::make_unsigned(xText->getCharacterCount());
    if (offset == nTextLength)
        offset = nTextLength - 1;

    if (offset >= nTextLength)
    {
        SAL_WARN("vcl.gtk",
                 "lo_accessible_text_get_attributes called with invalid offset: " << offset);
        return false;
    }

    css::uno::Sequence<css::beans::PropertyValue> aAttribs;
    css::uno::Reference<css::accessibility::XAccessibleTextAttributes> xAttributes(
        xText, css::uno::UNO_QUERY);
    if (xAttributes.is())
        aAttribs = xAttributes->getRunAttributes(offset, css::uno::Sequence<OUString>());
    else
        aAttribs = xText->getCharacterAttributes(offset, css::uno::Sequence<OUString>());

    const int nCount = convertUnoTextAttributesToGtk(aAttribs, attribute_names, attribute_values);
    if (nCount == 0)
        return false;

    *n_ranges = nCount;
    *ranges = g_new(GtkAccessibleTextRange, nCount);
    // just use start and end of attribute run for each single attribute
    const css::accessibility::TextSegment aAttributeRun
        = xText->getTextAtIndex(offset, css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
    for (int i = 0; i < nCount; i++)
    {
        ((*ranges)[i]).start = aAttributeRun.SegmentStart;
        ((*ranges)[i]).length = aAttributeRun.SegmentEnd - aAttributeRun.SegmentStart;
    }

    return true;
}

static void lo_accessible_text_get_default_attributes(GtkAccessibleText* self,
                                                      char*** attribute_names,
                                                      char*** attribute_values)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return;

    css::uno::Reference<css::accessibility::XAccessibleTextAttributes> xAttributes(
        xText, css::uno::UNO_QUERY);
    if (!xAttributes.is())
        return;

    css::uno::Sequence<css::beans::PropertyValue> aAttribs
        = xAttributes->getDefaultAttributes(css::uno::Sequence<OUString>());

    convertUnoTextAttributesToGtk(aAttribs, attribute_names, attribute_values);
}

#if GTK_CHECK_VERSION(4, 15, 0)
static gboolean lo_accessible_text_get_extents(GtkAccessibleText* self, unsigned int start,
                                               unsigned int end, graphene_rect_t* extents)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return false;

    if (end != start + 1)
    {
        SAL_WARN("vcl.gtk""lo_accessible_text_get_extents called for a text range of more than a "
                            "single character. This is not implemented yet.");
        return false;
    }

    if (start > o3tl::make_unsigned(xText->getCharacterCount()))
    {
        SAL_WARN("vcl.gtk",
                 "lo_accessible_text_get_extents called with invalid start index: " << start);
        return false;
    }

    css::awt::Rectangle aBounds = xText->getCharacterBounds(start);
    extents->origin.x = aBounds.X;
    extents->origin.y = aBounds.Y;
    extents->size.width = aBounds.Width;
    extents->size.height = aBounds.Height;

    return true;
}

static gboolean lo_accessible_text_get_offset(GtkAccessibleText* self,
                                              const graphene_point_t* point, unsigned int* offset)
{
    css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self);
    if (!xText.is())
        return false;

    css::awt::Point aPoint(point->x, point->y);
    const sal_Int32 nIndex = xText->getIndexAtPoint(aPoint);

    if (nIndex < 0)
        return false;

    *offset = nIndex;
    return true;
}
#endif

void lo_accessible_text_init(gpointer iface_, gpointer)
{
    auto const iface = static_cast<GtkAccessibleTextInterface*>(iface_);
    iface->get_contents = lo_accessible_text_get_contents;
    iface->get_contents_at = lo_accessible_text_get_contents_at;
    iface->get_caret_position = lo_accessible_text_get_caret_position;
    iface->get_selection = lo_accessible_text_get_selection;
    iface->get_attributes = lo_accessible_text_get_attributes;
    iface->get_default_attributes = lo_accessible_text_get_default_attributes;
#if GTK_CHECK_VERSION(4, 15, 0)
    iface->get_extents = lo_accessible_text_get_extents;
    iface->get_offset = lo_accessible_text_get_offset;
#endif
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=98 H=97 G=97

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© 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.