[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

rniwa at webkit.org rniwa at webkit.org
Wed Dec 22 16:23:48 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit e578ecd0a814d33364779b7371e9e0e000ccf788
Author: rniwa at webkit.org <rniwa at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Nov 23 00:25:10 2010 +0000

    2010-11-22  Ryosuke Niwa  <rniwa at webkit.org>
    
            Reviewed by Tony Chang.
    
            SelectionController::typingStyle() should return EditingStyle*
            https://bugs.webkit.org/show_bug.cgi?id=49813
    
            Changed the return value of SelectionController::typingStyle() to EditingStyle*.
            Also added SelectionController::copyTypingStyle() to copy the typing style
            as an instance of CSSMutableStyleDeclaration.
    
            No tests are added since this is no behavioral change.
    
            * WebView/WebFrame.mm:
            (-[WebFrame _typingStyle]): Calls SelectionController::copyTypingStyle()
    2010-11-22  Ryosuke Niwa  <rniwa at webkit.org>
    
            Reviewed by Tony Chang.
    
            SelectionController::typingStyle() should return EditingStyle*
            https://bugs.webkit.org/show_bug.cgi?id=49813
    
            Changed the return type of SelectionController::typingStyle to EditingStyle*.
    
            Extracted textDirection from Editor::textDirectionForSelection to hide the underlying
            CSSMutableStyleDeclaration.
    
            Also extracted the code to preserve unicode-bidi and direction CSS properties in
            InsertTextCommand::input, and moved into EditingStyle::prepareToApplyAt. ShouldPreserveWritingDirection,
            which is added to the argument list of EditingStyle::prepareToApplyAt, decides whether or not
            these two properties are preserved.
    
            Also added SelectionController::copyTypingStyle() to copy the typing style as an instance of
            CSSMutableStyleDeclaration.
    
            No new tests are added since this is a refactoring.
    
            * editing/EditingStyle.cpp:
            (WebCore::EditingStyle::textDirection): Extracted from Editor::textDirectionForSelection.
            (WebCore::EditingStyle::removeStyleConflictingWithStyleOfNode): Added a missing null check.
            (WebCore::EditingStyle::prepareToApplyAt): See above.
            (WebCore::editingStyleIncludingTypingStyle): Calls SelectionController::typingStyle.
            * editing/EditingStyle.h: Moved WritingDirection from Editor.h
            * editing/Editor.cpp:
            (WebCore::Editor::textDirectionForSelection): Calls EditingStyle::textDirection.
            (WebCore::Editor::computeAndSetTypingStyle): Calls SelectionController::typingStyle.
            (WebCore::Editor::selectionComputedStyle): Ditto.
            (WebCore::Editor::styleForSelectionStart): Ditto.
            * editing/Editor.h:
            * editing/InsertLineBreakCommand.cpp:
            (WebCore::InsertLineBreakCommand::doApply): Ditto.
            * editing/InsertTextCommand.cpp:
            (WebCore::InsertTextCommand::input): Calls EditingStyle::prepareToApplyAt with PreserveWritingDirection.
            * editing/SelectionController.h:
            (WebCore::SelectionController::typingStyle): Returns EditingStyle* rather than CSSMutableStyleDeclaration*.
            (WebCore::SelectionController::copyTypingStyle): Added.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@72573 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 7acb656..d4df669 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,45 @@
+2010-11-22  Ryosuke Niwa  <rniwa at webkit.org>
+
+        Reviewed by Tony Chang.
+
+        SelectionController::typingStyle() should return EditingStyle*
+        https://bugs.webkit.org/show_bug.cgi?id=49813
+
+        Changed the return type of SelectionController::typingStyle to EditingStyle*.
+
+        Extracted textDirection from Editor::textDirectionForSelection to hide the underlying
+        CSSMutableStyleDeclaration.
+
+        Also extracted the code to preserve unicode-bidi and direction CSS properties in
+        InsertTextCommand::input, and moved into EditingStyle::prepareToApplyAt. ShouldPreserveWritingDirection,
+        which is added to the argument list of EditingStyle::prepareToApplyAt, decides whether or not
+        these two properties are preserved.
+
+        Also added SelectionController::copyTypingStyle() to copy the typing style as an instance of
+        CSSMutableStyleDeclaration.
+
+        No new tests are added since this is a refactoring.
+
+        * editing/EditingStyle.cpp:
+        (WebCore::EditingStyle::textDirection): Extracted from Editor::textDirectionForSelection.
+        (WebCore::EditingStyle::removeStyleConflictingWithStyleOfNode): Added a missing null check.
+        (WebCore::EditingStyle::prepareToApplyAt): See above.
+        (WebCore::editingStyleIncludingTypingStyle): Calls SelectionController::typingStyle.
+        * editing/EditingStyle.h: Moved WritingDirection from Editor.h
+        * editing/Editor.cpp:
+        (WebCore::Editor::textDirectionForSelection): Calls EditingStyle::textDirection.
+        (WebCore::Editor::computeAndSetTypingStyle): Calls SelectionController::typingStyle.
+        (WebCore::Editor::selectionComputedStyle): Ditto.
+        (WebCore::Editor::styleForSelectionStart): Ditto.
+        * editing/Editor.h:
+        * editing/InsertLineBreakCommand.cpp:
+        (WebCore::InsertLineBreakCommand::doApply): Ditto.
+        * editing/InsertTextCommand.cpp:
+        (WebCore::InsertTextCommand::input): Calls EditingStyle::prepareToApplyAt with PreserveWritingDirection.
+        * editing/SelectionController.h:
+        (WebCore::SelectionController::typingStyle): Returns EditingStyle* rather than CSSMutableStyleDeclaration*.
+        (WebCore::SelectionController::copyTypingStyle): Added.
+
 2010-11-22  Patrick Gansterer  <paroga at webkit.org>
 
         Reviewed by Adam Roben.
diff --git a/WebCore/editing/EditingStyle.cpp b/WebCore/editing/EditingStyle.cpp
index 4a55dad..ad77696 100644
--- a/WebCore/editing/EditingStyle.cpp
+++ b/WebCore/editing/EditingStyle.cpp
@@ -30,6 +30,7 @@
 #include "ApplyStyleCommand.h"
 #include "CSSComputedStyleDeclaration.h"
 #include "CSSMutableStyleDeclaration.h"
+#include "CSSValueKeywords.h"
 #include "Frame.h"
 #include "RenderStyle.h"
 #include "SelectionController.h"
@@ -141,6 +142,33 @@ bool EditingStyle::isEmpty() const
     return !m_mutableStyle || m_mutableStyle->isEmpty();
 }
 
+bool EditingStyle::textDirection(WritingDirection& writingDirection) const
+{
+    RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
+    if (!unicodeBidi)
+        return false;
+
+    ASSERT(unicodeBidi->isPrimitiveValue());
+    int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
+    if (unicodeBidiValue == CSSValueEmbed) {
+        RefPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
+        ASSERT(!direction || direction->isPrimitiveValue());
+        if (!direction)
+            return false;
+
+        writingDirection = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
+
+        return true;
+    }
+
+    if (unicodeBidiValue == CSSValueNormal) {
+        writingDirection = NaturalWritingDirection;
+        return true;
+    }
+
+    return false;
+}
+
 void EditingStyle::setStyle(PassRefPtr<CSSMutableStyleDeclaration> style)
 {
     m_mutableStyle = style;
@@ -175,7 +203,7 @@ void EditingStyle::removeStyleAddedByNode(Node* node)
 
 void EditingStyle::removeStyleConflictingWithStyleOfNode(Node* node)
 {
-    if (!node || !node->parentNode())
+    if (!node || !node->parentNode() || !m_mutableStyle)
         return;
     RefPtr<CSSMutableStyleDeclaration> parentStyle = editingStyleFromComputedStyle(computedStyle(node->parentNode()));
     RefPtr<CSSMutableStyleDeclaration> nodeStyle = editingStyleFromComputedStyle(computedStyle(node));
@@ -192,12 +220,23 @@ void EditingStyle::removeNonEditingProperties()
         m_mutableStyle = copyEditingProperties(m_mutableStyle.get());
 }
 
-void EditingStyle::prepareToApplyAt(const Position& position)
+void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
 {
+    if (!m_mutableStyle)
+        return;
+
     // ReplaceSelectionCommand::handleStyleSpans() requires that this function only removes the editing style.
     // If this function was modified in the future to delete all redundant properties, then add a boolean value to indicate
     // which one of editingStyleAtPosition or computedStyle is called.
     RefPtr<EditingStyle> style = EditingStyle::create(position);
+
+    RefPtr<CSSValue> unicodeBidi;
+    RefPtr<CSSValue> direction;
+    if (shouldPreserveWritingDirection == PreserveWritingDirection) {
+        unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
+        direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
+    }
+
     style->m_mutableStyle->diff(m_mutableStyle.get());
 
     // if alpha value is zero, we don't add the background color.
@@ -207,14 +246,23 @@ void EditingStyle::prepareToApplyAt(const Position& position)
         ExceptionCode ec;
         m_mutableStyle->removeProperty(CSSPropertyBackgroundColor, ec);
     }
+
+    if (unicodeBidi) {
+        ASSERT(unicodeBidi->isPrimitiveValue());
+        m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent());
+        if (direction) {
+            ASSERT(direction->isPrimitiveValue());
+            m_mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent());
+        }
+    }
 }
 
 PassRefPtr<EditingStyle> editingStyleIncludingTypingStyle(const Position& position)
 {
     RefPtr<EditingStyle> editingStyle = EditingStyle::create(position);
-    RefPtr<CSSMutableStyleDeclaration> typingStyle = position.node()->document()->frame()->selection()->typingStyle();
-    if (typingStyle)
-        editingStyle->style()->merge(copyEditingProperties(typingStyle.get()).get());
+    RefPtr<EditingStyle> typingStyle = position.node()->document()->frame()->selection()->typingStyle();
+    if (typingStyle && typingStyle->style())
+        editingStyle->style()->merge(copyEditingProperties(typingStyle->style()).get());
     return editingStyle;
 }
     
diff --git a/WebCore/editing/EditingStyle.h b/WebCore/editing/EditingStyle.h
index 6b4c60c..b1c370b 100644
--- a/WebCore/editing/EditingStyle.h
+++ b/WebCore/editing/EditingStyle.h
@@ -40,8 +40,12 @@ namespace WebCore {
 class CSSStyleDeclaration;
 class CSSComputedStyleDeclaration;
 
+enum WritingDirection { NaturalWritingDirection, LeftToRightWritingDirection, RightToLeftWritingDirection };
+
 class EditingStyle : public RefCounted<EditingStyle> {
 public:
+    
+    enum ShouldPreserveWritingDirection { PreserveWritingDirection, DoNotPreserveWritingDirection };
 
     static PassRefPtr<EditingStyle> create()
     {
@@ -64,6 +68,7 @@ public:
     }
 
     CSSMutableStyleDeclaration* style() { return m_mutableStyle.get(); }
+    bool textDirection(WritingDirection&) const;
     bool isEmpty() const;
     void setStyle(PassRefPtr<CSSMutableStyleDeclaration>);
     void clear();
@@ -71,7 +76,7 @@ public:
     void removeStyleAddedByNode(Node* node);
     void removeStyleConflictingWithStyleOfNode(Node* node);
     void removeNonEditingProperties();
-    void prepareToApplyAt(const Position&);
+    void prepareToApplyAt(const Position&, ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
 
 private:
     EditingStyle();
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 15bad70..7a6d1cb 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -616,24 +616,11 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
     }
 
     if (m_frame->selection()->isCaret()) {
-        RefPtr<CSSMutableStyleDeclaration> typingStyle = m_frame->selection()->typingStyle();
-        if (typingStyle) {
-            RefPtr<CSSValue> unicodeBidi = typingStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
-            if (unicodeBidi) {
-                ASSERT(unicodeBidi->isPrimitiveValue());
-                int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
-                if (unicodeBidiValue == CSSValueEmbed) {
-                    RefPtr<CSSValue> direction = typingStyle->getPropertyCSSValue(CSSPropertyDirection);
-                    ASSERT(!direction || direction->isPrimitiveValue());
-                    if (direction) {
-                        hasNestedOrMultipleEmbeddings = false;
-                        return static_cast<CSSPrimitiveValue*>(direction.get())->getIdent() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
-                    }
-                } else if (unicodeBidiValue == CSSValueNormal) {
-                    hasNestedOrMultipleEmbeddings = false;
-                    return NaturalWritingDirection;
-                }
-            }
+        RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
+        WritingDirection direction;
+        if (typingStyle && typingStyle->textDirection(direction)) {
+            hasNestedOrMultipleEmbeddings = false;
+            return direction;
         }
         node = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
     }
@@ -3027,9 +3014,10 @@ void Editor::computeAndSetTypingStyle(CSSStyleDeclaration* style, EditAction edi
 
     // Calculate the current typing style.
     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
-    if (m_frame->selection()->typingStyle()) {
-        m_frame->selection()->typingStyle()->merge(mutableStyle.get());
-        mutableStyle = m_frame->selection()->typingStyle();
+    RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
+    if (typingStyle && typingStyle->style()) {
+        typingStyle->style()->merge(mutableStyle.get());
+        mutableStyle = typingStyle->style();
     }
 
     RefPtr<CSSValue> unicodeBidi;
@@ -3089,7 +3077,7 @@ PassRefPtr<CSSMutableStyleDeclaration> Editor::selectionComputedStyle(bool& shou
     if (!m_frame->selection()->typingStyle())
         return mutableStyle;
 
-    RefPtr<EditingStyle> typingStyle = EditingStyle::create(m_frame->selection()->typingStyle());
+    RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
     typingStyle->removeNonEditingProperties();
     typingStyle->prepareToApplyAt(position);
     mutableStyle->merge(typingStyle->style());
@@ -3173,13 +3161,14 @@ RenderStyle* Editor::styleForSelectionStart(Node *&nodeToRemove) const
     if (!position.node())
         return 0;
 
-    if (!m_frame->selection()->typingStyle())
+    RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
+    if (!typingStyle || !typingStyle->style())
         return position.node()->renderer()->style();
 
     RefPtr<Element> styleElement = m_frame->document()->createElement(spanTag, false);
 
     ExceptionCode ec = 0;
-    String styleText = m_frame->selection()->typingStyle()->cssText() + " display: inline";
+    String styleText = typingStyle->style()->cssText() + " display: inline";
     styleElement->setAttribute(styleAttr, styleText.impl(), ec);
     ASSERT(!ec);
 
diff --git a/WebCore/editing/Editor.h b/WebCore/editing/Editor.h
index 30aecce..2b87faa 100644
--- a/WebCore/editing/Editor.h
+++ b/WebCore/editing/Editor.h
@@ -70,7 +70,6 @@ struct CompositionUnderline {
 
 enum TriState { FalseTriState, TrueTriState, MixedTriState };
 enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface };
-enum WritingDirection { NaturalWritingDirection, LeftToRightWritingDirection, RightToLeftWritingDirection };
 
 class Editor {
 public:
diff --git a/WebCore/editing/InsertLineBreakCommand.cpp b/WebCore/editing/InsertLineBreakCommand.cpp
index 5588326..9397000 100644
--- a/WebCore/editing/InsertLineBreakCommand.cpp
+++ b/WebCore/editing/InsertLineBreakCommand.cpp
@@ -164,15 +164,15 @@ void InsertLineBreakCommand::doApply()
     }
 
     // Handle the case where there is a typing style.
-    
-    RefPtr<CSSMutableStyleDeclaration> typingStyle = document()->frame()->selection()->typingStyle();
-    
-    if (typingStyle && typingStyle->length() > 0) {
+
+    RefPtr<EditingStyle> typingStyle = document()->frame()->selection()->typingStyle();
+
+    if (typingStyle && !typingStyle->isEmpty()) {
         // Apply the typing style to the inserted line break, so that if the selection
         // leaves and then comes back, new input will have the right style.
         // FIXME: We shouldn't always apply the typing style to the line break here,
         // see <rdar://problem/5794462>.
-        applyStyle(typingStyle.get(), firstDeepEditingPositionForNode(nodeToInsert.get()), lastDeepEditingPositionForNode(nodeToInsert.get()));
+        applyStyle(typingStyle->style(), firstDeepEditingPositionForNode(nodeToInsert.get()), lastDeepEditingPositionForNode(nodeToInsert.get()));
         // Even though this applyStyle operates on a Range, it still sets an endingSelection().
         // It tries to set a VisibleSelection around the content it operated on. So, that VisibleSelection
         // will either (a) select the line break we inserted, or it will (b) be a caret just 
diff --git a/WebCore/editing/InsertTextCommand.cpp b/WebCore/editing/InsertTextCommand.cpp
index 87a695d..9eb8aa7 100644
--- a/WebCore/editing/InsertTextCommand.cpp
+++ b/WebCore/editing/InsertTextCommand.cpp
@@ -190,26 +190,11 @@ void InsertTextCommand::input(const String& text, bool selectInsertedText)
     setEndingSelection(forcedEndingSelection);
 
     // Handle the case where there is a typing style.
-    RefPtr<CSSMutableStyleDeclaration> typingStyle = document()->frame()->selection()->typingStyle();
-    RefPtr<CSSComputedStyleDeclaration> endingStyle = endPosition.computedStyle();
-    RefPtr<CSSValue> unicodeBidi;
-    RefPtr<CSSValue> direction;
-    if (typingStyle) {
-        unicodeBidi = typingStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
-        direction = typingStyle->getPropertyCSSValue(CSSPropertyDirection);
+    if (RefPtr<EditingStyle> typingStyle = document()->frame()->selection()->typingStyle()) {
+        typingStyle->prepareToApplyAt(endPosition, EditingStyle::PreserveWritingDirection);
+        if (!typingStyle->isEmpty())
+            applyStyle(typingStyle->style());
     }
-    endingStyle->diff(typingStyle.get());
-    if (typingStyle && unicodeBidi) {
-        ASSERT(unicodeBidi->isPrimitiveValue());
-        typingStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent());
-        if (direction) {
-            ASSERT(direction->isPrimitiveValue());
-            typingStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent());
-        }
-    }
-
-    if (typingStyle && typingStyle->length())
-        applyStyle(typingStyle.get());
 
     if (!selectInsertedText)
         setEndingSelection(VisibleSelection(endingSelection().end(), endingSelection().affinity()));
diff --git a/WebCore/editing/SelectionController.h b/WebCore/editing/SelectionController.h
index 2edad0a..8cc89e4 100644
--- a/WebCore/editing/SelectionController.h
+++ b/WebCore/editing/SelectionController.h
@@ -160,7 +160,8 @@ public:
 
     void paintDragCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const;
 
-    CSSMutableStyleDeclaration* typingStyle() const;
+    EditingStyle* typingStyle() const;
+    PassRefPtr<CSSMutableStyleDeclaration> copyTypingStyle() const;
     void setTypingStyle(PassRefPtr<EditingStyle>);
     void clearTypingStyle();
 
@@ -233,9 +234,16 @@ private:
     bool m_caretPaint;
 };
 
-inline CSSMutableStyleDeclaration* SelectionController::typingStyle() const
+inline EditingStyle* SelectionController::typingStyle() const
 {
-    return m_typingStyle ? m_typingStyle->style() : 0;
+    return m_typingStyle.get();
+}
+
+inline PassRefPtr<CSSMutableStyleDeclaration> SelectionController::copyTypingStyle() const
+{
+    if (!m_typingStyle || !m_typingStyle->style())
+        return 0;
+    return m_typingStyle->style()->copy();
 }
 
 inline void SelectionController::clearTypingStyle()
diff --git a/WebKit/mac/ChangeLog b/WebKit/mac/ChangeLog
index bd11503..5b9ab92 100644
--- a/WebKit/mac/ChangeLog
+++ b/WebKit/mac/ChangeLog
@@ -1,3 +1,19 @@
+2010-11-22  Ryosuke Niwa  <rniwa at webkit.org>
+
+        Reviewed by Tony Chang.
+
+        SelectionController::typingStyle() should return EditingStyle*
+        https://bugs.webkit.org/show_bug.cgi?id=49813
+
+        Changed the return value of SelectionController::typingStyle() to EditingStyle*.
+        Also added SelectionController::copyTypingStyle() to copy the typing style
+        as an instance of CSSMutableStyleDeclaration.
+
+        No tests are added since this is no behavioral change.
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame _typingStyle]): Calls SelectionController::copyTypingStyle()
+
 2010-11-19  Michael Saboff  <msaboff at apple.com>
 
         Reviewed by Sam Weinig
diff --git a/WebKit/mac/WebView/WebFrame.mm b/WebKit/mac/WebView/WebFrame.mm
index fb6d69c..d1d4953 100644
--- a/WebKit/mac/WebView/WebFrame.mm
+++ b/WebKit/mac/WebView/WebFrame.mm
@@ -901,9 +901,12 @@ static inline WebDataSource *dataSource(DocumentLoader* loader)
 
 - (DOMCSSStyleDeclaration *)_typingStyle
 {
-    if (!_private->coreFrame || !_private->coreFrame->selection()->typingStyle())
+    if (!_private->coreFrame)
+        return nil;
+    RefPtr<CSSMutableStyleDeclaration> typingStyle = _private->coreFrame->selection()->copyTypingStyle();
+    if (!typingStyle)
         return nil;
-    return kit(_private->coreFrame->selection()->typingStyle()->copy().get());
+    return kit(typingStyle.get());
 }
 
 - (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list