зеркало из https://github.com/mozilla/gecko-dev.git
Completely collapse GeckoGLLayerClient into GeckoLayerClient.
This commit is contained in:
Родитель
0ae451b288
Коммит
0741d7041c
|
@ -42,7 +42,6 @@ package org.mozilla.gecko;
|
|||
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.gfx.FloatSize;
|
||||
import org.mozilla.gecko.gfx.GeckoGLLayerClient;
|
||||
import org.mozilla.gecko.gfx.GeckoLayerClient;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.Layer;
|
||||
|
@ -1781,14 +1780,11 @@ abstract public class GeckoApp
|
|||
|
||||
if (mLayerController == null) {
|
||||
/*
|
||||
* Create a layer client so that Gecko will have a buffer to draw into, but don't hook
|
||||
* it up to the layer controller yet.
|
||||
*
|
||||
* TODO: Switch between software and GL appropriately.
|
||||
* Create a layer client, but don't hook it up to the layer controller yet.
|
||||
*/
|
||||
Log.e(LOGTAG, "### Creating GeckoGLLayerClient");
|
||||
mLayerClient = new GeckoGLLayerClient(this);
|
||||
Log.e(LOGTAG, "### Done creating GeckoGLLayerClient");
|
||||
Log.e(LOGTAG, "### Creating GeckoLayerClient");
|
||||
mLayerClient = new GeckoLayerClient(this);
|
||||
Log.e(LOGTAG, "### Done creating GeckoLayerClient");
|
||||
|
||||
/*
|
||||
* Hook a placeholder layer client up to the layer controller so that the user can pan
|
||||
|
|
|
@ -110,7 +110,6 @@ FENNEC_JAVA_FILES = \
|
|||
gfx/CheckerboardImage.java \
|
||||
gfx/FlexibleGLSurfaceView.java \
|
||||
gfx/FloatSize.java \
|
||||
gfx/GeckoGLLayerClient.java \
|
||||
gfx/GeckoLayerClient.java \
|
||||
gfx/GLController.java \
|
||||
gfx/GLThread.java \
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
public class GeckoGLLayerClient extends GeckoLayerClient {
|
||||
private static final String LOGTAG = "GeckoGLLayerClient";
|
||||
|
||||
private boolean mLayerRendererInitialized;
|
||||
|
||||
public GeckoGLLayerClient(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public ViewTransform getViewTransform() {
|
||||
Log.e(LOGTAG, "### getViewTransform()");
|
||||
|
||||
// NB: We don't begin a transaction here because this can be called in a synchronous
|
||||
// manner between beginDrawing() and endDrawing(), and that will cause a deadlock.
|
||||
|
||||
synchronized (mLayerController) {
|
||||
ViewportMetrics viewportMetrics = mLayerController.getViewportMetrics();
|
||||
PointF viewportOrigin = viewportMetrics.getOrigin();
|
||||
Point tileOrigin = mTileLayer.getOrigin();
|
||||
float scrollX = viewportOrigin.x;
|
||||
float scrollY = viewportOrigin.y;
|
||||
float zoomFactor = viewportMetrics.getZoomFactor();
|
||||
Log.e(LOGTAG, "### Viewport metrics = " + viewportMetrics + " tile reso = " +
|
||||
mTileLayer.getResolution());
|
||||
return new ViewTransform(scrollX, scrollY, zoomFactor);
|
||||
}
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public LayerRenderer.Frame createFrame() {
|
||||
// Create the shaders and textures if necessary.
|
||||
if (!mLayerRendererInitialized) {
|
||||
mLayerRenderer.createProgram();
|
||||
mLayerRendererInitialized = true;
|
||||
}
|
||||
|
||||
// Build the contexts and create the frame.
|
||||
Layer.RenderContext pageContext = mLayerRenderer.createPageContext();
|
||||
Layer.RenderContext screenContext = mLayerRenderer.createScreenContext();
|
||||
return mLayerRenderer.createFrame(pageContext, screenContext);
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public void activateProgram() {
|
||||
mLayerRenderer.activateProgram();
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public void deactivateProgram() {
|
||||
mLayerRenderer.deactivateProgram();
|
||||
}
|
||||
}
|
||||
|
|
@ -59,13 +59,14 @@ import android.view.View;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class GeckoLayerClient implements GeckoEventListener,
|
||||
FlexibleGLSurfaceView.Listener,
|
||||
VirtualLayer.Listener {
|
||||
public class GeckoLayerClient implements GeckoEventListener,
|
||||
FlexibleGLSurfaceView.Listener,
|
||||
VirtualLayer.Listener {
|
||||
private static final String LOGTAG = "GeckoLayerClient";
|
||||
|
||||
protected LayerController mLayerController;
|
||||
protected LayerRenderer mLayerRenderer;
|
||||
private LayerRenderer mLayerRenderer;
|
||||
private boolean mLayerRendererInitialized;
|
||||
|
||||
protected IntSize mScreenSize;
|
||||
protected IntSize mWindowSize;
|
||||
|
@ -436,6 +437,49 @@ public abstract class GeckoLayerClient implements GeckoEventListener,
|
|||
sendResizeEventIfNecessary(false);
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public ViewTransform getViewTransform() {
|
||||
Log.e(LOGTAG, "### getViewTransform()");
|
||||
|
||||
// NB: We don't begin a transaction here because this can be called in a synchronous
|
||||
// manner between beginDrawing() and endDrawing(), and that will cause a deadlock.
|
||||
|
||||
synchronized (mLayerController) {
|
||||
ViewportMetrics viewportMetrics = mLayerController.getViewportMetrics();
|
||||
PointF viewportOrigin = viewportMetrics.getOrigin();
|
||||
Point tileOrigin = mTileLayer.getOrigin();
|
||||
float scrollX = viewportOrigin.x;
|
||||
float scrollY = viewportOrigin.y;
|
||||
float zoomFactor = viewportMetrics.getZoomFactor();
|
||||
Log.e(LOGTAG, "### Viewport metrics = " + viewportMetrics + " tile reso = " +
|
||||
mTileLayer.getResolution());
|
||||
return new ViewTransform(scrollX, scrollY, zoomFactor);
|
||||
}
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public LayerRenderer.Frame createFrame() {
|
||||
// Create the shaders and textures if necessary.
|
||||
if (!mLayerRendererInitialized) {
|
||||
mLayerRenderer.createProgram();
|
||||
mLayerRendererInitialized = true;
|
||||
}
|
||||
|
||||
// Build the contexts and create the frame.
|
||||
Layer.RenderContext pageContext = mLayerRenderer.createPageContext();
|
||||
Layer.RenderContext screenContext = mLayerRenderer.createScreenContext();
|
||||
return mLayerRenderer.createFrame(pageContext, screenContext);
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public void activateProgram() {
|
||||
mLayerRenderer.activateProgram();
|
||||
}
|
||||
|
||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature. */
|
||||
public void deactivateProgram() {
|
||||
mLayerRenderer.deactivateProgram();
|
||||
}
|
||||
/** Implementation of FlexibleGLSurfaceView.Listener */
|
||||
public void renderRequested() {
|
||||
Log.e(LOGTAG, "### Render requested, scheduling composite");
|
||||
|
|
|
@ -990,7 +990,7 @@ AndroidBridge::SetSurfaceView(jobject obj)
|
|||
void
|
||||
AndroidBridge::SetLayerClient(jobject obj)
|
||||
{
|
||||
AndroidGeckoGLLayerClient *client = new AndroidGeckoGLLayerClient();
|
||||
AndroidGeckoLayerClient *client = new AndroidGeckoLayerClient();
|
||||
client->Init(obj);
|
||||
mLayerClient = client;
|
||||
}
|
||||
|
|
|
@ -113,12 +113,10 @@ jmethodID AndroidAddress::jGetThoroughfareMethod;
|
|||
jclass AndroidGeckoLayerClient::jGeckoLayerClientClass = 0;
|
||||
jmethodID AndroidGeckoLayerClient::jBeginDrawingMethod = 0;
|
||||
jmethodID AndroidGeckoLayerClient::jEndDrawingMethod = 0;
|
||||
|
||||
jclass AndroidGeckoGLLayerClient::jGeckoGLLayerClientClass = 0;
|
||||
jmethodID AndroidGeckoGLLayerClient::jGetViewTransformMethod = 0;
|
||||
jmethodID AndroidGeckoGLLayerClient::jCreateFrameMethod = 0;
|
||||
jmethodID AndroidGeckoGLLayerClient::jActivateProgramMethod = 0;
|
||||
jmethodID AndroidGeckoGLLayerClient::jDeactivateProgramMethod = 0;
|
||||
jmethodID AndroidGeckoLayerClient::jGetViewTransformMethod = 0;
|
||||
jmethodID AndroidGeckoLayerClient::jCreateFrameMethod = 0;
|
||||
jmethodID AndroidGeckoLayerClient::jActivateProgramMethod = 0;
|
||||
jmethodID AndroidGeckoLayerClient::jDeactivateProgramMethod = 0;
|
||||
|
||||
jclass AndroidLayerRendererFrame::jLayerRendererFrameClass = 0;
|
||||
jmethodID AndroidLayerRendererFrame::jBeginDrawingMethod = 0;
|
||||
|
@ -162,7 +160,6 @@ mozilla::InitAndroidJavaWrappers(JNIEnv *jEnv)
|
|||
AndroidAddress::InitAddressClass(jEnv);
|
||||
AndroidRect::InitRectClass(jEnv);
|
||||
AndroidGeckoLayerClient::InitGeckoLayerClientClass(jEnv);
|
||||
AndroidGeckoGLLayerClient::InitGeckoGLLayerClientClass(jEnv);
|
||||
AndroidLayerRendererFrame::InitLayerRendererFrameClass(jEnv);
|
||||
AndroidViewTransform::InitViewTransformClass(jEnv);
|
||||
AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(jEnv);
|
||||
|
@ -352,17 +349,6 @@ AndroidGeckoLayerClient::InitGeckoLayerClientClass(JNIEnv *jEnv)
|
|||
|
||||
jBeginDrawingMethod = getMethod("beginDrawing", "(IIIILjava/lang/String;Z)Landroid/graphics/Rect;");
|
||||
jEndDrawingMethod = getMethod("endDrawing", "(IIII)V");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClient::InitGeckoGLLayerClientClass(JNIEnv *jEnv)
|
||||
{
|
||||
#ifdef MOZ_JAVA_COMPOSITOR
|
||||
initInit();
|
||||
|
||||
jGeckoGLLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoGLLayerClient");
|
||||
|
||||
jGetViewTransformMethod = getMethod("getViewTransform",
|
||||
"()Lorg/mozilla/gecko/gfx/ViewTransform;");
|
||||
jCreateFrameMethod = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
|
||||
|
@ -690,7 +676,7 @@ AndroidGeckoEvent::DoCallback(const nsAString& data) {
|
|||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClient::Init(jobject jobj)
|
||||
AndroidGeckoLayerClient::Init(jobject jobj)
|
||||
{
|
||||
NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
|
||||
wrapped_obj = jobj;
|
||||
|
@ -854,7 +840,7 @@ AndroidGeckoSurfaceView::GetSurfaceHolder()
|
|||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClient::GetViewTransform(AndroidViewTransform& aViewTransform)
|
||||
AndroidGeckoLayerClient::GetViewTransform(AndroidViewTransform& aViewTransform)
|
||||
{
|
||||
JNIEnv *env = GetJNIForThread();
|
||||
NS_ABORT_IF_FALSE(env, "No JNI environment at GetViewTransform()!");
|
||||
|
@ -868,7 +854,7 @@ AndroidGeckoGLLayerClient::GetViewTransform(AndroidViewTransform& aViewTransform
|
|||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClient::CreateFrame(AndroidLayerRendererFrame& aFrame)
|
||||
AndroidGeckoLayerClient::CreateFrame(AndroidLayerRendererFrame& aFrame)
|
||||
{
|
||||
JNIEnv *env = GetJNIForThread();
|
||||
NS_ABORT_IF_FALSE(env, "No JNI environment at CreateFrame()!");
|
||||
|
@ -882,7 +868,7 @@ AndroidGeckoGLLayerClient::CreateFrame(AndroidLayerRendererFrame& aFrame)
|
|||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClient::ActivateProgram()
|
||||
AndroidGeckoLayerClient::ActivateProgram()
|
||||
{
|
||||
JNIEnv *env = GetJNIForThread();
|
||||
NS_ABORT_IF_FALSE(env, "No JNI environment at ActivateProgram()!");
|
||||
|
@ -894,7 +880,7 @@ AndroidGeckoGLLayerClient::ActivateProgram()
|
|||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClient::DeactivateProgram()
|
||||
AndroidGeckoLayerClient::DeactivateProgram()
|
||||
{
|
||||
JNIEnv *env = GetJNIForThread();
|
||||
NS_ABORT_IF_FALSE(env, "No JNI environment at DeactivateProgram()!");
|
||||
|
@ -981,7 +967,7 @@ AndroidViewTransform::GetScale()
|
|||
}
|
||||
|
||||
void
|
||||
AndroidGeckoGLLayerClientViewTransformGetter::operator()(nsIntPoint& aScrollOffset, float& aScaleX,
|
||||
AndroidGeckoLayerClientViewTransformGetter::operator()(nsIntPoint& aScrollOffset, float& aScaleX,
|
||||
float& aScaleY)
|
||||
{
|
||||
AndroidViewTransform viewTransform;
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class AndroidGeckoGLLayerClient;
|
||||
class AndroidGeckoLayerClient;
|
||||
|
||||
void InitAndroidJavaWrappers(JNIEnv *jEnv);
|
||||
|
||||
|
@ -153,26 +153,6 @@ protected:
|
|||
static jfieldID jTopField;
|
||||
};
|
||||
|
||||
class AndroidGeckoLayerClient : public WrappedJavaObject {
|
||||
public:
|
||||
static void InitGeckoLayerClientClass(JNIEnv *jEnv);
|
||||
|
||||
void Init(jobject jobj);
|
||||
|
||||
bool BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight,
|
||||
nsIntRect &aDirtyRect, const nsAString &aMetadata, bool aHasDirectTexture);
|
||||
void EndDrawing(const nsIntRect &aRect);
|
||||
|
||||
protected:
|
||||
AndroidGeckoLayerClient() {
|
||||
// You shouldn't directly instantiate one of these; instead use one of the concrete derived
|
||||
// classes.
|
||||
}
|
||||
|
||||
static jclass jGeckoLayerClientClass;
|
||||
static jmethodID jBeginDrawingMethod;
|
||||
static jmethodID jEndDrawingMethod;
|
||||
};
|
||||
|
||||
/** A callback that retrieves the view transform. */
|
||||
class AndroidViewTransformGetter
|
||||
|
@ -181,15 +161,15 @@ public:
|
|||
virtual void operator()(nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY) = 0;
|
||||
};
|
||||
|
||||
class AndroidGeckoGLLayerClientViewTransformGetter : public AndroidViewTransformGetter {
|
||||
class AndroidGeckoLayerClientViewTransformGetter : public AndroidViewTransformGetter {
|
||||
public:
|
||||
AndroidGeckoGLLayerClientViewTransformGetter(AndroidGeckoGLLayerClient& aLayerClient)
|
||||
AndroidGeckoLayerClientViewTransformGetter(AndroidGeckoLayerClient& aLayerClient)
|
||||
: mLayerClient(aLayerClient) {}
|
||||
|
||||
virtual void operator()(nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY);
|
||||
|
||||
private:
|
||||
AndroidGeckoGLLayerClient& mLayerClient;
|
||||
AndroidGeckoLayerClient& mLayerClient;
|
||||
};
|
||||
|
||||
class AndroidViewTransform : public WrappedJavaObject {
|
||||
|
@ -232,31 +212,36 @@ private:
|
|||
static jmethodID jEndDrawingMethod;
|
||||
};
|
||||
|
||||
class AndroidGeckoGLLayerClient : public AndroidGeckoLayerClient {
|
||||
class AndroidGeckoLayerClient : public WrappedJavaObject {
|
||||
public:
|
||||
static void InitGeckoGLLayerClientClass(JNIEnv *jEnv);
|
||||
static void InitGeckoLayerClientClass(JNIEnv *jEnv);
|
||||
|
||||
void Init(jobject jobj);
|
||||
|
||||
AndroidGeckoGLLayerClient()
|
||||
AndroidGeckoLayerClient()
|
||||
: mViewTransformGetter(*this) {}
|
||||
|
||||
AndroidGeckoGLLayerClient(jobject jobj)
|
||||
AndroidGeckoLayerClient(jobject jobj)
|
||||
: mViewTransformGetter(*this) { Init(jobj); }
|
||||
|
||||
bool BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight,
|
||||
nsIntRect &aDirtyRect, const nsAString &aMetadata, bool aHasDirectTexture);
|
||||
void EndDrawing(const nsIntRect &aRect);
|
||||
void GetViewTransform(AndroidViewTransform& aViewTransform);
|
||||
void CreateFrame(AndroidLayerRendererFrame& aFrame);
|
||||
void ActivateProgram();
|
||||
void DeactivateProgram();
|
||||
|
||||
private:
|
||||
static jclass jGeckoGLLayerClientClass;
|
||||
protected:
|
||||
static jclass jGeckoLayerClientClass;
|
||||
static jmethodID jBeginDrawingMethod;
|
||||
static jmethodID jEndDrawingMethod;
|
||||
static jmethodID jGetViewTransformMethod;
|
||||
static jmethodID jCreateFrameMethod;
|
||||
static jmethodID jActivateProgramMethod;
|
||||
static jmethodID jDeactivateProgramMethod;
|
||||
|
||||
AndroidGeckoGLLayerClientViewTransformGetter mViewTransformGetter;
|
||||
AndroidGeckoLayerClientViewTransformGetter mViewTransformGetter;
|
||||
};
|
||||
|
||||
class AndroidGeckoSurfaceView : public WrappedJavaObject
|
||||
|
|
|
@ -2390,13 +2390,12 @@ nsWindow::DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) {
|
|||
AndroidBridge::AutoLocalJNIFrame jniFrame(GetJNIForThread());
|
||||
|
||||
AndroidGeckoLayerClient& client = AndroidBridge::Bridge()->GetLayerClient();
|
||||
AndroidGeckoGLLayerClient& glClient = static_cast<AndroidGeckoGLLayerClient&>(client);
|
||||
glClient.CreateFrame(mLayerRendererFrame);
|
||||
client.CreateFrame(mLayerRendererFrame);
|
||||
|
||||
glClient.ActivateProgram();
|
||||
client.ActivateProgram();
|
||||
mLayerRendererFrame.BeginDrawing();
|
||||
mLayerRendererFrame.DrawBackground();
|
||||
glClient.DeactivateProgram();
|
||||
client.DeactivateProgram();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2406,12 +2405,11 @@ nsWindow::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) {
|
|||
"Frame should have been created in DrawWindowUnderlay()!");
|
||||
|
||||
AndroidGeckoLayerClient& client = AndroidBridge::Bridge()->GetLayerClient();
|
||||
AndroidGeckoGLLayerClient& glClient = static_cast<AndroidGeckoGLLayerClient&>(client);
|
||||
|
||||
glClient.ActivateProgram();
|
||||
client.ActivateProgram();
|
||||
mLayerRendererFrame.DrawForeground();
|
||||
mLayerRendererFrame.EndDrawing();
|
||||
glClient.DeactivateProgram();
|
||||
client.DeactivateProgram();
|
||||
|
||||
mLayerRendererFrame.Dispose();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче