Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
skiko
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liuqiang
skiko
Commits
2ed9168d
Unverified
Commit
2ed9168d
authored
Nov 08, 2022
by
Pavel
Committed by
GitHub
Nov 08, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
take surface props into account when using direct3d (#613)
parent
5616a1b1
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
59 additions
and
42 deletions
+59
-42
SkiaLayer.android.kt
...droidMain/kotlin/org/jetbrains/skiko/SkiaLayer.android.kt
+4
-0
directXRedrawer.cc
skiko/src/awtMain/cpp/windows/directXRedrawer.cc
+4
-3
SkiaLayer.awt.kt
...o/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt
+4
-1
Direct3DContextHandler.kt
...lin/org/jetbrains/skiko/context/Direct3DContextHandler.kt
+3
-1
MetalContextHandler.kt
...kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt
+3
-5
OpenGLContextHandler.kt
...otlin/org/jetbrains/skiko/context/OpenGLContextHandler.kt
+3
-6
Direct3DRedrawer.kt
...n/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt
+4
-3
SkiaLayer.kt
skiko/src/commonMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt
+6
-0
SkiaLayer.ios.kt
...o/src/iosMain/kotlin/org/jetbrains/skiko/SkiaLayer.ios.kt
+4
-0
MetalContextHandler.kt
...kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt
+3
-5
CanvasRenderer.kt
...o/src/jsMain/kotlin/org/jetbrains/skiko/CanvasRenderer.kt
+4
-9
SkiaLayer.js.kt
skiko/src/jsMain/kotlin/org/jetbrains/skiko/SkiaLayer.js.kt
+6
-3
SkiaLayer.linux.kt
...c/linuxMain/kotlin/org/jetbrains/skiko/SkiaLayer.linux.kt
+3
-0
SkiaLayer.macos.kt
...c/macosMain/kotlin/org/jetbrains/skiko/SkiaLayer.macos.kt
+3
-0
MetalContextHandler.macos.kt
.../org/jetbrains/skiko/context/MetalContextHandler.macos.kt
+3
-5
OpenGLContextHandler.macos.kt
...org/jetbrains/skiko/context/OpenGLContextHandler.macos.kt
+2
-1
No files found.
skiko/src/androidMain/kotlin/org/jetbrains/skiko/SkiaLayer.android.kt
View file @
2ed9168d
...
...
@@ -4,6 +4,7 @@ import android.content.Context
import
android.view.*
import
android.view.inputmethod.InputMethodManager
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.PixelGeometry
actual
typealias
SkikoGesturePlatformEvent
=
MotionEvent
actual
typealias
SkikoPlatformPointerEvent
=
MotionEvent
...
...
@@ -109,6 +110,9 @@ actual open class SkiaLayer {
}
}
actual
val
pixelGeometry
:
PixelGeometry
get
()
=
PixelGeometry
.
UNKNOWN
actual
val
component
:
Any
?
get
()
=
this
.
container
...
...
skiko/src/awtMain/cpp/windows/directXRedrawer.cc
View file @
2ed9168d
...
...
@@ -10,6 +10,7 @@
#include "GrBackendSurface.h"
#include "GrDirectContext.h"
#include "SkSurface.h"
#include "../common/interop.hh"
#include "d3d/GrD3DTypes.h"
#include <d3d12sdklayers.h>
...
...
@@ -353,7 +354,7 @@ extern "C"
}
JNIEXPORT
jlong
JNICALL
Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_makeDirectXSurface
(
JNIEnv
*
env
,
jobject
redrawer
,
jlong
devicePtr
,
jlong
contextPtr
,
jint
width
,
jint
height
,
jint
index
)
JNIEnv
*
env
,
jobject
redrawer
,
jlong
devicePtr
,
jlong
contextPtr
,
jint
width
,
jint
height
,
j
object
surfacePropsObj
,
j
int
index
)
{
DirectXDevice
*
d3dDevice
=
fromJavaPointer
<
DirectXDevice
*>
(
devicePtr
);
GrDirectContext
*
context
=
fromJavaPointer
<
GrDirectContext
*>
(
contextPtr
);
...
...
@@ -368,11 +369,11 @@ extern "C"
info
.
fResource
=
d3dDevice
->
buffers
[
index
];
SkSurfaceProps
surfaceProps
(
0
,
kRGB_H_SkPixelGeometry
);
std
::
unique_ptr
<
SkSurfaceProps
>
surfaceProps
=
skija
::
SurfaceProps
::
toSkSurfaceProps
(
env
,
surfacePropsObj
);
GrBackendTexture
backendTexture
((
int
)
d3dDevice
->
buffers
[
index
]
->
GetDesc
().
Width
,
(
int
)
d3dDevice
->
buffers
[
index
]
->
GetDesc
().
Height
,
info
);
auto
result
=
SkSurface
::
MakeFromBackendTexture
(
context
,
backendTexture
,
kTopLeft_GrSurfaceOrigin
,
0
,
kRGBA_8888_SkColorType
,
SkColorSpace
::
MakeSRGB
(),
&
surfaceProps
)
kRGBA_8888_SkColorType
,
SkColorSpace
::
MakeSRGB
(),
surfaceProps
.
get
()
)
.
release
();
return
toJavaPointer
(
result
);
}
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt
View file @
2ed9168d
...
...
@@ -21,6 +21,7 @@ actual open class SkiaLayer internal constructor(
private
val
properties
:
SkiaLayerProperties
,
private
val
renderFactory
:
RenderFactory
=
RenderFactory
.
Default
,
private
val
analytics
:
SkiaLayerAnalytics
=
SkiaLayerAnalytics
.
Empty
,
actual
val
pixelGeometry
:
PixelGeometry
=
PixelGeometry
.
UNKNOWN
,
)
:
JPanel
()
{
internal
companion
object
{
...
...
@@ -53,7 +54,8 @@ actual open class SkiaLayer internal constructor(
isVsyncEnabled
:
Boolean
=
SkikoProperties
.
vsyncEnabled
,
isVsyncFramelimitFallbackEnabled
:
Boolean
=
SkikoProperties
.
vsyncFramelimitFallbackEnabled
,
renderApi
:
GraphicsApi
=
SkikoProperties
.
renderApi
,
analytics
:
SkiaLayerAnalytics
=
SkiaLayerAnalytics
.
Empty
analytics
:
SkiaLayerAnalytics
=
SkiaLayerAnalytics
.
Empty
,
pixelGeometry
:
PixelGeometry
=
PixelGeometry
.
UNKNOWN
,
)
:
this
(
externalAccessibleFactory
,
SkiaLayerProperties
(
...
...
@@ -63,6 +65,7 @@ actual open class SkiaLayer internal constructor(
),
RenderFactory
.
Default
,
analytics
,
pixelGeometry
)
val
canvas
:
java
.
awt
.
Canvas
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/Direct3DContextHandler.kt
View file @
2ed9168d
package
org.jetbrains.skiko.context
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceProps
import
org.jetbrains.skia.impl.getPtr
import
org.jetbrains.skiko.SkiaLayer
import
org.jetbrains.skiko.redrawer.Direct3DRedrawer
...
...
@@ -45,6 +46,7 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : JvmContextHandler(laye
val
scale
=
layer
.
contentScale
val
w
=
(
layer
.
width
*
scale
).
toInt
().
coerceAtLeast
(
0
)
val
h
=
(
layer
.
height
*
scale
).
toInt
().
coerceAtLeast
(
0
)
val
surfaceProps
=
SurfaceProps
(
pixelGeometry
=
layer
.
pixelGeometry
)
if
(
isSizeChanged
(
w
,
h
)
||
isSurfacesNull
())
{
disposeCanvas
()
...
...
@@ -58,7 +60,7 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : JvmContextHandler(laye
try
{
for
(
bufferIndex
in
0
..
bufferCount
-
1
)
{
surfaces
[
bufferIndex
]
=
directXRedrawer
.
makeSurface
(
getPtr
(
context
!!
),
w
,
h
,
bufferIndex
)
surfaces
[
bufferIndex
]
=
directXRedrawer
.
makeSurface
(
getPtr
(
context
!!
),
w
,
h
,
surfaceProps
,
bufferIndex
)
}
}
finally
{
Reference
.
reachabilityFence
(
context
!!
)
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt
View file @
2ed9168d
package
org.jetbrains.skiko.context
import
org.jetbrains.skia.ColorSpace
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceColorFormat
import
org.jetbrains.skia.SurfaceOrigin
import
org.jetbrains.skia.*
import
org.jetbrains.skiko.RenderException
import
org.jetbrains.skiko.SkiaLayer
import
org.jetbrains.skiko.redrawer.MetalRedrawer
...
...
@@ -42,7 +39,8 @@ internal class MetalContextHandler(layer: SkiaLayer) : JvmContextHandler(layer)
renderTarget
!!
,
SurfaceOrigin
.
TOP_LEFT
,
SurfaceColorFormat
.
BGRA_8888
,
ColorSpace
.
sRGB
ColorSpace
.
sRGB
,
SurfaceProps
(
pixelGeometry
=
layer
.
pixelGeometry
)
)
?:
throw
RenderException
(
"Cannot create surface"
)
canvas
=
surface
!!
.
canvas
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.kt
View file @
2ed9168d
package
org.jetbrains.skiko.context
import
org.jetbrains.skia.ColorSpace
import
org.jetbrains.skia.FramebufferFormat
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceColorFormat
import
org.jetbrains.skia.SurfaceOrigin
import
org.jetbrains.skia.*
import
org.jetbrains.skiko.*
internal
class
OpenGLContextHandler
(
layer
:
SkiaLayer
)
:
JvmContextHandler
(
layer
)
{
...
...
@@ -56,7 +52,8 @@ internal class OpenGLContextHandler(layer: SkiaLayer) : JvmContextHandler(layer)
renderTarget
!!
,
SurfaceOrigin
.
BOTTOM_LEFT
,
SurfaceColorFormat
.
RGBA_8888
,
ColorSpace
.
sRGB
ColorSpace
.
sRGB
,
SurfaceProps
(
pixelGeometry
=
layer
.
pixelGeometry
)
)
?:
throw
RenderException
(
"Cannot create surface"
)
}
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt
View file @
2ed9168d
...
...
@@ -4,6 +4,7 @@ import kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
import
org.jetbrains.skia.DirectContext
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceProps
import
org.jetbrains.skiko.*
import
org.jetbrains.skiko.context.Direct3DContextHandler
...
...
@@ -85,8 +86,8 @@ internal class Direct3DRedrawer(
makeDirectXContext
(
device
)
)
fun
makeSurface
(
context
:
Long
,
width
:
Int
,
height
:
Int
,
index
:
Int
)
=
Surface
(
makeDirectXSurface
(
device
,
context
,
width
,
height
,
index
)
fun
makeSurface
(
context
:
Long
,
width
:
Int
,
height
:
Int
,
surfaceProps
:
SurfaceProps
,
index
:
Int
)
=
Surface
(
makeDirectXSurface
(
device
,
context
,
width
,
height
,
surfaceProps
,
index
)
)
fun
resizeBuffers
(
width
:
Int
,
height
:
Int
)
=
resizeBuffers
(
device
,
width
,
height
)
...
...
@@ -101,7 +102,7 @@ internal class Direct3DRedrawer(
private
external
fun
chooseAdapter
(
adapterPriority
:
Int
):
Long
private
external
fun
createDirectXDevice
(
adapter
:
Long
,
contentHandle
:
Long
,
transparency
:
Boolean
):
Long
private
external
fun
makeDirectXContext
(
device
:
Long
):
Long
private
external
fun
makeDirectXSurface
(
device
:
Long
,
context
:
Long
,
width
:
Int
,
height
:
Int
,
index
:
Int
):
Long
private
external
fun
makeDirectXSurface
(
device
:
Long
,
context
:
Long
,
width
:
Int
,
height
:
Int
,
surfaceProps
:
SurfaceProps
,
index
:
Int
):
Long
private
external
fun
resizeBuffers
(
device
:
Long
,
width
:
Int
,
height
:
Int
)
private
external
fun
swap
(
device
:
Long
,
isVsyncEnabled
:
Boolean
)
private
external
fun
disposeDevice
(
device
:
Long
)
...
...
skiko/src/commonMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt
View file @
2ed9168d
...
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.Picture
import
org.jetbrains.skia.PixelGeometry
/**
* Generic layer for Skiko rendering.
...
...
@@ -17,6 +18,11 @@ expect open class SkiaLayer {
*/
val
contentScale
:
Float
/**
* Pixel geometry corresponding to graphics device which renders this layer
*/
val
pixelGeometry
:
PixelGeometry
/**
* If rendering is full screen.
*/
...
...
skiko/src/iosMain/kotlin/org/jetbrains/skiko/SkiaLayer.ios.kt
View file @
2ed9168d
...
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko
import
kotlinx.cinterop.useContents
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.PixelGeometry
import
org.jetbrains.skiko.context.MetalContextHandler
import
org.jetbrains.skiko.redrawer.MetalRedrawer
import
platform.UIKit.*
...
...
@@ -106,6 +107,9 @@ actual open class SkiaLayer {
skikoView
?.
onRender
(
canvas
,
pictureWidth
.
toInt
(),
pictureHeight
.
toInt
(),
getTimeNanos
())
}
actual
val
pixelGeometry
:
PixelGeometry
get
()
=
PixelGeometry
.
UNKNOWN
}
// TODO: do properly
...
...
skiko/src/iosMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt
View file @
2ed9168d
package
org.jetbrains.skiko.context
import
kotlinx.cinterop.useContents
import
org.jetbrains.skia.ColorSpace
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceColorFormat
import
org.jetbrains.skia.SurfaceOrigin
import
org.jetbrains.skia.*
import
org.jetbrains.skiko.RenderException
import
org.jetbrains.skiko.SkiaLayer
import
org.jetbrains.skiko.redrawer.MetalRedrawer
...
...
@@ -55,7 +52,8 @@ internal class MetalContextHandler(layer: SkiaLayer) : ContextHandler(layer, lay
renderTarget
!!
,
SurfaceOrigin
.
TOP_LEFT
,
SurfaceColorFormat
.
BGRA_8888
,
ColorSpace
.
sRGB
ColorSpace
.
sRGB
,
SurfaceProps
(
pixelGeometry
=
layer
.
pixelGeometry
)
)
?:
throw
RenderException
(
"Cannot create surface"
)
canvas
=
surface
!!
.
canvas
...
...
skiko/src/jsMain/kotlin/org/jetbrains/skiko/CanvasRenderer.kt
View file @
2ed9168d
package
org.jetbrains.skiko
import
kotlinx.browser.window
import
org.jetbrains.skia.BackendRenderTarget
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.ColorSpace
import
org.jetbrains.skia.DirectContext
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceColorFormat
import
org.jetbrains.skia.SurfaceOrigin
import
org.jetbrains.skia.*
import
org.jetbrains.skiko.wasm.createWebGLContext
import
org.jetbrains.skiko.wasm.GL
import
org.w3c.dom.HTMLCanvasElement
...
...
@@ -57,7 +51,7 @@ abstract class CanvasRenderer constructor(val htmlCanvas: HTMLCanvasElement) {
* @param scale - a value to adjust the canvas' size
* (https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio)
*/
fun
initCanvas
(
desiredWidth
:
Int
,
desiredHeight
:
Int
,
scale
:
Float
)
{
fun
initCanvas
(
desiredWidth
:
Int
,
desiredHeight
:
Int
,
scale
:
Float
,
pixelGeometry
:
PixelGeometry
)
{
disposeCanvas
()
htmlCanvas
.
width
=
(
desiredWidth
*
scale
).
toInt
()
htmlCanvas
.
height
=
(
desiredHeight
*
scale
).
toInt
()
...
...
@@ -67,7 +61,8 @@ abstract class CanvasRenderer constructor(val htmlCanvas: HTMLCanvasElement) {
renderTarget
!!
,
SurfaceOrigin
.
BOTTOM_LEFT
,
SurfaceColorFormat
.
RGBA_8888
,
ColorSpace
.
sRGB
ColorSpace
.
sRGB
,
SurfaceProps
(
pixelGeometry
=
pixelGeometry
)
)
?:
throw
RenderException
(
"Cannot create surface"
)
canvas
=
surface
!!
.
canvas
}
...
...
skiko/src/jsMain/kotlin/org/jetbrains/skiko/SkiaLayer.js.kt
View file @
2ed9168d
...
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko
import
kotlinx.browser.window
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.PixelGeometry
import
org.w3c.dom.HTMLCanvasElement
import
org.w3c.dom.events.InputEvent
import
org.w3c.dom.events.KeyboardEvent
...
...
@@ -95,14 +96,13 @@ actual open class SkiaLayer {
htmlCanvas
.
style
.
width
=
"${desiredWidth}px"
htmlCanvas
.
style
.
height
=
"${desiredHeight}px"
setOnChangeScaleNotifier
()
state
=
object
:
CanvasRenderer
(
htmlCanvas
)
{
override
fun
drawFrame
(
currentTimestamp
:
Double
)
{
// currentTimestamp is in milliseconds.
val
currentNanos
=
currentTimestamp
*
1
_000_000
skikoView
?.
onRender
(
canvas
!!
,
width
,
height
,
currentNanos
.
toLong
())
}
}.
apply
{
initCanvas
(
desiredWidth
,
desiredHeight
,
contentScale
)
}
}.
apply
{
initCanvas
(
desiredWidth
,
desiredHeight
,
contentScale
,
pixelGeometry
)
}
// See https://www.w3schools.com/jsref/dom_obj_event.asp
// https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
htmlCanvas
.
addEventListener
(
"mousedown"
,
{
event
->
...
...
@@ -145,7 +145,7 @@ actual open class SkiaLayer {
}
private
fun
setOnChangeScaleNotifier
()
{
state
?.
initCanvas
(
desiredWidth
,
desiredHeight
,
contentScale
)
state
?.
initCanvas
(
desiredWidth
,
desiredHeight
,
contentScale
,
this
.
pixelGeometry
)
window
.
matchMedia
(
"(resolution: ${contentScale}dppx)"
).
addEventListener
(
"change"
,
{
setOnChangeScaleNotifier
()
},
true
)
onContentScaleChanged
?.
invoke
(
contentScale
)
}
...
...
@@ -153,6 +153,9 @@ actual open class SkiaLayer {
internal
actual
fun
draw
(
canvas
:
Canvas
)
{
skikoView
?.
onRender
(
canvas
,
state
!!
.
width
,
state
!!
.
height
,
currentNanoTime
())
}
actual
val
pixelGeometry
:
PixelGeometry
get
()
=
PixelGeometry
.
UNKNOWN
}
var
onContentScaleChanged
:
((
Float
)
->
Unit
)?
=
null
...
...
skiko/src/linuxMain/kotlin/org/jetbrains/skiko/SkiaLayer.linux.kt
View file @
2ed9168d
package
org.jetbrains.skiko
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.PixelGeometry
actual
open
class
SkiaLayer
{
actual
var
renderApi
:
GraphicsApi
...
...
@@ -31,6 +32,8 @@ actual open class SkiaLayer {
}
actual
var
skikoView
:
SkikoView
?
=
null
actual
val
pixelGeometry
:
PixelGeometry
get
()
=
TODO
(
"Not yet implemented"
)
}
// TODO: do properly
...
...
skiko/src/macosMain/kotlin/org/jetbrains/skiko/SkiaLayer.macos.kt
View file @
2ed9168d
...
...
@@ -281,6 +281,9 @@ actual open class SkiaLayer {
canvas
.
drawPicture
(
it
.
instance
)
}
}
actual
val
pixelGeometry
:
PixelGeometry
get
()
=
PixelGeometry
.
UNKNOWN
}
// TODO: do properly
...
...
skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.macos.kt
View file @
2ed9168d
package
org.jetbrains.skiko.context
import
kotlinx.cinterop.useContents
import
org.jetbrains.skia.ColorSpace
import
org.jetbrains.skia.Surface
import
org.jetbrains.skia.SurfaceColorFormat
import
org.jetbrains.skia.SurfaceOrigin
import
org.jetbrains.skia.*
import
org.jetbrains.skiko.RenderException
import
org.jetbrains.skiko.SkiaLayer
import
org.jetbrains.skiko.redrawer.MacOsMetalRedrawer
...
...
@@ -43,7 +40,8 @@ internal class MacOsMetalContextHandler(layer: SkiaLayer) : ContextHandler(layer
renderTarget
!!
,
SurfaceOrigin
.
TOP_LEFT
,
SurfaceColorFormat
.
BGRA_8888
,
ColorSpace
.
sRGB
ColorSpace
.
sRGB
,
SurfaceProps
(
pixelGeometry
=
layer
.
pixelGeometry
)
)
?:
throw
RenderException
(
"Cannot create surface"
)
canvas
=
surface
!!
.
canvas
...
...
skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.macos.kt
View file @
2ed9168d
...
...
@@ -68,7 +68,8 @@ internal class MacOSOpenGLContextHandler(layer: SkiaLayer) : ContextHandler(laye
renderTarget
!!
,
SurfaceOrigin
.
BOTTOM_LEFT
,
SurfaceColorFormat
.
RGBA_8888
,
ColorSpace
.
sRGB
ColorSpace
.
sRGB
,
SurfaceProps
(
pixelGeometry
=
layer
.
pixelGeometry
)
)
?:
throw
RenderException
(
"Cannot create surface"
)
canvas
=
surface
?.
canvas
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment