#include "GuiGraphicsWindowsDirect2D.h"
#include "GuiGraphicsLayoutProviderWindowsDirect2D.h"
namespace
{
namespace
{
using
namespace
elements
;
using
namespace
collections
;
namespace
{
class
WindowsDirect2DElementInlineObject
:
public
{
public
:
class
:
public
{
public
:
virtual
(
) =
0
;
virtual
IWindowsDirect2DRenderTarget
*
() =
0
;
virtual
() =
0
;
virtual
IGuiGraphicsParagraphCallback
*
() =
0
;
};
protected
:
;
::
;
*
;
;
;
public
:
WindowsDirect2DElementInlineObject
(
const
::
&
,
*
,
,
)
:counter(
1
)
,properties(
)
,rendererCallback(
)
,start(
)
,length(
)
{
}
~
WindowsDirect2DElementInlineObject
()
{
if
(
.
)
{
*
=
.
();
if
(
graphicsRenderer
)
{
graphicsRenderer
->
(
0
);
}
}
}
()
{
return
;
}
()
{
return
;
}
const
::
&
()
{
return
;
}
<
>
()
{
return
.
;
}
HRESULT STDMETHODCALLTYPE QueryInterface(
void __RPC_FAR *__RPC_FAR *ppvObject
)
{
if
(
)
{
}
}
ULONG STDMETHODCALLTYPE AddRef(void)
{
++
;
}
ULONG STDMETHODCALLTYPE Release(void)
{
if
(--
==
0
)
{
delete
this
;
}
}
STDMETHOD(Draw)(
virtual
__declspec
(nothrow)
__stdcall
(
void
*
,
*
,
,
,
,
,
*
)
override
{
(
((
)
, (
)
),
.
);
if
(
.
)
{
*
=
.
();
if
(
graphicsRenderer
)
{
graphicsRenderer
->
(
bounds
);
}
}
=
->
(
);
if
(
color
.
!=
0
)
{
color
.
/=
2
;
if
(
IWindowsDirect2DRenderTarget
*
=
->
())
{
*
=
renderTarget
->
(
color
);
renderTarget
->
()->
(
D2D1
::
(
bounds
.
-
0.5f
,
bounds
.
-
0.5f
,
bounds
.
+
0.5f
,
bounds
.
+
0.5f
),
brush
);
renderTarget
->
(
color
);
}
}
if
(
.
!= -
1
)
{
if
(
auto
=
->
())
{
auto
=
->
();
auto
=
callback
->
(
.
,
(
(
bounds
.
-
offset
.
,
bounds
.
-
offset
.
),
bounds
.
()));
.
size
;
}
}
}
STDMETHOD(GetMetrics)(
virtual
__declspec
(nothrow)
__stdcall
(
DWRITE_INLINE_OBJECT_METRICS
*
)
override
{
->
=(
)
.
.
;
->
=(
)
.
.
;
->
=(
)(
.
==-
1
?
.
.
:
.
);
metrics->supportsSideways=TRUE;
}
STDMETHOD(GetOverhangMetrics)(
virtual
__declspec
(nothrow)
__stdcall
(
*
)
override
{
->
=
0
;
->
=
0
;
->
=
0
;
->
=
0
;
}
STDMETHOD(GetBreakConditions)(
virtual
__declspec
(nothrow)
__stdcall
(
*
,
*
)
override
{
switch
(
.
)
{
case
::
:
*
=
DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
*
=
DWRITE_BREAK_CONDITION_CAN_BREAK
;
break
;
case
::
:
*
=
DWRITE_BREAK_CONDITION_CAN_BREAK
;
*
=
DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
break
;
default
:
*
=
DWRITE_BREAK_CONDITION_CAN_BREAK
;
*
=
DWRITE_BREAK_CONDITION_CAN_BREAK
;
}
}
};
class
:
public
,
public
,
public
WindowsDirect2DElementInlineObject
::
{
protected
:
struct
{
;
;
(){}
(
,
):start(
),end(
){}
bool
(
const
& )
const
{
return
==
.
; }
bool
(
const
& )
const
{
return
!=
.
; }
bool
(
const
& )
const
{
return
<
.
; }
bool
(
const
& )
const
{
return
<=
.
; }
bool
(
const
& )
const
{
return
>
.
; }
bool
(
const
& )
const
{
return
>=
.
; }
};
typedef
<
*,
<
WindowsDirect2DElementInlineObject
>>
;
typedef
<
,
>
;
typedef
<
,
*>
;
protected
:
IGuiGraphicsLayoutProvider
*
;
*
;
*
;
IWindowsDirect2DRenderTarget
*
;
;
<
>
;
bool
;
;
<
>
;
;
;
;
;
;
bool
;
*
;
bool
;
<
>
;
<
>
;
<
>
;
<
>
;
<
>
;
<
>
;
;
IGuiGraphicsParagraphCallback
*
;
template
<
typename
>
void
(
<
,
>& ,
,
)
{
=
+
;
for
(
=
.
()-
1
;
i
>=
0
;
i
--)
{
=
.
()
i
];
if
(
key
.
<
end
&&
<
key
.
)
{
=
.
()
i
];
=
key
.
;
=
key
.
>
?
key
.
:
;
=
key
.
<
end
?
key
.
:
end
;
=
key
.
;
.
(
key
);
if
(
s1
<
s2
)
{
.
(
(
s1
,
s2
),
value
);
}
if
(
s2
<
s3
)
{
.
(
(
s2
,
s3
),
value
);
}
if
(
s3
<
s4
)
{
.
(
(
s3
,
s4
),
value
);
}
}
}
}
template
<
typename
>
void
(
<
,
>& ,
,
,
const
& )
{
=
+
;
for
(
=
.
()-
1
;
i
>=
0
;
i
--)
{
=
.
()
i
];
if
(
key
.
<
end
&&
<
key
.
)
{
.
(
key
,
);
}
}
}
template
<
typename
>
void
(
<
,
>& )
{
=
.
()-
1
;
=
.
()
lastIndex
];
for
(
=
.
()-
2
;
i
>=-
1
;
i
--)
{
if
(
i
==-
1
||
.
()
i
]!=
lastValue
)
{
if
(
lastIndex
-
i
>
0
)
{
=
.
()
i
+
1
].
;
=
.
()
lastIndex
].
;
(
start
,
end
);
for
(
=
lastIndex
;
j
>
i
;
j
--)
{
.
(
.
()
j
]);
}
.
(
key
,
lastValue
);
}
lastIndex
=
i
;
if
(
i
!=-
1
)
{
lastValue
=
.
()
i
];
}
}
}
}
template
<
typename
>
void
(
<
,
>& ,
,
,
const
& )
{
(
,
,
);
(
,
,
,
);
(
);
}
template
<
typename
>
bool
(
<
,
>& ,
,
& )
{
=
0
;
=
.
()-
1
;
while
(
start
<=
end
)
{
=(
start
+
end
)/
2
;
=
.
()
middle
];
if
(
<
key
.
)
{
end
=
middle
-
1
;
}
else
if
(
>=
key
.
)
{
start
=
middle
+
1
;
}
else
{
=
.
()
middle
];
return
true
;
}
}
return
false
;
}
void
()
{
if
(!
)
{
=
true
;
{
=
0
;
textLayout->GetLineMetrics(NULL, 0, &lineCount);
.
(
lineCount
);
if
(
lineCount
>
0
)
{
(&
0
],
lineCount
, &
lineCount
);
}
.
(
lineCount
);
.
(
lineCount
);
=
0
;
=
0
;
for
(
=
0
;
i
<
.
();
i
++)
{
&
=
i
];
i
]=
start
;
start
+=
metrics
.
;
i
]=
top
;
top
+=
metrics
.
;
}
}
{
=
0
;
textLayout->GetClusterMetrics(NULL, 0, &clusterCount);
.
(
clusterCount
);
if
(
clusterCount
>
0
)
{
(&
0
],
clusterCount
, &
clusterCount
);
}
}
{
=
0
;
.
(
.
());
for
(
=
0
;
i
<
.
();
i
++)
{
=
0
;
=
0
;
&
=
i
];
textLayout->HitTestTextPosition((UINT32)textPos, FALSE, &x, &y, &metrics);
((
)
textPos
,
0
, &
x
, &
y
, &
metrics
);
textPos
+=
metrics
.
;
}
}
{
.
(
.
());
for
(
=
0
;
i
<
.
();
i
++)
{
&
=
i
];
for
(
=
0
;
j
<
metrics
.
;
j
++)
{
metrics
.
+
j
]=
i
;
}
}
}
}
}
public
:
(
IGuiGraphicsLayoutProvider
*
,
const
&
,
*
,
IGuiGraphicsParagraphCallback
*
)
:provider(
)
,dwriteFactory(
GetWindowsDirect2DObjectProvider
()->
())
,renderTarget(
dynamic_cast
<
IWindowsDirect2DRenderTarget
*>(
))
,paragraphText(
)
,textLayout(
0
)
,wrapLine(
true
)
,maxWidth(-
1
)
,caret(-
1
)
,caretFrontSide(
false
)
,caretBrush(
0
)
,formatDataAvailable(
false
)
,paragraphCallback(
)
{
=
()->
()->
();
Direct2DTextFormatPackage
*
=
GetWindowsDirect2DResourceManager
()->
(
defaultFont
);
=
->
(
(
0
,
0
,
0
));
.
(
(
0
,
0
,
0
));
*
=
0
;
=
->
(
.
(),
(
int
)
.
(),
package
->
.
(),
0
,
0
,
&
rawTextLayout
);
{
rawTextLayout
;
(
65536
);
(
DWRITE_WORD_WRAPPING_WRAP
);
}
.
(
(
0
,
.
()),
0
);
.
(
(
0
,
.
()),
(
0
,
0
,
0
,
0
));
GetWindowsDirect2DResourceManager
()->
DestroyDirect2DTextFormat
(
defaultFont
);
}
~
WindowsDirect2DParagraph
()
{
();
FOREACH(Color, color, usedColors)
if
(
bool
=
true
)
for
(
const
::
vl
::
collections
::
<
>&
= ::
vl
::
collections
::
(
);
__scope_variable_flag__
;
__scope_variable_flag__
=
false
)
for
(
;
__foreach_iterator__
.
(
color
);)
{
->
(
color
);
}
}
IGuiGraphicsLayoutProvider
*
()
override
{
return
;
}
*
()
override
{
return
;
}
()
override
{
return
;
}
IGuiGraphicsParagraphCallback
*
()
override
{
return
;
}
bool
()
override
{
return
;
}
void
(
bool
)
override
{
if
(
!=
)
{
=
;
(
?
DWRITE_WORD_WRAPPING_WRAP
:
DWRITE_WORD_WRAPPING_NO_WRAP
);
=
false
;
}
}
()
override
{
return
;
}
void
(
)
override
{
if
(
!=
)
{
=
;
(
==-
1
?
65536
:(
)
);
=
false
;
}
}
()
override
{
switch
(
())
{
case
DWRITE_TEXT_ALIGNMENT_LEADING
:
return
::
;
case
DWRITE_TEXT_ALIGNMENT_CENTER
:
return
::
;
case
DWRITE_TEXT_ALIGNMENT_TRAILING
:
return
::
;
default
:
return
::
;
}
}
void
(
)
override
{
=
false
;
switch
(
)
{
case
::
:
(
DWRITE_TEXT_ALIGNMENT_LEADING
);
break
;
case
::
:
(
DWRITE_TEXT_ALIGNMENT_CENTER
);
break
;
case
::
:
(
DWRITE_TEXT_ALIGNMENT_TRAILING
);
break
;
}
}
bool
(
,
,
const
&
)
override
{
if
(
==
0
)
return
true
;
=
false
;
;
range
.
=(
int
)
;
range
.
=(
int
)
;
=
(
.
(),
range
);
}
bool
(
,
,
)
override
{
if
(
==
0
)
return
true
;
=
false
;
;
range
.
=(
int
)
;
range
.
=(
int
)
;
=
((
)
,
range
);
}
bool
(
,
,
)
override
{
if
(
==
0
)
return
true
;
=
false
;
;
range
.
=(
int
)
;
range
.
=(
int
)
;
hr
=
(
&
?
:
,
range
);
if(FAILED(hr)) return false;
if
((((
)(
hr
)) <
0
))
return
false
;
hr
=
(
&
?
:
DWRITE_FONT_WEIGHT_NORMAL
,
range
);
if(FAILED(hr)) return false;
if
((((
)(
hr
)) <
0
))
return
false
;
hr=textLayout->SetUnderline(value&Underline?TRUE:FALSE, range);
if(FAILED(hr)) return false;
if
((((
)(
hr
)) <
0
))
return
false
;
hr=textLayout->SetStrikethrough(value&Strikeline?TRUE:FALSE, range);
if(FAILED(hr)) return false;
if
((((
)(
hr
)) <
0
))
return
false
;
return
true
;
}
bool
(
,
,
)
override
{
if
(
==
0
)
return
true
;
=
false
;
*
=
->
(
);
.
(
);
;
range
.
=(
int
)
;
range
.
=(
int
)
;
=
(
brush
,
range
);
}
bool
(
,
,
)
override
{
(
,
,
,
);
return
true
;
}
bool
(
,
,
const
&
)
override
{
if
(
.
().
(
.
.
()))
{
return
false
;
}
for
(
=
0
;
i
<
.
();
i
++)
{
<
WindowsDirect2DElementInlineObject
>
=
.
().
(
i
);
if
(
<
inlineObject
()+
inlineObject
() &&
inlineObject
()<
+
)
{
return
false
;
}
}
=
false
;
<
WindowsDirect2DElementInlineObject
>
=
new
WindowsDirect2DElementInlineObject
(
,
this
,
,
);
;
range
.
=(
int
)
;
range
.
=(
int
)
;
=
(
inlineObject
.
(),
range
);
{
if
(
.
)
{
*
=
.
();
if
(
renderer
)
{
renderer
->
(
);
}
.
(
.
.
(),
inlineObject
);
}
(
,
,
,
.
.
());
return
true
;
}
else
{
return
false
;
}
}
bool
(
,
)
override
{
*
=
0
;
if
(
(
,
,
element
) &&
element
)
{
<
WindowsDirect2DElementInlineObject
>
=
element
];
;
range
.
=(
int
)
inlineObject
();
range
.
=(
int
)
inlineObject
();
HRESULT hr=textLayout->SetInlineObject(NULL, range);
{
=
false
;
.
(
element
);
(
,
inlineObject
(),
inlineObject
(), (
*)
0
);
return
true
;
}
else
{
return
false
;
}
}
return
false
;
}
()
override
{
;
(&
metrics
);
return
(
)
(
metrics
.
);
}
(
)
override
{
;
if
(
(
,
,
color
))
{
return
color
;
}
else
{
return
(
0
,
0
,
0
,
0
);
}
}
IWindowsDirect2DRenderTarget
*
()
override
{
return
;
}
bool
(
,
,
bool
)
override
{
if
(!
(
))
return
false
;
if
(
!=-
1
)
();
=
;
;
=
;
=
->
(
);
return
true
;
}
bool
()
override
{
if
(
==-
1
)
return
false
;
=-
1
;
->
(
);
=
0
;
return
true
;
}
struct
{
IWindowsDirect2DRenderTarget
*
=
nullptr
;
*
=
nullptr
;
,
,
,
;
void
()
{
if
(
)
{
->
()->
(
D2D1
::
(
,
,
,
),
);
=
nullptr
;
}
}
void
(
*
,
,
,
,
)
{
if
(
)
{
if
(
!=
)
{
();
}
else
{
= (
+
) /
2
;
if
(
yc
<
||
yc
>
)
{
();
}
}
}
if
(
)
{
if
(
>
)
=
;
if
(
>
)
=
;
if
(
<
)
=
;
if
(
<
)
=
;
}
else
{
=
;
=
;
=
;
=
;
=
;
}
}
};
void
(
)
override
{
.
();
();
{
;
backgroundRenderer
.
=
;
for
(
=
0
;
i
<
.
();
i
++)
{
=
.
()
i
];
=
.
()
i
];
if
(
color
.
>
0
)
{
*
=
->
(
color
);
=
key
.
;
if
(
start
<
0
)
{
start
=
0
;
}
while
(
start
<
.
() &&
start
<
key
.
)
{
=
start
];
&
=
index
];
=
hitTest
.
+ (
)
.
;
=
hitTest
.
+ (
)
.
;
=
x1
+
hitTest
.
;
=
y1
+
hitTest
.
;
x1
-=
0.5f
;
y1
-=
0.0f
;
x2
+=
0.5f
;
y2
+=
0.5f
;
backgroundRenderer
.
(
brush
,
x1
,
y1
,
x2
,
y2
);
start
=
hitTest
.
+
hitTest
.
;
}
->
(
color
);
}
}
backgroundRenderer
.
();
}
->
()->
(
D2D1
::
((
)
.
(), (
)
.
()),
.
(),
,
D2D1_DRAW_TEXT_OPTIONS_NO_SNAP
);
if
(
!= -
1
)
{
=
(
,
);
=
caretBounds
.
+
.
;
=
caretBounds
.
+
.
;
=
y1
+
caretBounds
.
();
->
()->
(
D2D1
::
((
)
x
-
0.5f
, (
)
y1
+
0.5f
),
D2D1
::
((
)
x
-
0.5f
, (
)
y2
+
0.5f
),
);
->
()->
(
D2D1
::
((
)
x
+
0.5f
, (
)
y1
+
0.5f
),
D2D1
::
((
)
x
+
0.5f
, (
)
y2
+
0.5f
),
);
}
}
void
(
,
&
,
&
)
{
=-
1
;
=-
1
;
=
0
;
=
.
()-
1
;
while
(
start
<=
end
)
{
=(
start
+
end
)/
2
;
&
=
middle
];
=
middle
];
=
lineStart
+
metrics
.
-
metrics
.
;
if
(
<
lineStart
)
{
end
=
middle
-
1
;
}
else
if
(
>
lineEnd
)
{
start
=
middle
+
1
;
}
else
if
(
==
lineStart
&&
middle
!=
0
)
{
&
=
middle
-
1
];
=
anotherLine
.
==
0
?
middle
-
1
:
middle
;
=
middle
;
return
;
}
else
if
(
==
lineEnd
&&
middle
!=
.
()-
1
)
{
=
middle
;
=
metrics
.
==
0
?
middle
+
1
:
middle
;
return
;
}
else
{
=
middle
;
=
middle
;
return
;
}
}
}
<
,
>
(
)
{
&
=
];
=
];
return
<
,
>(
top
,
top
+
line
.
);
}
(
)
{
if
(
.
()==
0
)
return
0
;
=
0
;
=
0
;
{
minY
=
0
].
;
&
=
.
()-
1
];
maxY
=
hitTest
.
+
hitTest
.
;
}
if
(
<
minY
)
{
return
0
;
}
else
if
(
>=
maxY
)
{
return
.
()-
1
;
}
=
0
;
=
.
()-
1
;
while
(
start
<=
end
)
{
=(
start
+
end
)/
2
;
<
,
>
=
(
middle
);
minY
=
yRange
.
;
maxY
=
yRange
.
;
if
(
<
minY
)
{
end
=
middle
-
1
;
}
else
if
(
>=
maxY
)
{
start
=
middle
+
1
;
}
else
{
return
middle
;
}
}
return
-
1
;
}
(
,
)
{
&
=
];
=
];
=
lineStart
+
line
.
-
line
.
;
=
0
;
=
0
;
for
(
=
lineStart
;
i
<
lineEnd
;)
{
=
i
];
&
=
index
];
=
hitTest
.
;
=
minX
+
hitTest
.
;
if
(
minLineX
>
minX
)
minLineX
=
minX
;
if
(
maxLineX
<
maxX
)
maxLineX
=
maxX
;
if
(
minX
<=
&&
<
maxX
)
{
&
=
index
];
=
-
minX
;
=
maxX
-
;
if
(
d1
<=
d2
)
{
return
cluster
.
?
i
+
hitTest
.
:
i
;
}
else
{
return
cluster
.
?
i
:
i
+
hitTest
.
;
}
}
i
+=
hitTest
.
;
}
if
(
<
minLineX
)
return
lineStart
;
if
(
>=
maxLineX
)
return
lineEnd
;
return
lineStart
;
}
(
,
,
bool
&
)
override
{
();
if
(
==
)
return
0
;
if
(
==
)
return
.
();
if
(!
(
))
return
-
1
;
=-
1
;
=-
1
;
(
,
frontLineIndex
,
backLineIndex
);
=
?
frontLineIndex
:
backLineIndex
;
&
=
lineIndex
];
=
lineIndex
];
=
lineStart
+
line
.
-
line
.
;
switch
(
)
{
case
:
return
lineIndex
];
case
:
return
lineIndex
]+
line
.
-
line
.
;
case
:
{
if
(
==
0
)
{
return
0
;
}
else
if
(
==
lineStart
)
{
=
lineIndex
-
1
].
;
if
(
offset
>
0
)
{
return
lineStart
-
offset
;
}
}
return
-
1
]].
;
}
case
:
{
if
(
==
.
())
{
return
.
();
}
else
if
(
==
lineEnd
&&
line
.
!=
0
)
{
return
lineEnd
+
line
.
;
}
else
{
=
];
if
(
index
==
.
()-
1
)
return
.
();
return
index
+
1
].
;
}
}
case
:
{
if
(
lineIndex
==
0
)
{
return
;
}
else
{
=
(
,
);
=
true
;
return
(
bounds
.
,
lineIndex
-
1
);
}
}
case
:
{
if
(
lineIndex
==
.
()-
1
)
{
return
;
}
else
{
=
(
,
);
=
false
;
return
(
bounds
.
,
lineIndex
+
1
);
}
}
}
return
-
1
;
}
(
,
bool
)
override
{
();
if
(!
(
))
return
();
if
(
.
()==
0
)
return
(
(
0
,
0
),
(
0
,
()));
=-
1
;
=-
1
;
(
,
frontLineIndex
,
backLineIndex
);
=
?
frontLineIndex
:
backLineIndex
;
<
,
>
=
(
lineIndex
);
&
=
lineIndex
];
if
(
line
.
-
line
.
==
0
)
{
return
(
0
, (
)
lineYRange
.
,
0
, (
)
lineYRange
.
);
}
else
{
=
lineIndex
];
=
lineStart
+
line
.
-
line
.
;
if
(
==
lineStart
)
{
=
false
;
}
else
if
(
==
lineEnd
)
{
=
true
;
}
if
(
)
{
--;
}
=
];
&
=
index
];
&
=
index
];
if
(
cluster
.
)
{
=!
;
}
if
(
)
{
return
(
((
)(
hitTest
.
+
hitTest
.
), (
)
hitTest
.
),
(
0
, (
)
hitTest
.
)
);
}
else
{
return
(
((
)
hitTest
.
, (
)
hitTest
.
),
(
0
, (
)
hitTest
.
)
);
}
}
}
(
)
override
{
();
=
(
.
);
=
(
.
,
lineIndex
);
return
caret
;
}
<
>
(
,
&
,
&
)
override
{
={
0
};
=-
1
;
=
0
;
=
((
)
.
, (
)
.
, &
trailingHit
, &
inside
, &
metrics
);
{
*
=
0
;
if
(
(
,
metrics
.
,
element
) &&
element
)
{
<
WindowsDirect2DElementInlineObject
>
=
element
];
=
inlineObject
();
=
inlineObject
();
return
inlineObject
();
}
}
return
<
>();
}
GetNearestCaretFromTextPos
(
,
bool
)
override
{
();
if
(!
(
))
return
-
1
;
if
(
==
0
||
==
.
())
return
;
=
];
&
=
index
];
if
(
hitTest
.
==
)
{
return
;
}
else
if
(
)
{
return
hitTest
.
;
}
else
{
return
hitTest
.
+
hitTest
.
;
}
}
bool
(
)
override
{
();
if
(!
(
))
return
false
;
if
(
==
0
||
==
.
())
return
true
;
if
(
]].
==
)
return
true
;
=-
1
;
=-
1
;
(
,
frontLineIndex
,
backLineIndex
);
if
(
frontLineIndex
==-
1
&&
backLineIndex
==-
1
)
return
false
;
return
false
;
}
bool
(
)
{
return
0
<=
&&
<=
.
();
}
};
<
>
WindowsDirect2DLayoutProvider
::
(
const
&
,
*
,
elements
::
IGuiGraphicsParagraphCallback
*
)
{
return
new
(
this
,
,
,
);
}
}
}
}