mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 19:46:08 +08:00
502 lines
14 KiB
C++
502 lines
14 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
|
|
|
|
ON_OBJECT_IMPLEMENT( ON_TextStyle, ON_ModelComponent, "4F0F51FB-35D0-4865-9998-6D2C6A99721D" );
|
|
|
|
const ON_TextStyle* ON_TextStyle::FromModelComponentRef(
|
|
const class ON_ModelComponentReference& model_component_reference,
|
|
const ON_TextStyle* none_return_value
|
|
)
|
|
{
|
|
const ON_TextStyle* p = ON_TextStyle::Cast(model_component_reference.ModelComponent());
|
|
return (nullptr != p) ? p : none_return_value;
|
|
}
|
|
|
|
ON_TextStyle::ON_TextStyle()
|
|
: ON_ModelComponent(ON_ModelComponent::Type::TextStyle)
|
|
{}
|
|
|
|
ON_TextStyle::ON_TextStyle(const ON_TextStyle& src)
|
|
: ON_ModelComponent(ON_ModelComponent::Type::TextStyle,src)
|
|
{
|
|
Internal_Copy(src);
|
|
}
|
|
|
|
ON_TextStyle& ON_TextStyle::operator=(const ON_TextStyle& src)
|
|
{
|
|
if (this != &src)
|
|
{
|
|
m_is_locked_bits = 0;
|
|
ON_ModelComponent::operator=(src);
|
|
Internal_Copy(src);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void ON_TextStyle::Internal_Copy(
|
|
const ON_TextStyle& src
|
|
)
|
|
{
|
|
m_managed_font = src.m_managed_font;
|
|
m_font_description = src.m_font_description;
|
|
m_is_set_bits = src.m_is_set_bits;
|
|
// DO NOT COPY m_is_locked_bits.
|
|
}
|
|
|
|
// On September 24, 2015 the "V3" ON_Font was split into
|
|
// ON_TextStyle (a document object) and
|
|
// ON_Font (a current runtime resource)
|
|
// Versions of opennurbs before ON_TextStyle::binary_archive_opennurbs_version
|
|
// serialized ON_TextStyle information in the V5 ON_Font format.
|
|
const unsigned int ON_TextStyle::binary_archive_opennurbs_version = ON_VersionNumberConstruct(6, 0, 2015, 9, 23, 0);
|
|
|
|
bool ON_TextStyle::Write(
|
|
ON_BinaryArchive& file // serialize definition to binary archive
|
|
) const
|
|
{
|
|
const ON_Font* font
|
|
= (nullptr == m_managed_font || 0 == m_managed_font->RuntimeSerialNumber())
|
|
? &ON_Font::Default
|
|
: m_managed_font;
|
|
|
|
if ( file.Archive3dmVersion() < 60
|
|
|| file.ArchiveOpenNURBSVersion() < ON_TextStyle::binary_archive_opennurbs_version
|
|
)
|
|
return font->WriteV5(Index(),Id(),file);
|
|
|
|
if (!file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,1))
|
|
return false;
|
|
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
if (!file.WriteModelComponentAttributes(*this,ON_ModelComponent::Attributes::BinaryArchiveAttributes))
|
|
break;
|
|
|
|
// We only need to save the m_font_description when we are using an
|
|
// alternate font or writing a V5 Mac file.
|
|
const bool bWriteFont = (nullptr != m_managed_font);
|
|
ON_wString postscript_name;
|
|
ON_wString font_description;
|
|
if (nullptr != m_managed_font)
|
|
{
|
|
postscript_name = m_managed_font->PostScriptName();
|
|
if (postscript_name.IsEmpty())
|
|
postscript_name = m_managed_font->Description(ON_Font::NameLocale::LocalizedFirst, ON_wString::HyphenMinus, 0, false);
|
|
font_description = postscript_name;
|
|
}
|
|
else
|
|
{
|
|
font_description = m_font_description;
|
|
}
|
|
|
|
if (ON::RuntimeEnvironment::Apple == file.ArchiveRuntimeEnvironment() && m_apple_font_name.IsNotEmpty() && postscript_name.IsEmpty() )
|
|
{
|
|
font_description = m_apple_font_name;
|
|
}
|
|
|
|
const bool bHaveFontDescription = font_description.IsNotEmpty();
|
|
|
|
if (!file.WriteBool(bHaveFontDescription))
|
|
break;
|
|
|
|
if (bHaveFontDescription)
|
|
{
|
|
if (!file.WriteString(font_description))
|
|
break;
|
|
}
|
|
|
|
if (!file.WriteBool(bWriteFont))
|
|
break;
|
|
|
|
if (bWriteFont)
|
|
{
|
|
if (!m_managed_font->Write(file))
|
|
break;
|
|
}
|
|
|
|
// version 1.1 added id and name
|
|
if (!file.WriteUuid(Id()))
|
|
break;
|
|
if (!file.WriteString(Name()))
|
|
break;
|
|
|
|
rc = true;
|
|
break;
|
|
}
|
|
if (!file.EndWrite3dmChunk() )
|
|
rc = false;
|
|
return rc;
|
|
}
|
|
|
|
static void SetNameFromFontDescription(
|
|
const ON_ComponentManifest& manifest,
|
|
ON_TextStyle& text_style
|
|
)
|
|
{
|
|
// Dale Lear RH-63824 May 3, 2021
|
|
// It is critical that bIncludeNotOnDevice be set to false.
|
|
// Otherwise missing fonts will have a description beginning with "[Not on device]"
|
|
// and square brackets are not permitted in names.
|
|
// This code is inventing a Rhino 6/7 dimstyle name from a V4 text style.
|
|
// The text style names were unreliable in V4 and we've used the font
|
|
// description as a proxy for years now.
|
|
const bool bIncludeNotOnDevice = false;
|
|
|
|
const ON_wString font_description(text_style.Font().Description(ON_Font::NameLocale::LocalizedFirst, ON_wString::HyphenMinus, ON_wString::Space, true, bIncludeNotOnDevice));
|
|
|
|
ON_wString text_style_name = manifest.UnusedName(
|
|
text_style.ComponentType(),
|
|
ON_nil_uuid,
|
|
static_cast<const wchar_t*>(font_description),
|
|
nullptr,
|
|
nullptr,
|
|
0,
|
|
nullptr);
|
|
text_style.SetName(text_style_name);
|
|
}
|
|
|
|
bool ON_TextStyle::Read(
|
|
ON_BinaryArchive& file // restore definition from binary archive
|
|
)
|
|
{
|
|
ClearModelComponentAttributes(ON_ModelComponent::Attributes::AllAttributes);
|
|
m_managed_font = nullptr;
|
|
m_font_description = ON_wString::EmptyString;
|
|
|
|
ON__UINT32 typecode = 0;
|
|
ON__INT64 big_value = 0;
|
|
if (file.Archive3dmVersion() < 60
|
|
|| file.ArchiveOpenNURBSVersion() < ON_TextStyle::binary_archive_opennurbs_version
|
|
// Sep 23, 215 had several in-house WIP versions and this makes the few files created
|
|
// on that day read correctly
|
|
|| (file.ArchiveOpenNURBSVersion() < ON_VersionNumberConstruct(6, 0, 2015, 9, 24, 0)
|
|
&& file.PeekAt3dmBigChunkType(&typecode,&big_value)
|
|
&& TCODE_ANONYMOUS_CHUNK != typecode
|
|
)
|
|
)
|
|
{
|
|
ON_Font font;
|
|
int V5_font_index = -1;
|
|
ON_UUID V5_font_id = ON_nil_uuid;
|
|
bool rc = font.ReadV5(file,&V5_font_index,&V5_font_id);
|
|
SetFont(font.ManagedFont());
|
|
SetIndex(V5_font_index);
|
|
if ( ON_nil_uuid == V5_font_id )
|
|
SetId();
|
|
else
|
|
SetId(V5_font_id);
|
|
|
|
// Use V5 font face name to set text style name.
|
|
if (nullptr != m_managed_font)
|
|
SetNameFromFontDescription(file.Manifest(),*this);
|
|
return rc;
|
|
}
|
|
|
|
int major_version = 0;
|
|
int minor_version = 0;
|
|
if (!file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK, &major_version, &minor_version))
|
|
return false;
|
|
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
unsigned int model_component_attributes_filter = 0;
|
|
if (!file.ReadModelComponentAttributes(*this,&model_component_attributes_filter) )
|
|
break;
|
|
|
|
// We only need to save the m_font_description when we are using an
|
|
// alternate font.
|
|
bool bHaveFontDescription = false;
|
|
if (!file.ReadBool(&bHaveFontDescription))
|
|
break;
|
|
|
|
ON_wString font_description;
|
|
ON_wString apple_font_name;
|
|
|
|
if (bHaveFontDescription)
|
|
{
|
|
if (!file.ReadString(font_description))
|
|
break;
|
|
font_description.TrimLeftAndRight();
|
|
bHaveFontDescription = font_description.IsNotEmpty();
|
|
}
|
|
|
|
if (ON::RuntimeEnvironment::Apple == file.ArchiveRuntimeEnvironment()
|
|
&& font_description.IsNotEmpty()
|
|
&& false == ON_Font::IsNotAppleFontName(font_description) )
|
|
{
|
|
apple_font_name = font_description;
|
|
}
|
|
|
|
bool bReadFont = false;
|
|
if (!file.ReadBool(&bReadFont))
|
|
break;
|
|
|
|
if (bReadFont)
|
|
{
|
|
ON_Font font_characteristics;
|
|
if (!font_characteristics.Read(file))
|
|
break;
|
|
if (apple_font_name.IsEmpty())
|
|
apple_font_name = font_characteristics.PostScriptName();
|
|
SetFontFromDescription(
|
|
static_cast<const wchar_t*>(font_description),
|
|
static_cast<const wchar_t*>(apple_font_name),
|
|
&font_characteristics
|
|
);
|
|
}
|
|
else
|
|
{
|
|
SetFontFromDescription(
|
|
static_cast<const wchar_t*>(font_description),
|
|
static_cast<const wchar_t*>(apple_font_name),
|
|
nullptr
|
|
);
|
|
}
|
|
|
|
if (minor_version < 1)
|
|
{
|
|
// id and name were not saved in version 1.0
|
|
// They are required now and are created when an old file is read.
|
|
SetId();
|
|
if (nullptr != m_managed_font)
|
|
SetNameFromFontDescription(file.Manifest(),*this);
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
// version 1.1 added id and name
|
|
ON_UUID id;
|
|
if (!file.ReadUuid(id))
|
|
break;
|
|
SetId(id);
|
|
|
|
ON_wString name;
|
|
if (!file.ReadString(name))
|
|
break;
|
|
SetName(name);
|
|
|
|
rc = true;
|
|
break;
|
|
}
|
|
if (!file.EndRead3dmChunk() )
|
|
rc = false;
|
|
return rc;
|
|
}
|
|
|
|
void ON_TextStyle::ClearFont()
|
|
{
|
|
if (false == FontIsLocked())
|
|
{
|
|
m_managed_font = nullptr;
|
|
m_font_description = ON_wString::EmptyString;
|
|
m_apple_font_name = ON_wString::EmptyString;
|
|
m_is_set_bits &= ~ON_TextStyle::font_bit;
|
|
IncrementContentVersionNumber();
|
|
}
|
|
}
|
|
|
|
bool ON_TextStyle::FontIsSet() const
|
|
{
|
|
return (0 != (m_is_set_bits & ON_TextStyle::font_bit));
|
|
}
|
|
|
|
void ON_TextStyle::LockFont()
|
|
{
|
|
m_is_locked_bits |= ON_TextStyle::font_bit;
|
|
}
|
|
|
|
bool ON_TextStyle::FontIsLocked() const
|
|
{
|
|
return (0 != (m_is_locked_bits & ON_TextStyle::font_bit));
|
|
}
|
|
|
|
|
|
void ON_TextStyle::SetFont(
|
|
const ON_Font& font_characteristics
|
|
)
|
|
{
|
|
return SetFont(&font_characteristics);
|
|
}
|
|
|
|
void ON_TextStyle::SetFont(
|
|
const ON_Font* font_characteristics
|
|
)
|
|
{
|
|
if (false == FontIsLocked())
|
|
{
|
|
m_font_description = ON_wString::EmptyString;
|
|
m_apple_font_name = ON_wString::EmptyString;
|
|
|
|
m_managed_font
|
|
= (nullptr == font_characteristics)
|
|
? nullptr
|
|
: font_characteristics->ManagedFont();
|
|
|
|
|
|
if (nullptr == m_managed_font)
|
|
{
|
|
m_managed_font = &ON_Font::Default;
|
|
}
|
|
|
|
if (nullptr != font_characteristics)
|
|
{
|
|
m_font_description = font_characteristics->Description();
|
|
m_apple_font_name = font_characteristics->PostScriptName();
|
|
}
|
|
|
|
if (m_font_description.IsEmpty())
|
|
m_font_description = m_managed_font->Description();
|
|
|
|
if (m_apple_font_name.IsEmpty())
|
|
m_apple_font_name = m_managed_font->PostScriptName();
|
|
|
|
m_is_set_bits |= ON_TextStyle::font_bit;
|
|
IncrementContentVersionNumber();
|
|
}
|
|
}
|
|
|
|
void ON_TextStyle::SetFontFromDescription(
|
|
const wchar_t* font_description,
|
|
const wchar_t* apple_font_name,
|
|
const ON_Font* alternate_font
|
|
)
|
|
{
|
|
ON_wString local_font_description(font_description);
|
|
local_font_description.TrimLeftAndRight();
|
|
ON_wString local_apple_font_name(apple_font_name);
|
|
local_apple_font_name.TrimLeftAndRight();
|
|
if (local_font_description.IsEmpty())
|
|
{
|
|
SetFont(alternate_font);
|
|
}
|
|
else if (false == FontIsLocked())
|
|
{
|
|
ON_Font font_characteristics;
|
|
font_characteristics.SetFromFontDescription(
|
|
static_cast<const wchar_t*>(local_font_description),
|
|
static_cast<const wchar_t*>(local_apple_font_name)
|
|
);
|
|
const ON_Font* managed_font = font_characteristics.ManagedFont();
|
|
if (nullptr == managed_font)
|
|
{
|
|
SetFont(alternate_font);
|
|
}
|
|
else
|
|
{
|
|
SetFont(managed_font);
|
|
m_font_description = local_font_description;
|
|
m_apple_font_name = local_apple_font_name;
|
|
}
|
|
unsigned char font_is_set_bit = 1;
|
|
m_is_set_bits &= font_is_set_bit;
|
|
IncrementContentVersionNumber();
|
|
}
|
|
}
|
|
|
|
bool ON_TextStyle::EqualTextStyleFontAndName(
|
|
const ON_TextStyle& a,
|
|
const ON_TextStyle& b
|
|
)
|
|
{
|
|
return (
|
|
a.Font().RuntimeSerialNumber() == b.Font().RuntimeSerialNumber()
|
|
&& a.m_font_description == b.m_font_description
|
|
&& ON_ModelComponent::CompareNameExact(a, b)
|
|
);
|
|
}
|
|
|
|
const wchar_t* ON_TextStyle::GetNameAndFontDescription(
|
|
const wchar_t* sSeparator,
|
|
ON_wString& name_and_font_description
|
|
) const
|
|
{
|
|
GetName(name_and_font_description);
|
|
if ( FontIsSet() )
|
|
{
|
|
ON_wString font_description = FontDescription();
|
|
if (font_description != name_and_font_description)
|
|
{
|
|
if (name_and_font_description.IsNotEmpty() && font_description.IsNotEmpty())
|
|
name_and_font_description += sSeparator;
|
|
name_and_font_description += font_description;
|
|
if (name_and_font_description.IsEmpty() || font_description.IsEmpty())
|
|
name_and_font_description.TrimLeftAndRight();
|
|
}
|
|
}
|
|
return static_cast<const wchar_t*>(name_and_font_description);
|
|
}
|
|
|
|
const ON_Font& ON_TextStyle::Font() const
|
|
{
|
|
return (nullptr != m_managed_font && m_managed_font->IsManagedFont()) ? *m_managed_font : ON_Font::Default;
|
|
}
|
|
|
|
const ON_wString& ON_TextStyle::FontDescription() const
|
|
{
|
|
return m_font_description;
|
|
}
|
|
|
|
const wchar_t* ON_TextStyle::FontDescriptionAsPointer() const
|
|
{
|
|
return static_cast<const wchar_t*>(m_font_description);
|
|
}
|
|
|
|
|
|
const ON_wString& ON_TextStyle::AppleFontName() const
|
|
{
|
|
return m_apple_font_name;
|
|
}
|
|
|
|
const wchar_t* ON_TextStyle::AppleFontNameAsPointer() const
|
|
{
|
|
return static_cast<const wchar_t*>(m_apple_font_name);
|
|
}
|
|
|
|
|
|
bool ON_TextStyle::IsValid(ON_TextLog* text_log) const
|
|
{
|
|
return (
|
|
FontIsSet()
|
|
&& ON_ModelComponent::Type::TextStyle == ComponentType()
|
|
&& ON_ModelComponent::IsValid(text_log)
|
|
&& nullptr != m_managed_font
|
|
&& m_managed_font->IsManagedFont()
|
|
&& m_managed_font->IsValid()
|
|
);
|
|
}
|
|
|
|
void ON_TextStyle::Dump(ON_TextLog& dump) const
|
|
{
|
|
dump.Print("Text Style\n");
|
|
dump.PushIndent();
|
|
|
|
ON_ModelComponent::Dump(dump);
|
|
|
|
dump.Print(L"Font = \"%ls\"\n", static_cast<const wchar_t*>(m_font_description));
|
|
|
|
dump.PopIndent();
|
|
}
|
|
|