/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// Recalculate the selection highlight as the metrics may have changed.
eventData->mUpdateLeftSelectionPosition = true;
eventData->mUpdateRightSelectionPosition = true;
+ eventData->mUpdateHighlightBox = true;
return fontDescriptionRun;
}
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
LAYOUT |
ALIGN |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
UPDATE_DIRECTION |
REORDER );
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
LAYOUT |
ALIGN |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER );
}
}
else
{
- DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored" );
+ DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
mImpl->mAutoScrollEnabled = false;
}
}
return offset;
}
+void Controller::SetHorizontalScrollEnabled( bool enable )
+{
+ if( ( NULL != mImpl->mEventData ) &&
+ mImpl->mEventData->mDecorator )
+ {
+ mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
+ }
+}
+
+bool Controller::IsHorizontalScrollEnabled() const
+{
+ if( ( NULL != mImpl->mEventData ) &&
+ mImpl->mEventData->mDecorator )
+ {
+ return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
+ }
+
+ return false;
+}
+
+void Controller::SetVerticalScrollEnabled( bool enable )
+{
+ if( ( NULL != mImpl->mEventData ) &&
+ mImpl->mEventData->mDecorator )
+ {
+ if( mImpl->mEventData->mDecorator )
+ {
+ mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
+ }
+ }
+}
+
+bool Controller::IsVerticalScrollEnabled() const
+{
+ if( ( NULL != mImpl->mEventData ) &&
+ mImpl->mEventData->mDecorator )
+ {
+ return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
+ }
+
+ return false;
+}
+
+void Controller::SetSmoothHandlePanEnabled( bool enable )
+{
+ if( ( NULL != mImpl->mEventData ) &&
+ mImpl->mEventData->mDecorator )
+ {
+ mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
+ }
+}
+
+bool Controller::IsSmoothHandlePanEnabled() const
+{
+ if( ( NULL != mImpl->mEventData ) &&
+ mImpl->mEventData->mDecorator )
+ {
+ return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
+ }
+
+ return false;
+}
+
void Controller::SetText( const std::string& text )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
- mImpl->mFontDefaults->familyDefined = true;
+ mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
// Clear the font-specific data
ClearFontData();
return EMPTY_STRING;
}
-void Controller::SetDefaultFontStyle( const std::string& style )
-{
- if( NULL == mImpl->mFontDefaults )
- {
- mImpl->mFontDefaults = new FontDefaults();
- }
-
- mImpl->mFontDefaults->mFontStyle = style;
-}
-
-const std::string& Controller::GetDefaultFontStyle() const
-{
- if( NULL != mImpl->mFontDefaults )
- {
- return mImpl->mFontDefaults->mFontStyle;
- }
-
- return EMPTY_STRING;
-}
-
void Controller::SetDefaultFontWeight( FontWeight weight )
{
if( NULL == mImpl->mFontDefaults )
mImpl->RequestRelayout();
}
+bool Controller::IsDefaultFontWeightDefined() const
+{
+ return mImpl->mFontDefaults->weightDefined;
+}
+
FontWeight Controller::GetDefaultFontWeight() const
{
if( NULL != mImpl->mFontDefaults )
mImpl->RequestRelayout();
}
+bool Controller::IsDefaultFontWidthDefined() const
+{
+ return mImpl->mFontDefaults->widthDefined;
+}
+
FontWidth Controller::GetDefaultFontWidth() const
{
if( NULL != mImpl->mFontDefaults )
mImpl->RequestRelayout();
}
+bool Controller::IsDefaultFontSlantDefined() const
+{
+ return mImpl->mFontDefaults->slantDefined;
+}
+
FontSlant Controller::GetDefaultFontSlant() const
{
if( NULL != mImpl->mFontDefaults )
void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange");
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
{
if( UPDATE_INPUT_STYLE == type )
{
+ // Keep a copy of the current input style.
+ InputStyle currentInputStyle;
+ currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
+
// Set first the default input style.
mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
// Update the input style.
mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
+
+ // Compare if the input style has changed.
+ const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
+
+ if( hasInputStyleChanged )
+ {
+ const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
+ // Queue the input style changed signal.
+ mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
+ }
}
// Updates the text style runs by removing characters. Runs with no characters are removed.
if( NULL != mImpl->mEventData )
{
mImpl->mEventData->mInputStyle.familyName = fontFamily;
- mImpl->mEventData->mInputStyle.familyDefined = true;
+ mImpl->mEventData->mInputStyle.isFamilyDefined = true;
if( EventData::SELECTING == mImpl->mEventData->mState )
{
SHAPE_TEXT |
GET_GLYPH_METRICS |
LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER |
ALIGN );
mImpl->mRecalculateNaturalSize = true;
// As the font changes, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
mImpl->mEventData->mScrollAfterUpdatePosition = true;
}
}
return GetDefaultFontFamily();
}
-void Controller::SetInputFontStyle( const std::string& fontStyle )
-{
- if( NULL != mImpl->mEventData )
- {
- mImpl->mEventData->mInputStyle.fontStyle = fontStyle;
- }
-}
-
-const std::string& Controller::GetInputFontStyle() const
-{
- if( NULL != mImpl->mEventData )
- {
- return mImpl->mEventData->mInputStyle.fontStyle;
- }
-
- // Return the default font's style if there is no EventData.
- return GetDefaultFontStyle();
-}
-
void Controller::SetInputFontWeight( FontWeight weight )
{
if( NULL != mImpl->mEventData )
{
mImpl->mEventData->mInputStyle.weight = weight;
- mImpl->mEventData->mInputStyle.weightDefined = true;
+ mImpl->mEventData->mInputStyle.isWeightDefined = true;
if( EventData::SELECTING == mImpl->mEventData->mState )
{
SHAPE_TEXT |
GET_GLYPH_METRICS |
LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER |
ALIGN );
mImpl->mRecalculateNaturalSize = true;
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
mImpl->mEventData->mScrollAfterUpdatePosition = true;
}
}
}
+bool Controller::IsInputFontWeightDefined() const
+{
+ bool defined = false;
+
+ if( NULL != mImpl->mEventData )
+ {
+ defined = mImpl->mEventData->mInputStyle.isWeightDefined;
+ }
+
+ return defined;
+}
+
FontWeight Controller::GetInputFontWeight() const
{
if( NULL != mImpl->mEventData )
if( NULL != mImpl->mEventData )
{
mImpl->mEventData->mInputStyle.width = width;
- mImpl->mEventData->mInputStyle.widthDefined = true;
+ mImpl->mEventData->mInputStyle.isWidthDefined = true;
if( EventData::SELECTING == mImpl->mEventData->mState )
{
SHAPE_TEXT |
GET_GLYPH_METRICS |
LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER |
ALIGN );
mImpl->mRecalculateNaturalSize = true;
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
mImpl->mEventData->mScrollAfterUpdatePosition = true;
}
}
}
+bool Controller::IsInputFontWidthDefined() const
+{
+ bool defined = false;
+
+ if( NULL != mImpl->mEventData )
+ {
+ defined = mImpl->mEventData->mInputStyle.isWidthDefined;
+ }
+
+ return defined;
+}
+
FontWidth Controller::GetInputFontWidth() const
{
if( NULL != mImpl->mEventData )
if( NULL != mImpl->mEventData )
{
mImpl->mEventData->mInputStyle.slant = slant;
- mImpl->mEventData->mInputStyle.slantDefined = true;
+ mImpl->mEventData->mInputStyle.isSlantDefined = true;
if( EventData::SELECTING == mImpl->mEventData->mState )
{
SHAPE_TEXT |
GET_GLYPH_METRICS |
LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER |
ALIGN );
mImpl->mRecalculateNaturalSize = true;
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
mImpl->mEventData->mScrollAfterUpdatePosition = true;
}
}
}
+bool Controller::IsInputFontSlantDefined() const
+{
+ bool defined = false;
+
+ if( NULL != mImpl->mEventData )
+ {
+ defined = mImpl->mEventData->mInputStyle.isSlantDefined;
+ }
+
+ return defined;
+}
+
FontSlant Controller::GetInputFontSlant() const
{
if( NULL != mImpl->mEventData )
if( NULL != mImpl->mEventData )
{
mImpl->mEventData->mInputStyle.size = size;
+ mImpl->mEventData->mInputStyle.isSizeDefined = true;
if( EventData::SELECTING == mImpl->mEventData->mState )
{
SHAPE_TEXT |
GET_GLYPH_METRICS |
LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER |
ALIGN );
mImpl->mRecalculateNaturalSize = true;
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
mImpl->mEventData->mScrollAfterUpdatePosition = true;
}
}
if( NULL != mImpl->mEventData )
{
mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
+ mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
}
}
return layoutSize.height;
}
-bool Controller::Relayout( const Size& size )
+Controller::UpdateTextType Controller::Relayout( const Size& size )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, (mImpl->mAutoScrollEnabled)?"true":"false" );
+ UpdateTextType updateTextType = NONE_UPDATED;
+
if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
{
- bool glyphsRemoved( false );
if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
{
mImpl->mVisualModel->mGlyphPositions.Clear();
- glyphsRemoved = true;
+ updateTextType = MODEL_UPDATED;
}
// Clear the update info. This info will be set the next time the text is updated.
// Not worth to relayout if width or height is equal to zero.
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
- return glyphsRemoved;
+ return updateTextType;
}
// Whether a new size has been set.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
LAYOUT |
ALIGN |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER );
// Set the update info to relayout the whole text.
mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
mImpl->mOperationsPending,
layoutSize ) || updated;
+ if( updated )
+ {
+ updateTextType = MODEL_UPDATED;
+ }
+
// Do not re-do any operation until something changes.
mImpl->mOperationsPending = NO_OPERATION;
}
// Move the cursor, grab handle etc.
- updated = mImpl->ProcessInputEvents() || updated;
+ if( mImpl->ProcessInputEvents() )
+ {
+ updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
+ }
}
// Clear the update info. This info will be set the next time the text is updated.
mImpl->mTextUpdateInfo.Clear();
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
- return updated;
+ return updateTextType;
}
void Controller::ProcessModifyEvents()
events.Clear();
}
+bool Controller::IsInputStyleChangedSignalsQueueEmpty()
+{
+ return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
+}
+
+void Controller::ProcessInputStyleChangedSignals()
+{
+ if( NULL == mImpl->mEventData )
+ {
+ // Nothing to do.
+ return;
+ }
+
+ for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
+ endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
+ it != endIt;
+ ++it )
+ {
+ const InputStyle::Mask mask = *it;
+
+ // Emit the input style changed signal.
+ mImpl->mControlInterface.InputStyleChanged( mask );
+ }
+
+ mImpl->mEventData->mInputStyleChangedQueue.Clear();
+}
+
void Controller::ResetText()
{
// Reset buffers.
const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
+ // Get the current layout size.
+ layoutSize = mImpl->mVisualModel->GetLayoutSize();
+
if( NO_OPERATION != ( LAYOUT & operations ) )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
if( 0u == totalNumberOfGlyphs )
{
- if( NO_OPERATION != ( UPDATE_ACTUAL_SIZE & operations ) )
+ if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
{
mImpl->mVisualModel->SetLayoutSize( Size::ZERO );
}
layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
// Update the visual model.
+ Size newLayoutSize;
viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
glyphPositions,
mImpl->mVisualModel->mLines,
- layoutSize );
+ newLayoutSize );
+ viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
if( viewUpdated )
{
+ layoutSize = newLayoutSize;
+
if ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
{
mImpl->mAutoScrollDirectionRTL = false;
}
} // REORDER
- // Sets the actual size.
- if( NO_OPERATION != ( UPDATE_ACTUAL_SIZE & operations ) )
+ // Sets the layout size.
+ if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
{
mImpl->mVisualModel->SetLayoutSize( layoutSize );
}
// Store the size used to layout the text.
mImpl->mVisualModel->mControlSize = size;
}
- else
- {
- layoutSize = mImpl->mVisualModel->GetLayoutSize();
- }
if( NO_OPERATION != ( ALIGN & operations ) )
{
// Set the flags to redo the layout operations
const OperationsMask layoutOperations = static_cast<OperationsMask>( LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
ALIGN |
REORDER );
mImpl->ChangeState( EventData::EDITING );
mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
}
-
+ mImpl->NotifyImfMultiLineStatus();
if( mImpl->IsShowingPlaceholderText() )
{
// Show alternative placeholder-text when editing
{
if( !mImpl->mEventData->mPreEditFlag )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
// Record the start of the pre-edit text
mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
if( NULL != mImpl->mEventData )
{
DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
+ EventData::State state( mImpl->mEventData->mState );
+ bool relayoutNeeded( false ); // to avoid unnecessary relayouts when tapping an empty text-field
- if( 1u == tapCount )
+ if( mImpl->IsClipboardVisible() )
{
- // This is to avoid unnecessary relayouts when tapping an empty text-field
- bool relayoutNeeded( false );
-
- if( ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
- ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
+ if( EventData::INACTIVE == state || EventData::EDITING == state)
+ {
+ mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
+ }
+ relayoutNeeded = true;
+ }
+ else if( 1u == tapCount )
+ {
+ if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
{
mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); // If Popup shown hide it here so can be shown again if required.
}
- if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != mImpl->mEventData->mState ) )
+ if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
{
- // Already in an active state so show a popup
- if( !mImpl->IsClipboardEmpty() )
- {
- // Shows Paste popup but could show full popup with Selection options. ( EDITING_WITH_POPUP )
- mImpl->ChangeState( EventData::EDITING_WITH_PASTE_POPUP );
- }
- else
- {
- mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
- }
+ mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
relayoutNeeded = true;
}
else
ResetText();
}
- if( EventData::INACTIVE == mImpl->mEventData->mState )
+ if( EventData::INACTIVE == state )
{
mImpl->ChangeState( EventData::EDITING );
}
}
relayoutNeeded = true;
}
-
- // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
- if( relayoutNeeded )
- {
- Event event( Event::TAP_EVENT );
- event.p1.mUint = tapCount;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- mImpl->mEventData->mEventQueue.push_back( event );
-
- mImpl->RequestRelayout();
- }
}
else if( 2u == tapCount )
{
SelectEvent( x, y, false );
}
}
+ // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
+ if( relayoutNeeded )
+ {
+ Event event( Event::TAP_EVENT );
+ event.p1.mUint = tapCount;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ mImpl->mEventData->mEventQueue.push_back( event );
+
+ mImpl->RequestRelayout();
+ }
}
// Reset keyboard as tap event has occurred.
}
void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
- // Show cursor and grabhandle on first tap, this matches the behaviour of tapping when already editing
{
DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
mImpl->RequestRelayout();
}
- else
+ else if( !mImpl->IsClipboardVisible() )
{
// Reset the imf manger to commit the pre-edit before selecting the text.
mImpl->ResetImfManager();
if( NULL != mImpl->mEventData )
{
- mImpl->ChangeState( EventData::SELECTING );
-
if( selectAll )
{
Event event( Event::SELECT_ALL );
case Toolkit::TextSelectionPopup::COPY:
{
mImpl->SendSelectionToClipboard( false ); // Text not modified
- mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
+
+ mImpl->mEventData->mUpdateCursorPosition = true;
+
+ mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
break;
}
case Toolkit::TextSelectionPopup::PASTE:
{
- std::string stringToPaste("");
- mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
- PasteText( stringToPaste );
+ mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
break;
}
case Toolkit::TextSelectionPopup::SELECT:
mImpl->mEventData->mScrollAfterDelete = true;
requestRelayout = true;
- retrieveCursor = true;
}
break;
}
{
mImpl->mOperationsPending = ALL_OPERATIONS;
mImpl->RequestRelayout();
-
- // Do this last since it provides callbacks into application code
- mImpl->mControlInterface.TextChanged();
}
std::string text;
ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
+ if( requestRelayout )
+ {
+ // Do this last since it provides callbacks into application code
+ mImpl->mControlInterface.TextChanged();
+ }
+
return callbackData;
}
SHAPE_TEXT |
GET_GLYPH_METRICS |
LAYOUT |
- UPDATE_ACTUAL_SIZE |
+ UPDATE_LAYOUT_SIZE |
REORDER |
ALIGN );
}