189 lines
4.8 KiB
C++
189 lines
4.8 KiB
C++
/*
|
|
* Copyright (C) 2026 Behdad Esfahbod
|
|
*
|
|
* This is part of HarfBuzz, a text shaping library.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and its documentation for any purpose, provided that the
|
|
* above copyright notice and the following two paragraphs appear in
|
|
* all copies of this software.
|
|
*
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
* DAMAGE.
|
|
*
|
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
*
|
|
* Author(s): Behdad Esfahbod
|
|
*/
|
|
|
|
#include "font-options.hh"
|
|
#include "main-font-text.hh"
|
|
#include "shape-consumer.hh"
|
|
#include "text-options.hh"
|
|
#include "gpu-output.hh"
|
|
|
|
#include <hb-ot.h>
|
|
|
|
const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_UPEM;
|
|
const unsigned SUBPIXEL_BITS = 0;
|
|
|
|
#include "gpu/default-text-en.hh"
|
|
#include "gpu/default-text-fa.hh"
|
|
|
|
struct demo_script_text_t {
|
|
hb_script_t script;
|
|
const char *text;
|
|
};
|
|
|
|
static const demo_script_text_t demo_texts[] = {
|
|
{ HB_SCRIPT_LATIN, default_text_en },
|
|
{ HB_SCRIPT_ARABIC, default_text_fa },
|
|
};
|
|
|
|
static void
|
|
append_lines (GString *s, const char *text, unsigned max_lines)
|
|
{
|
|
const char *p = text;
|
|
unsigned lines = 0;
|
|
while (*p && lines < max_lines)
|
|
{
|
|
const char *end = strchr (p, '\n');
|
|
if (!end)
|
|
end = p + strlen (p);
|
|
if (s->len)
|
|
g_string_append_c (s, '\n');
|
|
g_string_append_len (s, p, end - p);
|
|
lines++;
|
|
p = *end ? end + 1 : end;
|
|
}
|
|
}
|
|
|
|
#define MAX_TOTAL_LINES 60
|
|
|
|
static bool
|
|
font_has_script (hb_face_t *face, hb_script_t script)
|
|
{
|
|
hb_tag_t script_tags[2];
|
|
unsigned num_tags = 2;
|
|
hb_ot_tags_from_script_and_language (script, HB_LANGUAGE_INVALID,
|
|
&num_tags, script_tags, nullptr, nullptr);
|
|
for (unsigned t = 0; t < num_tags; t++)
|
|
{
|
|
unsigned script_index;
|
|
if (hb_ot_layout_table_find_script (face, HB_OT_TAG_GSUB,
|
|
script_tags[t],
|
|
&script_index))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static char *
|
|
build_default_text (hb_face_t *face)
|
|
{
|
|
/* Count how many scripts the font supports. */
|
|
unsigned num_supported = 0;
|
|
for (unsigned i = 0; i < G_N_ELEMENTS (demo_texts); i++)
|
|
if (font_has_script (face, demo_texts[i].script))
|
|
num_supported++;
|
|
|
|
if (!num_supported)
|
|
num_supported = 1; /* fallback */
|
|
|
|
unsigned lines_per = MAX_TOTAL_LINES / num_supported;
|
|
|
|
GString *s = g_string_new (nullptr);
|
|
|
|
for (unsigned i = 0; i < G_N_ELEMENTS (demo_texts); i++)
|
|
{
|
|
if (!font_has_script (face, demo_texts[i].script))
|
|
continue;
|
|
append_lines (s, demo_texts[i].text, lines_per);
|
|
}
|
|
|
|
/* Fallback to English if nothing matched. */
|
|
if (!s->len)
|
|
append_lines (s, default_text_en, MAX_TOTAL_LINES);
|
|
|
|
return g_string_free (s, FALSE);
|
|
}
|
|
|
|
static const char *gpu_default_text_sentinel = "";
|
|
static hb_bool_t *gpu_demo_flag = nullptr;
|
|
|
|
struct gpu_text_options_t : shape_text_options_t
|
|
{
|
|
const char *default_text () override
|
|
{
|
|
return (gpu_demo_flag && *gpu_demo_flag) ? gpu_default_text_sentinel : nullptr;
|
|
}
|
|
};
|
|
|
|
struct gpu_font_options_t : font_options_t
|
|
{
|
|
hb_face_t *default_face () override
|
|
{
|
|
if (!gpu_demo_flag || !*gpu_demo_flag)
|
|
return nullptr;
|
|
#include "gpu/default-font.hh"
|
|
hb_blob_t *blob = hb_blob_create ((const char *) default_font,
|
|
sizeof (default_font),
|
|
HB_MEMORY_MODE_READONLY,
|
|
nullptr, nullptr);
|
|
hb_face_t *face_ = hb_face_create (blob, 0);
|
|
hb_blob_destroy (blob);
|
|
return face_;
|
|
}
|
|
};
|
|
|
|
using base_t = main_font_text_t<shape_consumer_t<gpu_output_t>,
|
|
gpu_font_options_t,
|
|
gpu_text_options_t>;
|
|
|
|
struct gpu_main_t : base_t
|
|
{
|
|
int operator () (int argc, char **argv)
|
|
{
|
|
gpu_demo_flag = &this->output.demo;
|
|
|
|
add_options ();
|
|
add_exit_code (RETURN_VALUE_OPERATION_FAILED, "Operation failed.");
|
|
|
|
parse (&argc, &argv);
|
|
|
|
/* If no text was provided, build from font's supported scripts. */
|
|
if (!text || !*text)
|
|
{
|
|
g_free (text);
|
|
text = build_default_text (face);
|
|
}
|
|
|
|
this->init (this);
|
|
|
|
while (this->consume_line (*this))
|
|
;
|
|
|
|
this->finish (this);
|
|
|
|
if (this->failed && return_value == RETURN_VALUE_SUCCESS)
|
|
return_value = RETURN_VALUE_OPERATION_FAILED;
|
|
|
|
return return_value;
|
|
}
|
|
};
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
gpu_main_t driver;
|
|
return driver (argc, argv);
|
|
}
|