Files
opennurbs/opennurbs_textcontext.cpp
Bozo The Builder e7c29061e3 Sync changes from upstream repository
Co-authored-by: Alain <alain@mcneel.com>
Co-authored-by: Andrew Le Bihan <andy@mcneel.com>
Co-authored-by: chuck <chuck@mcneel.com>
Co-authored-by: croudyj <croudyj@gmail.com>
Co-authored-by: Dale Fugier <dale@mcneel.com>
Co-authored-by: Giulio Piacentino <giulio@mcneel.com>
Co-authored-by: Greg Arden <greg@mcneel.com>
Co-authored-by: Jussi Aaltonen <jussi@mcneel.com>
Co-authored-by: kike-garbo <kike@mcneel.com>
Co-authored-by: Steve Baer <steve@mcneel.com>
2022-11-21 14:18:57 -08:00

317 lines
9.1 KiB
C++

//
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
// McNeel & Associates.
//
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
//
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
////////////////////////////////////////////////////////////////
#include "opennurbs.h"
#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
// and the opennurbs .h files alter what is declared and how it is declared.
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
#endif
#include "opennurbs_textiterator.h"
// static
int ON_TextContext::ConvertCodepointsToString(int cplen, const ON__UINT32* cp, ON_wString& str_out)
{
str_out.Empty();
bool b = sizeof(wchar_t) == sizeof(*cp);
if (b)
{
str_out.Append((wchar_t*)cp, cplen);
return cplen;
}
unsigned int error_status = 0;
int wc_count = ON_ConvertUTF32ToWideChar(
0, //int bTestByteOrder,
cp, //const ON__UINT32* sUTF32,
cplen, //int sUTF32_count,
0, //wchar_t* sWideChar,
0, //int sWideChar_count,
&error_status, //unsigned int* error_status,
0xFFFFFFFF, //unsigned int error_mask,
0xFFFD, //ON__UINT32 error_code_point,
0 //const ON__UINT32** sNextUTF32
);
if(0 < wc_count)
{
str_out.ReserveArray(wc_count + 1);
error_status = 0;
int ok = ON_ConvertUTF32ToWideChar(
0, //int bTestByteOrder,
cp, //const ON__UINT32* sUTF32,
cplen, //int sUTF32_count,
str_out.Array(), //wchar_t* sWideChar,
wc_count + 1, //int sWideChar_count,
&error_status, //unsigned int* error_status,
0xFFFFFFFF, //unsigned int error_mask,
0xFFFD, //ON__UINT32 error_code_point,
0 //const ON__UINT32** sNextUTF32
);
if (0 < ok)
{
str_out.SetLength(wc_count);
}
}
return str_out.Length();
}
//static
int ON_TextContext::ConvertStringToCodepoints(const wchar_t* str, ON__UINT32*& cp)
{
if (nullptr == str)
return 0;
int wcnt = (int)wcslen(str);
if (0 == wcnt)
return 0;
// number of code points is always <= number of wchar_t's. the +1 is for a null terminator.
int cpcnt = wcnt + 1;
ON__UINT32* cp_local = cp;
cp = nullptr;
cp_local = (ON__UINT32*)onrealloc(cp_local, cpcnt*sizeof(cp_local[0]));
if(nullptr == cp_local)
return 0;
unsigned int error_status = 0;
int cnt = ON_ConvertWideCharToUTF32(
0, //int bTestByteOrder,
str, //const wchar_t* sWideChar,
wcnt, //int sWideChar_count,
cp_local, //ON__UINT32* sUTF32,
cpcnt, //int sUTF32_count,
&error_status, //unsigned int* error_status,
0xFFFFFFFF, //unsigned int error_mask,
0xFFFD, //ON__UINT32 error_code_point,
nullptr // wchar_t** sNextWideChar
);
cp = cp_local;
return cnt;
}
//static
const ON_wString ON_TextContext::FormatRtfString(
const wchar_t* rtf_string,
const ON_DimStyle* dimstyle,
bool clear_bold, bool set_bold,
bool clear_italic, bool set_italic,
bool clear_underline, bool set_underline,
bool clear_facename, bool set_facename, const wchar_t* override_facename)
{
ON_wString string_out;
if (nullptr == rtf_string || 0 == rtf_string[0])
return string_out;
size_t len = wcslen(rtf_string);
if (0 == len)
return string_out;
if (nullptr == dimstyle)
dimstyle = &ON_DimStyle::Default;
const ON_wString rtf_font_name = ON_Font::RichTextFontName(&dimstyle->Font(),true);
ON_wString rtf_wstring(rtf_string);
int rtf = rtf_wstring.Find("rtf1");
if (-1 == rtf) // Input is plain text string
{
ON_wString font_table_str;
ON_wString rtf_text_str;
ON_wString fmts;
// Keep dimstyle font as f0 in the font table even if we don't need itg here
if (set_facename && !rtf_font_name.EqualOrdinal(override_facename, true))
{
font_table_str.Format(L"{\\fonttbl{\\f0 %ls;}{\\f1 %ls;}}", rtf_font_name.Array(), override_facename);
fmts = L"\\f1";
}
else // Use style facename
{
font_table_str.Format(L"{\\fonttbl{\\f0 %ls;}}", rtf_font_name.Array());
fmts = L"\\f0";
}
if (set_bold)
fmts += L"\\b";
if (set_italic)
fmts += L"\\i";
if (set_underline)
fmts += "L\\ul";
rtf_wstring.Replace(L"\\", L"\\\\");
rtf_text_str.Format(L"{%ls %ls}", fmts.Array(), rtf_wstring.Array());
ON_wString par;
par.Format(L"}{\\par}{%ls ", fmts.Array());
rtf_text_str.Replace(L"\n", par.Array());
rtf_wstring.Format(L"{\\rtf1\\deff0%ls%ls}", font_table_str.Array(), rtf_text_str.Array());
return rtf_wstring;
}
// else Input is RTF string
ON_RtfStringBuilder builder(dimstyle, 1.0, ON_UNSET_COLOR);
builder.SetSkipColorTbl(true);
builder.SetSkipBold(clear_bold);
builder.SetSkipItalic(clear_italic);
builder.SetSkipUnderline(clear_underline);
builder.SetSkipFacename(clear_facename);
builder.SetMakeBold(set_bold);
builder.SetMakeItalic(set_italic);
builder.SetMakeUnderline(set_underline);
builder.SetMakeFacename(set_facename);
builder.SetOverrideFacename(override_facename);
builder.SetDefaultFacename(rtf_font_name);
if (builder.SettingFacename())
{
int ftbl = rtf_wstring.Find(L"fonttbl");
if (-1 == ftbl)
{
ON_wString temp;
len = rtf_wstring.Length();
ON_wString str = rtf_wstring.Right(((int)len) - 7);
temp.Format(L"{\\rtf1{\\fonttbl}%ls", str.Array());
rtf_wstring = temp;
}
}
len = rtf_wstring.Length();
ON_TextIterator iter(rtf_wstring.Array(), len);
ON_RtfParser parser(iter, builder);
bool rc = parser.Parse();
if (rc)
string_out = builder.OutputString();
return string_out;
}
//static
bool ON_TextContext::RtfFirstCharProperties(const wchar_t* rtf_string,
bool& bold, bool& italic, bool& underline, ON_wString& facename)
{
if (nullptr == rtf_string || 0 == rtf_string[0])
return false;
size_t len = wcslen(rtf_string);
if (0 == len)
return false;
ON_RtfFirstChar builder(nullptr, 1.0, ON_UNSET_COLOR);
ON_wString rtf_wstring(rtf_string);
int rtf = rtf_wstring.Find("rtf1");
if (-1 == rtf)
return false;
len = rtf_wstring.Length();
ON_TextIterator iter(rtf_wstring.Array(), len);
ON_RtfParser parser(iter, builder);
bool rc = parser.Parse();
if (rc)
{
bold = builder.m_current_run.IsBold();
italic = builder.m_current_run.IsItalic();
underline = builder.m_current_run.IsUnderlined();
int fi = builder.m_current_run.FontIndex();
if (-1 != fi)
facename = builder.FaceNameFromMap(fi);
}
return rc;
}
const ON_Font* ON_TextContent::FirstCharFont() const
{
ON_TextRunArray* runs = TextRuns(true);
if (nullptr != runs)
{
for (int i = 0; i < runs->Count(); i++)
{
if (ON_TextRun::RunType::kText == (*runs)[i]->Type() ||
ON_TextRun::RunType::kField == (*runs)[i]->Type())
{
return (*runs)[i]->Font();
}
}
}
return &ON_Font::Default;
}
//static
bool ON_TextContent::GetRichTextFontTable(
const ON_wString rich_text,
ON_ClassArray< ON_wString >& font_table
)
{
int table_pos = rich_text.Find(L"\\fonttbl");
if (table_pos < 0)
return false;
const wchar_t* rtf = rich_text.Array();
int open = 1;
int table_len = 0;
int len = rich_text.Length();
for (int i = table_pos + 8; i < len && open > 0; i++)
{
if (L'{' == rich_text[i])
{
open++;
}
else if (L'}' == rich_text[i])
{
open--;
table_len = i;
}
}
for (int i = table_pos + 8; i < table_len; i++)
{
int font_pos = rich_text.Find(L"\\f", i);
if (font_pos > i)
{
for (int j = font_pos + 2; j < table_len; j++)
{
if (rtf[j] == L' ')
{
for (int si = 0; si + j < table_len; si++)
{
if (rich_text[si + j] != L' ')
{
j += si;
break;
}
}
for (int ni = 1; ni + j < table_len; ni++)
{
if (rtf[ni + j] == L';' || rtf[ni + j] == L'}')
{
font_table.AppendNew() = rich_text.SubString(j, ni);
i = ni + j;
j = len;
break;
}
}
}
}
}
}
return true;
}
//--------------------------------------------------------------------