Files
Slnkdwf/Whiptk702/text.cpp
Jos Groot Lipman 0b9083fc17 SLNKDWF 2.11
svn path=/Slnkdwf/trunk/; revision=12487
2008-02-12 07:07:56 +00:00

856 lines
32 KiB
C++

// Copyright (c) 1996-2001 by Autodesk, Inc.
//
// By using this code, you are agreeing to the terms and conditions of
// the License Agreement included in the documentation for this code.
//
// AUTODESK MAKES NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE CORRECTNESS
// OF THIS CODE OR ANY DERIVATIVE WORKS WHICH INCORPORATE IT. AUTODESK
// PROVIDES THE CODE ON AN "AS-IS" BASIS AND EXPLICITLY DISCLAIMS ANY
// LIABILITY, INCLUDING CONSEQUENTIAL AND INCIDENTAL DAMAGES FOR ERRORS,
// OMISSIONS, AND OTHER PROBLEMS IN THE CODE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer Software
// Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) (Rights in Technical
// Data and Computer Software), as applicable.
//
// $Header: /Components/Internal/DWF Toolkit/v7.0.1/develop/global/src/dwf/whiptk/text.cpp 5 5/09/05 12:39a Evansg $
#include "whiptk/pch.h"
#include <stddef.h>
#include <assert.h>
///////////////////////////////////////////////////////////////////////////
WT_Text::WT_Text (WT_Text const &in)
: WT_Drawable()
, m_position(in.m_position)
, m_string(in.m_string)
, m_option_bounds(in.m_option_bounds)
, m_option_overscore(in.m_option_overscore)
, m_option_underscore(in.m_option_underscore)
, m_option_reserved(in.m_option_reserved)
, m_stage(in.m_stage)
, m_transformed(in.m_transformed)
, m_relativized(in.m_relativized)
, m_optioncode(in.m_optioncode)
, m_obsolete_font_holder(in.m_obsolete_font_holder)
, m_obsolete_length_holder(in.m_obsolete_length_holder)
, m_obsolete_msg_holder(in.m_obsolete_msg_holder)
{
}
///////////////////////////////////////////////////////////////////////////
WT_Text & WT_Text::operator= (WT_Text const & in)
{
m_position = in.m_position;
m_string = in.m_string;
m_option_bounds = in.m_option_bounds;
m_option_overscore = in.m_option_overscore;
m_option_underscore = in.m_option_underscore;
m_option_reserved = in.m_option_reserved;
m_stage = in.m_stage;
m_transformed = in.m_transformed;
m_relativized = in.m_relativized;
m_optioncode = in.m_optioncode;
m_obsolete_font_holder = in.m_obsolete_font_holder;
m_obsolete_length_holder = in.m_obsolete_length_holder;
m_obsolete_msg_holder = in.m_obsolete_msg_holder;
return *this;
}
///////////////////////////////////////////////////////////////////////////
WT_Text::WT_Text ()
: m_position (WT_Logical_Point (0,0))
, m_stage (Getting_Started)
, m_transformed (WD_False)
, m_relativized (WD_False)
, m_obsolete_font_holder (WD_Null)
{ }
///////////////////////////////////////////////////////////////////////////
WT_Text::~WT_Text()
{
if (m_obsolete_font_holder)
delete m_obsolete_font_holder;
}
///////////////////////////////////////////////////////////////////////////
WT_Text::WT_Text (WT_Logical_Point const & position,
WT_String const & string,
WT_Logical_Point const * bounds,
WT_Unsigned_Integer16 overscore_count,
WT_Unsigned_Integer16 const * overscore_pos,
WT_Unsigned_Integer16 underscore_count,
WT_Unsigned_Integer16 const * underscore_pos)
: m_position (position)
, m_string(string)
, m_stage (Getting_Started)
, m_transformed (WD_False)
, m_relativized (WD_False)
, m_obsolete_font_holder (WD_Null)
{
m_option_bounds.set(bounds);
if (overscore_count)
m_option_overscore.set(overscore_count, overscore_pos);
if (underscore_count)
m_option_underscore.set(underscore_count, underscore_pos);
}
///////////////////////////////////////////////////////////////////////////
WT_Text::WT_Text (WT_Logical_Point const & position,
WT_String const & string)
: m_position (position)
, m_string(string)
, m_stage (Getting_Started)
, m_transformed (WD_False)
, m_relativized (WD_False)
, m_obsolete_font_holder (WD_Null)
{
}
///////////////////////////////////////////////////////////////////////////
WT_Object::WT_ID WT_Text::object_id() const
{
return Text_ID;
}
///////////////////////////////////////////////////////////////////////////
#if DESIRED_CODE(WHIP_OUTPUT)
WT_Result WT_Text::serialize(WT_File & file) const
{
WD_CHECK (file.dump_delayed_drawable());
// BPM: This is a hack, but is the best I can do for now.
// Here's the issue: if Tahoe has set the heuristic to flip landscape into portrait,
// then we actually need the Font attribute to have a different rotation.
// The rotation code will do the adjustment, but we need to make sure that
// the rendition sync code "thinks" the font attribute might need updating.
file.desired_rendition().font().rotation() = file.desired_rendition().font().rotation();
WT_Integer32 parts_to_sync = WT_Rendition::Color_Bit |
// WT_Rendition::Color_Map_Bit |
// WT_Rendition::Fill_Bit |
// WT_Rendition::Fill_Pattern_Bit |
// WT_Rendition::Merge_Control_Bit |
WT_Rendition::BlockRef_Bit |
WT_Rendition::Visibility_Bit |
// WT_Rendition::Line_Weight_Bit |
WT_Rendition::Pen_Pattern_Bit |
// WT_Rendition::Line_Pattern_Bit |
// WT_Rendition::Line_Caps_Bit |
// WT_Rendition::Line_Join_Bit |
// WT_Rendition::Marker_Size_Bit |
// WT_Rendition::Marker_Symbol_Bit |
WT_Rendition::URL_Bit |
WT_Rendition::Layer_Bit |
WT_Rendition::Viewport_Bit |
WT_Rendition::Font_Extension_Bit |
WT_Rendition::Font_Bit |
WT_Rendition::Object_Node_Bit;
WD_CHECK (file.desired_rendition().sync(file, parts_to_sync));
if (file.heuristics().apply_transform())
((WT_Text *)this)->transform (file.heuristics().transform());
if (file.heuristics().allow_binary_data())
{
((WT_Text *)this)->relativize(file);
if (m_option_bounds.bounds() ||
m_option_overscore.count() ||
m_option_underscore.count())
{
// Advanced binary text
WD_CHECK (file.write((WT_Byte) 0x18)); // CTRL-X
WD_CHECK (file.write(1, &m_position));
WD_CHECK (m_string.serialize(file, WD_True));
WD_CHECK (m_option_overscore.serialize(*this, file));
WD_CHECK (m_option_underscore.serialize(*this, file));
WD_CHECK (m_option_bounds.serialize(*this, file));
if (file.heuristics().target_version() >= REVISION_WHEN_PACKAGE_FORMAT_BEGINS)
WD_CHECK (m_option_reserved.serialize(*this, file));
}
else
{
// Basic binary text
WD_CHECK (file.write((WT_Byte) 'x'));
WD_CHECK (file.write(1, &m_position));
WD_CHECK (m_string.serialize(file, WD_True));
}
} // if (allow binary data)
else
{
// Extended ASCII
// Don't relativize ASCII objects
WD_CHECK (file.write_geom_tab_level());
WD_CHECK (file.write("(Text "));
WD_CHECK (file.write_ascii(m_position));
WD_CHECK (file.write((WT_Byte) ' '));
WD_CHECK (m_string.serialize(file));
WD_CHECK (m_option_overscore.serialize(*this, file));
WD_CHECK (m_option_underscore.serialize(*this, file));
WD_CHECK (m_option_bounds.serialize(*this, file));
if (file.heuristics().target_version() >= REVISION_WHEN_PACKAGE_FORMAT_BEGINS)
WD_CHECK (m_option_reserved.serialize(*this, file));
WD_CHECK (file.write((WT_Byte) ')'));
} // else (extended ASCII output)
return WT_Result::Success;
}
#else
WT_Result WT_Text::serialize(WT_File &) const
{
return WT_Result::Success;
}
#endif // DESIRED_CODE()
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Text::materialize(WT_Opcode const & opcode, WT_File & file)
{
switch (opcode.type())
{
case WT_Opcode::Single_Byte:
{
if (file.rendition().drawing_info().decimal_revision() < REVISION_WHEN_DRAW_TEXT_ATTRIBUTES_REMOVED)
return materialize_obsolete_form(opcode, file); // Old obsolete version of DrawText opcode
else
{
// Current version of DrawText opcode
switch (opcode.token()[0])
{
case 0x18: // Ctrl-X
{
switch (m_stage)
{
case Getting_Started:
m_stage = Getting_Position;
// No break;
case Getting_Position:
WD_CHECK (file.read(1, &m_position));
m_stage = Getting_String;
// No break
case Getting_String:
WD_CHECK (m_string.materialize(file));
m_stage = Getting_Overscore;
// No break
case Getting_Overscore:
WD_CHECK (m_option_overscore.materialize(*this, m_optioncode, file));
m_stage = Getting_Underscore;
// No break
case Getting_Underscore:
WD_CHECK (m_option_underscore.materialize(*this, m_optioncode, file));
m_stage = Getting_Bounds;
// No break
case Getting_Bounds:
WD_CHECK (m_option_bounds.materialize(*this, m_optioncode, file));
m_stage = Getting_Reserved;
// No break
case Getting_Reserved:
if (file.rendition().drawing_info().decimal_revision() >= REVISION_WHEN_PACKAGE_FORMAT_BEGINS)
WD_CHECK (m_option_reserved.materialize(*this, m_optioncode, file));
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
} // case Ctrl-X
break;
case 'x':
{
switch (m_stage)
{
case Getting_Started:
m_stage = Getting_Position;
// No break
case Getting_Position:
WD_CHECK (file.read(1, &m_position));
m_stage = Getting_String;
// No break
case Getting_String:
WD_CHECK (m_string.materialize(file));
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
} // switch (m_stage)
} break; // case 'x'
default:
return WT_Result::Opcode_Not_Valid_For_This_Object; // Illegal opcode token
} // switch (opcode token)
} // else (current version of DrawText)
m_relativized = WD_True;
de_relativize(file);
} break;
case WT_Opcode::Extended_ASCII:
{
switch (m_stage)
{
case Getting_Started:
m_stage = Getting_Position;
// No break
case Getting_Position:
WD_CHECK (file.read_ascii(m_position));
m_stage = Getting_String;
// No break
case Getting_String:
WD_CHECK (m_string.materialize(file));
m_stage = Getting_Next_Optioncode;
// No break
Getting_Next_Optioncode_Hop:
case Getting_Next_Optioncode:
WD_CHECK(m_optioncode.get_optioncode(file));
if (m_optioncode.type() == WT_Opcode::Null_Optioncode)
{
m_stage = Skipping_Last_Paren;
goto Skipping_Last_Paren_Hop;
}
m_stage = Materializing_Option;
// No Break;
case Materializing_Option:
switch (m_optioncode.option_id())
{
case WT_Text_Optioncode::Overscore_Option:
WD_CHECK(m_option_overscore.materialize(*this, m_optioncode, file));
break;
case WT_Text_Optioncode::Underscore_Option:
WD_CHECK(m_option_underscore.materialize(*this, m_optioncode, file));
break;
case WT_Text_Optioncode::Bounds_Option:
WD_CHECK(m_option_bounds.materialize(*this, m_optioncode, file));
break;
case WT_Text_Optioncode::Reserved_Option:
WD_CHECK(m_option_reserved.materialize(*this, m_optioncode, file));
break;
case WT_Text_Optioncode::Unknown_Option:
WD_CHECK(m_optioncode.skip_past_matching_paren(file));
break;
default:
return WT_Result::Internal_Error;
} // switch (m_sub_option.option_id())
m_stage = Getting_Next_Optioncode;
goto Getting_Next_Optioncode_Hop;
Skipping_Last_Paren_Hop:
case Skipping_Last_Paren:
WD_CHECK (opcode.skip_past_matching_paren(file));
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
} // switch (m_stage)
} break; // ASCII
case WT_Opcode::Extended_Binary:
default:
{
return WT_Result::Opcode_Not_Valid_For_This_Object;
} break;
} // switch
if (file.heuristics().apply_transform())
transform(file.heuristics().transform());
m_materialized = WD_True;
return WT_Result::Success;
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Text::materialize_obsolete_form(WT_Opcode const & opcode, WT_File & file)
{
WT_Integer16 tmp_int16;
WT_Integer32 tmp_int32;
switch (opcode.token()[0])
{
case 'x':
{
switch (m_stage)
{
case Getting_Started:
WD_Assert(!m_obsolete_font_holder);
m_obsolete_font_holder = new WT_Font;
if (!m_obsolete_font_holder)
return WT_Result::Out_Of_Memory_Error;
m_obsolete_font_holder->set_fields_defined( WT_Font::FONT_HEIGHT_BIT |
WT_Font::FONT_ROTATION_BIT |
WT_Font::FONT_OBLIQUE_BIT |
WT_Font::FONT_WIDTH_SCALE_BIT |
WT_Font::FONT_SPACING_BIT |
WT_Font::FONT_FLAGS_BIT );
m_stage = Getting_Width_Scale;
// No break
case Getting_Width_Scale:
WD_CHECK (file.read(tmp_int16));
m_obsolete_font_holder->width_scale().set(tmp_int16);
m_stage = Getting_Spacing;
case Getting_Spacing:
WD_CHECK (file.read(tmp_int16));
m_obsolete_font_holder->spacing().set(tmp_int16);
m_stage = Getting_Flags;
case Getting_Flags:
WD_CHECK (file.read(tmp_int32));
m_obsolete_font_holder->flags().set(tmp_int32);
m_stage = Getting_Oblique_Angle;
// No break
case Getting_Oblique_Angle:
WD_CHECK (file.read(tmp_int16));
m_obsolete_font_holder->oblique().set(tmp_int16);
m_stage = Getting_Overscore;
// No break
case Getting_Overscore:
WD_CHECK (m_option_overscore.materialize(*this, m_optioncode, file));
m_stage = Getting_Underscore;
// No break
case Getting_Underscore:
WD_CHECK (m_option_underscore.materialize(*this, m_optioncode, file));
m_stage = Getting_Rotation;
// No break
case Getting_Rotation:
WD_CHECK (file.read(tmp_int16));
m_obsolete_font_holder->rotation().set(tmp_int16);
m_stage = Getting_Height;
// No break
case Getting_Height:
WD_CHECK (file.read(tmp_int32));
if (file.heuristics().apply_transform())
tmp_int32 = (WT_Integer32) (tmp_int32 * file.heuristics().transform().m_y_scale);
m_obsolete_font_holder->height().set(tmp_int32);
m_stage = Getting_Position;
// No break
case Getting_Position:
WD_CHECK (file.read(1, &m_position));
m_stage = Getting_BBox_Deltas;
// No break
case Getting_BBox_Deltas:
{
WT_Logical_Point tmp_bbox[4];
WD_CHECK (file.read(4, tmp_bbox));
// convert from relative to absolute
m_position = file.de_update_current_point(m_position);
m_relativized = WD_False;
WT_Integer32 delta[8];
delta[0] = tmp_bbox[0].m_x;
delta[1] = tmp_bbox[0].m_y;
delta[2] = tmp_bbox[1].m_x;
delta[3] = tmp_bbox[1].m_y;
delta[4] = tmp_bbox[2].m_x;
delta[5] = tmp_bbox[2].m_y;
delta[6] = tmp_bbox[3].m_x;
delta[7] = tmp_bbox[3].m_y;
tmp_bbox[0].m_x = m_position.m_x + delta[4];
tmp_bbox[0].m_y = m_position.m_y + delta[6];
tmp_bbox[1].m_x = tmp_bbox[0].m_x + delta[7];
tmp_bbox[1].m_y = tmp_bbox[0].m_y + delta[5];
tmp_bbox[2].m_x = tmp_bbox[1].m_x + delta[2];
tmp_bbox[2].m_y = tmp_bbox[1].m_y + delta[3];
tmp_bbox[3].m_x = tmp_bbox[0].m_x + delta[0];
tmp_bbox[3].m_y = tmp_bbox[0].m_y + delta[1];
m_option_bounds.set(tmp_bbox);
m_stage = Getting_Str_Length;
}
// No break
case Getting_Str_Length:
WD_CHECK (file.read_count(m_obsolete_length_holder));
m_obsolete_msg_holder = new unsigned short[m_obsolete_length_holder + 1];
if (!m_obsolete_msg_holder)
throw WT_Result::Out_Of_Memory_Error;
m_stage = Getting_Msg;
// No break
case Getting_Msg:
WD_CHECK (file.read( 2 * m_obsolete_length_holder, (WT_Byte *)m_obsolete_msg_holder));
m_obsolete_msg_holder[m_obsolete_length_holder] = 0;
m_string.set(m_obsolete_length_holder, m_obsolete_msg_holder);
delete []m_obsolete_msg_holder;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
} // switch (m_stage)
if (file.heuristics().apply_transform())
transform(file.heuristics().transform());
} break;
case 0x18:
{
WT_Integer32 tmp_int32;
WT_Integer16 tmp_int16;
switch (m_stage)
{
case Getting_Started:
WD_Assert(!m_obsolete_font_holder);
m_obsolete_font_holder = new WT_Font;
if (!m_obsolete_font_holder)
return WT_Result::Out_Of_Memory_Error;
m_obsolete_font_holder->set_fields_defined( WT_Font::FONT_HEIGHT_BIT |
WT_Font::FONT_ROTATION_BIT );
m_stage = Getting_Rotation;
case Getting_Rotation:
WD_CHECK (file.read(tmp_int16));
m_obsolete_font_holder->rotation().set(tmp_int16);
m_stage = Getting_Height;
case Getting_Height:
WD_CHECK (file.read(tmp_int32));
if (file.heuristics().apply_transform())
tmp_int32 = (WT_Integer32) (tmp_int32 * file.heuristics().transform().m_y_scale);
m_obsolete_font_holder->height().set(tmp_int32);
m_stage = Getting_Position;
case Getting_Position:
WD_CHECK (file.read(1, &m_position));
m_relativized = WD_True;
m_stage = Getting_Str_Length;
case Getting_Str_Length:
WD_CHECK (file.read_count(m_obsolete_length_holder));
m_obsolete_msg_holder = new unsigned short[m_obsolete_length_holder + 1];
if (!m_obsolete_msg_holder)
throw WT_Result::Out_Of_Memory_Error;
m_stage = Getting_Msg;
// No break
case Getting_Msg:
WD_CHECK (file.read( 2 * m_obsolete_length_holder, (WT_Byte *)m_obsolete_msg_holder));
m_obsolete_msg_holder[m_obsolete_length_holder] = 0;
m_string.set(m_obsolete_length_holder, m_obsolete_msg_holder);
delete []m_obsolete_msg_holder;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
} // switch (m_stage)
} break;
default:
{
return WT_Result::Opcode_Not_Valid_For_This_Object;
} break;
} // switch
de_relativize(file);
if (file.heuristics().apply_transform())
transform(file.heuristics().transform());
m_materialized = WD_True;
// Now send these WT_Font attributes off for processing...
if (m_obsolete_font_holder)
{
m_obsolete_font_holder->process(file);
delete m_obsolete_font_holder;
m_obsolete_font_holder = WD_Null;
}
return WT_Result::Success;
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Text::skip_operand(WT_Opcode const & opcode, WT_File & file)
{
switch (opcode.type())
{
case WT_Opcode::Single_Byte:
{
return materialize(opcode, file);
} break;
case WT_Opcode::Extended_ASCII:
WD_CHECK (opcode.skip_past_matching_paren(file));
break;
case WT_Opcode::Extended_Binary:
default:
{
return WT_Result::Opcode_Not_Valid_For_This_Object;
} break;
} // switch
return WT_Result::Success;
}
///////////////////////////////////////////////////////////////////////////
void WT_Text::transform(WT_Transform const & transform)
{
if (!m_transformed)
{
WT_Logical_Point tmp_pt;
tmp_pt = m_position;
m_position = tmp_pt * transform;
m_option_bounds.transform(transform);
m_transformed = WD_True;
}
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Text::process(WT_File & file)
{
WD_Assert (file.text_action());
return (file.text_action())(*this, file);
}
WT_Result WT_Text::default_process(WT_Text &, WT_File &)
{
return WT_Result::Success;
}
///////////////////////////////////////////////////////////////////////////
#if DESIRED_CODE(WHIP_OUTPUT)
void WT_Text::relativize(WT_File & file)
{
if (!m_relativized)
{
m_position = file.update_current_point(m_position);
m_option_bounds.relativize(file);
m_relativized = WD_True;
} // If (!relativized)
}
#else
void WT_Text::relativize(WT_File &)
{
}
#endif // DESIRED_CODE()
///////////////////////////////////////////////////////////////////////////
void WT_Text::de_relativize(WT_File & file)
{
if (m_relativized)
{
m_position = file.de_update_current_point(m_position);
m_option_bounds.de_relativize(file);
m_relativized = WD_False;
} // If (!relativized)
}
///////////////////////////////////////////////////////////////////////////
// FIXME: WT_Text::update_bounds is completely Win32 specific, and must be ported.
#ifdef WD_WIN32_SYSTEM
#include <tchar.h>
#pragma comment (lib, "gdi32.lib") //for font bounds approximation
void WT_Text::update_bounds(WT_File * file)
{
if (m_option_bounds.bounds() != WD_Null)
{
WT_Drawable::update_bounds(m_option_bounds.bounds(), 2);
return;
}
WT_Drawable::update_bounds(m_position); //base point
if (m_string.length()==0)
return;
WT_Integer32 height = file->rendition().font().height();
int rotation = (int)((float)TWO_PI * (float)file->rendition().font().rotation() / 65536.0f);
int oblique = (int)((float)TWO_PI * (float)file->rendition().font().oblique() / 65536.0f);
BYTE charset = file->rendition().font().charset().charset();
BYTE pitch_and_family = file->rendition().font().pitch().pitch() | file->rendition().font().family().family();
UINT string_length = m_string.length();
BYTE italic = file->rendition().font().style().italic();
BYTE underline = file->rendition().font().style().underlined();
BYTE bold = file->rendition().font().style().bold();
//
// this is dangerous since it assumes wchar_t is always 16-bit uchar
//
wchar_t* facename = new wchar_t[file->rendition().font().font_name().name().length()+1];
const wchar_t* cwstr = (const wchar_t*)file->rendition().font().font_name().name().unicode();
if (cwstr)
{
wcscpy(facename, cwstr);
}
else
{
facename[0] = 0;
}
wchar_t* wstr = new wchar_t[m_string.length()+1];
wcscpy(wstr, (const wchar_t*)m_string.unicode());
HWND hwnd = NULL;
HDC hdc = NULL;
do
{
hwnd = ::GetDesktopWindow();
if (!hwnd || hwnd == INVALID_HANDLE_VALUE)
break;
hdc = ::GetDC(hwnd);
if (!hdc || hdc == INVALID_HANDLE_VALUE)
break;
LOGFONTW logfont;
logfont.lfHeight = 2048; //we'll get the right value down below
logfont.lfWidth = 0; //force aspect ratio of font
logfont.lfEscapement = oblique;
logfont.lfOrientation = rotation;
logfont.lfWeight = bold ? FW_BOLD : FW_DONTCARE;
logfont.lfItalic = italic;
logfont.lfUnderline = underline;
//logfont.lfStrikeOut;
logfont.lfCharSet = charset;
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = pitch_and_family;
memset(logfont.lfFaceName,0,LF_FACESIZE*sizeof(wchar_t));
wcsncpy(logfont.lfFaceName,facename,LF_FACESIZE);
HFONT hfont = ::CreateFontIndirectW(&logfont);
if (!hfont || hfont == INVALID_HANDLE_VALUE)
break;
//we want to get the width based on font design units, probably 2048, maybe 1024
//query and figure that out. use that as the height
HGDIOBJ hobj = ::SelectObject(hdc, hfont);
int size = ::GetOutlineTextMetricsW(hdc, 0, NULL);
if (size != 0)
{
OUTLINETEXTMETRICW *otm = (OUTLINETEXTMETRICW *)new char [size];
WD_Assert(otm != NULL);
UINT status = GetOutlineTextMetricsW (hdc, size, otm);
WD_Assert(status != 0);
if (status != 0)
logfont.lfHeight = otm->otmEMSquare;
delete [] otm;
}
else
{
logfont.lfHeight = 1000;
}
logfont.lfHeight *= -1; // Negative is more accurate
::SelectObject(hdc, hobj);
::DeleteObject(hfont);
hfont = ::CreateFontIndirectW(&logfont);
if (!hfont || hfont == INVALID_HANDLE_VALUE)
break;
hobj = ::SelectObject(hdc, hfont);
SIZE fontsize;
::GetTextExtentPointW(hdc, wstr, string_length, &fontsize);
::SelectObject(hdc, hobj);
::DeleteObject(hfont);
//now we have the width in font design units. Now translate this based on font height.
int deltaX = -(int)((double)height * (double)fontsize.cx / (double)logfont.lfHeight);
int deltaY = -(int)((double)height * (double)fontsize.cy / (double)logfont.lfHeight);
bool overflowX = (double)((m_position.m_x + deltaX) - (double)m_position.m_x) != deltaX;
bool overflowY = (double)((m_position.m_y + deltaY) - (double)m_position.m_y) != deltaY;
int ptx = overflowX //exceeded intmax?
? 0x7FFFFFFF
: m_position.m_x + deltaX;
int pty = overflowY //exceeded intmax?
? 0x7FFFFFFF
: m_position.m_y + deltaY;
// GetTextExtentPointW ignores rotation. So rotate around our basepoint ourselves
double drotation = ((float)TWO_PI * (float)file->rendition().font().rotation() / 65536.0f);
#define ROT(x,y) WT_Logical_Point(m_position.m_x+(long)((x)*cos((double)drotation)-(y)*sin((double)drotation)),\
m_position.m_y+(long)((y)*cos((double)drotation)+(x)*sin((double)drotation)))
ptx,pty;
WT_Logical_Point xx[] = { ROT(0,0),
ROT(deltaX,0),
ROT(deltaX,deltaY) ,
ROT(0,deltaY)};
// if (xx[0].m_x < 0 ||xx[1].m_x < 0 ||xx[2].m_x < 0 ||xx[3].m_x < 0)
// DebugBreak();
m_option_bounds.set(xx);
//m_option_bounds.transform(WT_Transform(m_position,1,1, 0));
WT_Drawable::update_bounds(m_option_bounds.bounds(), 4);
} while (false);
if (hdc && hdc != INVALID_HANDLE_VALUE && hwnd && hwnd != INVALID_HANDLE_VALUE)
::ReleaseDC(hwnd, hdc);
delete [] facename;
delete [] wstr;
}
#else // WD_WIN32_SYSTEM
void WT_Text::update_bounds(WT_File *) {
WD_Complain ("WT_Text::update_bounds is not implemented on this system");
}
#endif // WD_WIN32_SYSTEM