Title: [94502] trunk/Source/WebCore
Revision
94502
Author
[email protected]
Date
2011-09-04 10:51:35 -0700 (Sun, 04 Sep 2011)

Log Message

[wx] Unreviewed build fix. Add new / moved files missing from last commit.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (94501 => 94502)


--- trunk/Source/WebCore/ChangeLog	2011-09-04 16:49:10 UTC (rev 94501)
+++ trunk/Source/WebCore/ChangeLog	2011-09-04 17:51:35 UTC (rev 94502)
@@ -1,3 +1,26 @@
+2011-09-04  Kevin Ollivier  <[email protected]>
+
+        [wx] Unreviewed build fix. Add new / moved files missing from last commit.
+
+        * platform/wx/LocalDC.h: Added.
+        (WebCore::LocalDC::LocalDC):
+        (WebCore::LocalDC::context):
+        (WebCore::LocalDC::~LocalDC):
+        * platform/wx/wxcode/cairo: Added.
+        * platform/wx/wxcode/cairo/non-kerned-drawing.cpp: Added.
+        (WebCore::pangoFontMap):
+        (WebCore::createPangoFontForFont):
+        (WebCore::createScaledFontForFont):
+        (WebCore::pango_font_get_glyph):
+        (WebCore::drawTextWithSpacing):
+        * platform/wx/wxcode/gdiplus: Added.
+        * platform/wx/wxcode/gdiplus/non-kerned-drawing.cpp: Added.
+        (dmin):
+        (dmax):
+        (DegToRad):
+        (RadToDeg):
+        (WebCore::drawTextWithSpacing):
+
 2011-09-04  Robin Dunn  <[email protected]>
 
         [wx] Enable wxWebKit to run using the wxGC Cairo backend on platforms other than GTK.

Added: trunk/Source/WebCore/platform/wx/LocalDC.h (0 => 94502)


--- trunk/Source/WebCore/platform/wx/LocalDC.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/wx/LocalDC.h	2011-09-04 17:51:35 UTC (rev 94502)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2011 Kevin Ollivier <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "IntRect.h"
+
+#include <wtf/Assertions.h>
+
+#include <wx/defs.h>
+
+#include <wx/dc.h>
+#include <wx/dcmemory.h>
+#include <wx/rawbmp.h>
+
+namespace WebCore {
+
+wxBitmap* transparentBitmap(int width, int height);
+
+class LocalDC {
+
+public:
+    LocalDC(wxDC* host, const IntRect& r)
+    {
+#ifndef __WXMAC__
+        m_host = host;
+        int width = r.width();
+        int height = r.height();
+        m_bitmap = new wxBitmap(width, height, 32);
+        wxAlphaPixelData pixData(*m_bitmap, wxPoint(0,0), wxSize(width, height));
+        ASSERT(pixData);
+        if (pixData) {
+            wxAlphaPixelData::Iterator p(pixData);
+            for (int y=0; y<height; y++) {
+                wxAlphaPixelData::Iterator rowStart = p;
+                for (int x=0; x<width; x++) {
+                    p.Alpha() = 0;
+                    ++p; 
+                }
+                p = rowStart;
+                p.OffsetY(pixData, 1);
+            }
+        }
+
+        m_context = new wxMemoryDC(*m_bitmap);
+        m_context->SetDeviceOrigin(-r.x(), -r.y());
+        m_rect = r;
+#else
+        m_context = host;
+#endif
+    }
+
+    wxDC* context() { return m_context; }
+
+    ~LocalDC()
+    {
+#ifndef __WXMAC__
+        delete m_context;
+        m_host->DrawBitmap(*m_bitmap, m_rect.x(), m_rect.y());
+        delete m_bitmap;
+#endif
+    }
+
+private:
+    wxDC* m_host;
+    wxDC* m_context;
+    wxBitmap* m_bitmap;
+    IntRect m_rect;
+            
+};
+
+}
+

Added: trunk/Source/WebCore/platform/wx/wxcode/cairo/non-kerned-drawing.cpp (0 => 94502)


--- trunk/Source/WebCore/platform/wx/wxcode/cairo/non-kerned-drawing.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/wx/wxcode/cairo/non-kerned-drawing.cpp	2011-09-04 17:51:35 UTC (rev 94502)
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2007 Kevin Watters, Kevin Ollivier.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "SimpleFontData.h"
+
+#include <wx/dc.h>
+#include <wx/dcgraph.h>
+#include <wx/defs.h>
+#include <wx/dcclient.h>
+#include <wx/gdicmn.h>
+#include <vector>
+
+#if USE(WXGC)
+#include <cairo.h>
+#if __WXMSW__
+#include <cairo-win32.h>
+#endif
+#include <assert.h>
+
+#if wxUSE_PANGO
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+// Use cairo-ft if a recent enough Pango version isn't available
+#if !PANGO_VERSION_CHECK(1,18,0)
+#include <cairo-ft.h>
+#include <pango/pangofc-fontmap.h>
+#endif
+#endif
+
+#endif // USE(WXGC)
+
+#if __WXGTK__
+#include <gtk/gtk.h>
+#endif
+
+namespace WebCore {
+
+#if wxUSE_PANGO
+static PangoFontMap* g_fontMap;
+
+PangoFontMap* pangoFontMap()
+{
+    if (!g_fontMap)
+        g_fontMap = pango_cairo_font_map_get_default();
+
+    return g_fontMap;
+}
+
+PangoFont* createPangoFontForFont(const wxFont* wxfont)
+{
+    ASSERT(wxfont && wxfont->Ok());
+
+    const char* face = wxfont->GetFaceName().mb_str(wxConvUTF8);
+    char const* families[] = {
+        face,
+        0
+    };
+
+    switch (wxfont->GetFamily()) {
+    case wxFONTFAMILY_ROMAN:
+        families[1] = "serif";
+        break;
+    case wxFONTFAMILY_SWISS:
+        families[1] = "sans";
+        break;
+    case wxFONTFAMILY_MODERN:
+        families[1] = "monospace";
+        break;
+    default:
+        families[1] = "sans";
+    }
+    
+    PangoFontDescription* description = pango_font_description_new();
+    pango_font_description_set_absolute_size(description, wxfont->GetPointSize() * PANGO_SCALE);
+ 
+    PangoFont* pangoFont = 0;
+    PangoContext* pangoContext = 0;
+
+    switch (wxfont->GetWeight()) {
+    case wxFONTWEIGHT_LIGHT:
+        pango_font_description_set_weight(description, PANGO_WEIGHT_LIGHT);
+        break;
+    case wxFONTWEIGHT_NORMAL:
+        pango_font_description_set_weight(description, PANGO_WEIGHT_NORMAL);
+        break;
+    case wxFONTWEIGHT_BOLD:
+        pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
+        break;
+    }
+
+    switch (wxfont->GetStyle()) {
+    case wxFONTSTYLE_NORMAL:
+        pango_font_description_set_style(description, PANGO_STYLE_NORMAL);
+        break;
+    case wxFONTSTYLE_ITALIC:
+        pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
+        break;
+    case wxFONTSTYLE_SLANT:
+        pango_font_description_set_style(description, PANGO_STYLE_OBLIQUE);
+        break;
+    }
+
+    PangoFontMap* fontMap = pangoFontMap();
+
+    pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap));
+    for (unsigned i = 0; !pangoFont && i < G_N_ELEMENTS(families); i++) {
+        pango_font_description_set_family(description, families[i]);
+        pango_context_set_font_description(pangoContext, description);
+        pangoFont = pango_font_map_load_font(fontMap, pangoContext, description);
+    }
+    pango_font_description_free(description);
+
+    return pangoFont;
+}
+
+cairo_scaled_font_t* createScaledFontForFont(const wxFont* wxfont)
+{
+    ASSERT(wxfont && wxfont->Ok());
+
+    cairo_scaled_font_t* scaledFont = NULL;
+    PangoFont* pangoFont = createPangoFontForFont(wxfont);
+    
+#if PANGO_VERSION_CHECK(1,18,0)
+    if (pangoFont)
+        scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(pangoFont)));
+#endif
+
+    return scaledFont;
+}
+
+PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc)
+{
+    PangoGlyph result = 0;
+    gchar buffer[7];
+
+    gint  length = g_unichar_to_utf8(wc, buffer);
+    g_return_val_if_fail(length, 0);
+
+    GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL);
+
+    if (g_list_length(items) == 1) {
+        PangoItem* item = static_cast<PangoItem*>(items->data);
+        PangoFont* tmpFont = item->analysis.font;
+        item->analysis.font = font;
+
+        PangoGlyphString* glyphs = pango_glyph_string_new();
+        pango_shape(buffer, length, &item->analysis, glyphs);
+
+        item->analysis.font = tmpFont;
+
+        if (glyphs->num_glyphs == 1)
+            result = glyphs->glyphs[0].glyph;
+        else
+            g_warning("didn't get 1 glyph but %d", glyphs->num_glyphs);
+
+        pango_glyph_string_free(glyphs);
+    }
+
+    g_list_foreach(items, (GFunc)pango_item_free, NULL);
+    g_list_free(items);
+
+    return result;
+}
+#endif // wxUSE_PANGO
+
+
+void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
+{
+#if USE(WXGC)
+    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
+    wxGraphicsContext* gc = dc->GetGraphicsContext();
+    gc->PushState();
+    cairo_t* cr = (cairo_t*)gc->GetNativeContext();
+
+    wxFont* wxfont = font->getWxFont();
+    cairo_scaled_font_t* scaled_font = 0;
+#if wxUSE_PANGO
+    PangoFont* pangoFont = createPangoFontForFont(wxfont);
+    PangoFontMap* fontMap = pangoFontMap();
+    PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap));
+    scaled_font = createScaledFontForFont(wxfont); 
+#elif __WXMSW__
+    cairo_matrix_t sizeMatrix, ctm;
+    cairo_matrix_init_identity(&ctm);
+    int size = font->platformData().size();
+    cairo_matrix_init_scale(&sizeMatrix, size, size);
+
+    cairo_font_options_t* fontOptions = cairo_font_options_create();
+    cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
+    
+    cairo_font_face_t* win_face = cairo_win32_font_face_create_for_hfont((HFONT)wxfont->GetHFONT());
+    scaled_font = cairo_scaled_font_create(win_face, &sizeMatrix, &ctm, fontOptions); 
+#endif
+    ASSERT(scaled_font);
+
+    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
+    float offset = point.x();
+
+    for (int i = 0; i < numGlyphs; i++) {
+#if wxUSE_PANGO
+        glyphs[i].index = pango_font_get_glyph(pangoFont, pangoContext, glyphBuffer.glyphAt(from + i));
+#endif
+        glyphs[i].x = offset;
+        glyphs[i].y = point.y();
+        offset += glyphBuffer.advanceAt(from + i);
+    }
+
+    cairo_set_source_rgba(cr, color.Red()/255.0, color.Green()/255.0, color.Blue()/255.0, color.Alpha()/255.0);
+    cairo_set_scaled_font(cr, scaled_font);
+    
+    cairo_show_glyphs(cr, glyphs, numGlyphs);
+
+    cairo_scaled_font_destroy(scaled_font);
+    gc->PopState();
+#else
+    wxDC* dc = graphicsContext->platformContext();
+
+    wxFont* wxfont = font->getWxFont();
+    if (wxfont && wxfont->IsOk())
+        dc->SetFont(*wxfont);
+    dc->SetTextForeground(color);
+
+    // convert glyphs to wxString
+    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
+    int offset = point.x();
+    wxString text = wxEmptyString;
+    for (unsigned i = 0; i < numGlyphs; i++) {
+        text = text.Append((wxChar)glyphs[i]);
+        offset += glyphBuffer.advanceAt(from + i);
+    }
+    
+    // the y point is actually the bottom point of the text, turn it into the top
+    float height = font->ascent() - font->descent();
+    wxCoord ypoint = (wxCoord) (point.y() - height);
+     
+    dc->DrawText(text, (wxCoord)point.x(), ypoint);
+#endif
+}
+
+}

Added: trunk/Source/WebCore/platform/wx/wxcode/gdiplus/non-kerned-drawing.cpp (0 => 94502)


--- trunk/Source/WebCore/platform/wx/wxcode/gdiplus/non-kerned-drawing.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/wx/wxcode/gdiplus/non-kerned-drawing.cpp	2011-09-04 17:51:35 UTC (rev 94502)
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2007 Kevin Watters, Kevin Ollivier.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "AffineTransform.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "SimpleFontData.h"
+
+#include <wx/defs.h>
+
+#if 1 // !wxUSE_CAIRO
+
+#include <wx/dcclient.h>
+#include <wx/dcgraph.h>
+#include <wx/gdicmn.h>
+#include <vector>
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+// constants
+//-----------------------------------------------------------------------------
+
+const double RAD2DEG = 180.0 / M_PI;
+
+//-----------------------------------------------------------------------------
+// Local functions
+//-----------------------------------------------------------------------------
+
+static inline double dmin(double a, double b) { return a < b ? a : b; }
+static inline double dmax(double a, double b) { return a > b ? a : b; }
+
+static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
+static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
+
+#include "wx/msw/private.h"
+
+// TODO remove this dependency (gdiplus needs the macros)
+
+#ifndef max
+#define max(a,b)            (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b)            (((a) < (b)) ? (a) : (b))
+#endif
+
+#include "gdiplus.h"
+ 
+#if wxUSE_CAIRO
+#include <cairo.h>
+#include <cairo-win32.h>
+#endif
+
+namespace WebCore {
+
+void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
+{
+
+
+#if USE(WXGC)
+    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
+#else
+    wxDC* dc = graphicsContext->platformContext();
+#endif
+
+    // get the native HDC handle to draw using native APIs
+    HDC hdc = 0;
+    float y = point.y() - font->fontMetrics().ascent();
+    float x = point.x();
+
+
+#if USE(WXGC)
+
+    wxGraphicsContext* gc = dc->GetGraphicsContext();
+#if wxUSE_CAIRO
+    cairo_t* context = (cairo_t*)gc->GetNativeContext();
+    if (context) {
+        cairo_surface_t* surface = cairo_get_target(context);
+        hdc = cairo_win32_surface_get_dc(surface);
+    }
+#else
+    // when going from GdiPlus -> Gdi, any GdiPlus transformations are lost
+    // so we need to alter the coordinates to reflect their transformed point.
+    double xtrans = 0;
+    double ytrans = 0;
+    
+    gc->GetTransform().TransformPoint(&xtrans, &ytrans);
+    Gdiplus::Graphics* g;
+    if (gc) {
+        g = (Gdiplus::Graphics*)gc->GetNativeContext();
+        hdc = g->GetHDC();
+    }
+    x += (int)xtrans;
+    y += (int)ytrans;
+#endif // wxUSE_CAIRO
+#else
+    hdc = static_cast<HDC>(dc->GetHDC());
+#endif
+
+    // if the context has been scaled, we must manually re-apply that scale
+    // to the HDC.
+    FloatSize scale = graphicsContext->currentScale();
+    if (scale != FloatSize(1.0, 1.0)) {
+        SetGraphicsMode(hdc, GM_ADVANCED);
+        XFORM xForm;
+        xForm.eM11 = scale.width();
+        xForm.eM12 = 0.0;
+        xForm.eM21 = 0.0;
+        xForm.eM22 = scale.height();
+        xForm.eDx = 0.0;
+        xForm.eDy = 0.0;
+        SetWorldTransform(hdc, &xForm);
+    }
+    // ExtTextOut wants the offsets as an array of ints, so extract them
+    // from the glyph buffer
+    const GlyphBufferGlyph*   glyphs   = glyphBuffer.glyphs(from);
+    const GlyphBufferAdvance* advances = glyphBuffer.advances(from);
+
+    int* spacing = new int[numGlyphs - from];
+    for (unsigned i = 0; i < numGlyphs; ++i)
+        spacing[i] = advances[i].width();
+
+    wxFont* wxfont = font->getWxFont();
+    if (wxfont && wxfont->IsOk())
+        ::SelectObject(hdc, GetHfontOf(*wxfont));
+
+    if (color.Ok())
+        ::SetTextColor(hdc, color.GetPixel());
+
+    // do not draw background behind characters
+    ::SetBkMode(hdc, TRANSPARENT);
+
+    // draw text with optional character widths array
+    wxString string = wxString((wxChar*)(&glyphs[from]), numGlyphs);
+    ::ExtTextOut(hdc, x, y,  ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphs), numGlyphs, spacing);
+
+    ::SetBkMode(hdc, TRANSPARENT);
+
+    #if USE(WXGC) && !wxUSE_CAIRO
+        g->ReleaseHDC(hdc);
+    #endif
+
+    delete [] spacing;
+}
+
+}
+#endif
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to