diff --git a/.hgtags b/.hgtags
index b972d376f7d3e57ece33d4c577cb598723076693..02e19f6f6610700a810a9f23b6148f926f274dbd 100755
--- a/.hgtags
+++ b/.hgtags
@@ -482,3 +482,4 @@ d029faf69f20a23007f32420a1ac6a3b89a6d441 3.7.6-release
 83959480cb986522d07b151a0c778ab7f920d41b 3.7.7-release
 bba9b3722eea08949e4ff69591f736bf0f808434 3.7.8-release
 a9f2d0cb11f73b06858e6083bb50083becc3f9cd 3.7.9-release
+91dae9494b4d147541c7a01902334ba19a7ec05e 3.7.10-release
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
index 36a7d38bb71609d836222a2f60248a20b65b3b26..8a83ac498fea67716035452cefeafb082eff2831 100755
--- a/indra/integration_tests/llimage_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -7,6 +7,7 @@ project (llimage_libtest)
 include(00-Common)
 include(LLCommon)
 include(LLImage)
+include(LLMath)
 include(LLImageJ2COJ) 
 include(LLKDU)
 include(LLVFS)
@@ -15,6 +16,7 @@ include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
     ${LLVFS_INCLUDE_DIRS}
     ${LLIMAGE_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
     )
 include_directories(SYSTEM
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
@@ -64,6 +66,7 @@ endif (DARWIN)
 target_link_libraries(llimage_libtest
     ${LLCOMMON_LIBRARIES}
     ${LLVFS_LIBRARIES}
+    ${LLMATH_LIBRARIES}
     ${LLIMAGE_LIBRARIES}
     ${LLKDU_LIBRARIES}
     ${KDU_LIBRARY}
diff --git a/indra/integration_tests/llimage_libtest/filters/1970colorize.xml b/indra/integration_tests/llimage_libtest/filters/1970colorize.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0dab2489a05a1b3f42b51e19413a7ee35e806206
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/1970colorize.xml
@@ -0,0 +1,41 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.8</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.5</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>blend</string>
+            <real>10.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.1</real>
+            <real>0.1</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/autocontrast.xml b/indra/integration_tests/llimage_libtest/filters/autocontrast.xml
new file mode 100755
index 0000000000000000000000000000000000000000..ec3d7561bdcf6e662397f21cde040ed26897752b
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/autocontrast.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/badtrip.xml b/indra/integration_tests/llimage_libtest/filters/badtrip.xml
new file mode 100755
index 0000000000000000000000000000000000000000..14ee0baff3f9f953e05bae32e797e531318484da
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/badtrip.xml
@@ -0,0 +1,36 @@
+<llsd>
+    <array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>posterize</string>
+            <real>10.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>gradient</string>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.15</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/blowhighlights.xml b/indra/integration_tests/llimage_libtest/filters/blowhighlights.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2474a1b953c6b73a911566e54a4551d6a85f7b72
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/blowhighlights.xml
@@ -0,0 +1,25 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>uniform</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>gamma</string>
+            <real>0.25</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/blur.xml b/indra/integration_tests/llimage_libtest/filters/blur.xml
new file mode 100644
index 0000000000000000000000000000000000000000..addd0568552fdc9c788d755de78bd61729fc2a1d
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/blur.xml
@@ -0,0 +1,7 @@
+<llsd>
+    <array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/brighten.xml b/indra/integration_tests/llimage_libtest/filters/brighten.xml
new file mode 100755
index 0000000000000000000000000000000000000000..9b4232229fdfd314e0a337c8c415d9332354a9c3
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/brighten.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>brighten</string>
+            <real>0.5</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/colorize.xml b/indra/integration_tests/llimage_libtest/filters/colorize.xml
new file mode 100644
index 0000000000000000000000000000000000000000..72e58b0ffe096a0950e36e8aafb58ea544725f55
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/colorize.xml
@@ -0,0 +1,24 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>10.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/colortransform.xml b/indra/integration_tests/llimage_libtest/filters/colortransform.xml
new file mode 100644
index 0000000000000000000000000000000000000000..de4bebcce2e5b0b6c766c4be2cf661c8ea6df5ec
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/colortransform.xml
@@ -0,0 +1,16 @@
+<llsd>
+    <array>
+        <array>
+            <string>colortransform</string>
+            <real>0.2125</real>
+            <real>0.7154</real>
+            <real>0.0721</real>
+            <real>0.2125</real>
+            <real>0.7154</real>
+            <real>0.0721</real>
+            <real>0.2125</real>
+            <real>0.7154</real>
+            <real>0.0721</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/contrast.xml b/indra/integration_tests/llimage_libtest/filters/contrast.xml
new file mode 100644
index 0000000000000000000000000000000000000000..00746b8a9e433ae954455aa69c70391eb48fee4a
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/contrast.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>contrast</string>
+            <real>1.5</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/convolve.xml b/indra/integration_tests/llimage_libtest/filters/convolve.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6e65b5f88a78c7fa4693502d22bbf7a6c8c40832
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/convolve.xml
@@ -0,0 +1,18 @@
+<llsd>
+    <array>
+        <array>
+            <string>convolve</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>4.0</real>
+            <real>1.0</real>
+            <real>4.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>4.0</real>
+            <real>1.0</real>
+            <real>4.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/darken.xml b/indra/integration_tests/llimage_libtest/filters/darken.xml
new file mode 100755
index 0000000000000000000000000000000000000000..5cec3589b66017d84f30c86016abd32c18aa5082
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/darken.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>darken</string>
+            <real>0.5</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/dodgeandburn.xml b/indra/integration_tests/llimage_libtest/filters/dodgeandburn.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0e2e0ad68c0fc4abace1dc38b9ed58c74e8822a7
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/dodgeandburn.xml
@@ -0,0 +1,47 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.4</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>-0.8</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/edges.xml b/indra/integration_tests/llimage_libtest/filters/edges.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a66b81d01ef7f377c04fcad7550023a0ab67df96
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/edges.xml
@@ -0,0 +1,24 @@
+<llsd>
+    <array>
+        <array>
+            <string>gradient</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>2.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/focus.xml b/indra/integration_tests/llimage_libtest/filters/focus.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d8525fea62b7a0a3f9121d2b7147cdd6a6f802ab
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/focus.xml
@@ -0,0 +1,39 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>0.4</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>sharpen</string>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/gamma.xml b/indra/integration_tests/llimage_libtest/filters/gamma.xml
new file mode 100644
index 0000000000000000000000000000000000000000..19af09b046290176b3a017f1ce67b32f6bbbe832
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/gamma.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>gamma</string>
+            <real>1.7</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/grayscale.xml b/indra/integration_tests/llimage_libtest/filters/grayscale.xml
new file mode 100644
index 0000000000000000000000000000000000000000..984312c4fd291f049306ca09d4d66de9a5951bad
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/grayscale.xml
@@ -0,0 +1,14 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/heatwave.xml b/indra/integration_tests/llimage_libtest/filters/heatwave.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a99f41c8335cd35ac589ab5d41bcec9650106e3d
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/heatwave.xml
@@ -0,0 +1,38 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.8</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>fade</string>
+            <real>0.5</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>4.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.4</real>
+            <real>0.0</real>
+            <real>0.2</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/horizontalscreen.xml b/indra/integration_tests/llimage_libtest/filters/horizontalscreen.xml
new file mode 100644
index 0000000000000000000000000000000000000000..21cab70e54aeed1d56d73ae6a368515958e85e44
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/horizontalscreen.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.015</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/julesverne.xml b/indra/integration_tests/llimage_libtest/filters/julesverne.xml
new file mode 100644
index 0000000000000000000000000000000000000000..981e221da96fa43858ced7dd7df7b5182fbb8402
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/julesverne.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.02</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/lensflare.xml b/indra/integration_tests/llimage_libtest/filters/lensflare.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0b5af9c82be0c22873a0212c490cfac6b62df42d
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/lensflare.xml
@@ -0,0 +1,131 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>add</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.1</real>
+            <real>0.1</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.5</real>
+            <real>5.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.6</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>5.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.6</real>
+            <real>0.6</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>-0.5</real>
+            <real>0.10</real>
+            <real>20.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.7</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.6</real>
+            <real>-0.6</real>
+            <real>0.05</real>
+            <real>20.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.7</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.4</real>
+            <real>-0.4</real>
+            <real>0.025</real>
+            <real>20.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.7</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/lightleak.xml b/indra/integration_tests/llimage_libtest/filters/lightleak.xml
new file mode 100755
index 0000000000000000000000000000000000000000..6fe496506e700ca2ad50e1eb23ba43fde01a3d65
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/lightleak.xml
@@ -0,0 +1,78 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>brighten</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>add</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.1</real>
+            <real>0.1</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.5</real>
+            <real>5.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.8</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>5.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.8</real>
+            <real>0.8</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/linearize.xml b/indra/integration_tests/llimage_libtest/filters/linearize.xml
new file mode 100755
index 0000000000000000000000000000000000000000..23d0290e07834958bac64ae72db35de7346fa365
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/linearize.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/miniature.xml b/indra/integration_tests/llimage_libtest/filters/miniature.xml
new file mode 100755
index 0000000000000000000000000000000000000000..9aa8a87c6f470e7b581a3773a233ce6eaf5f83a7
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/miniature.xml
@@ -0,0 +1,118 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.02</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.02</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>saturate</string>
+            <real>1.2</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>0.25</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.25</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>sharpen</string>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>-1.0</real>
+            <real>0.0</real>
+            <real>-0.25</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.25</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
\ No newline at end of file
diff --git a/indra/integration_tests/llimage_libtest/filters/newsscreen.xml b/indra/integration_tests/llimage_libtest/filters/newsscreen.xml
new file mode 100755
index 0000000000000000000000000000000000000000..50ed27c6db555c3fa1c25cb185cd1bf3c4783dfe
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/newsscreen.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>2Dsine</string>
+            <real>0.015</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/overcast.xml b/indra/integration_tests/llimage_libtest/filters/overcast.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dce5ab3e9e81b99bfc58d2c38570a0892c04246e
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/overcast.xml
@@ -0,0 +1,24 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.3</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>saturate</string>
+            <real>0.35</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/pixelate.xml b/indra/integration_tests/llimage_libtest/filters/pixelate.xml
new file mode 100755
index 0000000000000000000000000000000000000000..f643419aa08eefc7720105f66c15459b214f6dba
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/pixelate.xml
@@ -0,0 +1,35 @@
+<llsd>
+    <array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>darken</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.9</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>posterize</string>
+            <real>4.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
\ No newline at end of file
diff --git a/indra/integration_tests/llimage_libtest/filters/posterize.xml b/indra/integration_tests/llimage_libtest/filters/posterize.xml
new file mode 100755
index 0000000000000000000000000000000000000000..4d03df3c6611858d37c73feae4887a87ef78d77b
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/posterize.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>posterize</string>
+            <real>10.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/rotatecolors180.xml b/indra/integration_tests/llimage_libtest/filters/rotatecolors180.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e25029720fe876d75f626810f4640a040c39a6a1
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/rotatecolors180.xml
@@ -0,0 +1,8 @@
+<llsd>
+    <array>
+        <array>
+            <string>rotate</string>
+            <real>180.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/saturate.xml b/indra/integration_tests/llimage_libtest/filters/saturate.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b77f07a0374b0f6143b59761758483b7ecc80453
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/saturate.xml
@@ -0,0 +1,8 @@
+<llsd>
+    <array>
+        <array>
+            <string>saturate</string>
+            <real>3.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/sepia.xml b/indra/integration_tests/llimage_libtest/filters/sepia.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0304ead015df4649b4d0744eb3fa5ae1476502d6
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/sepia.xml
@@ -0,0 +1,14 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>sepia</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/sharpen.xml b/indra/integration_tests/llimage_libtest/filters/sharpen.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6d3f9ae1a207077650887620c208e0197f78a152
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/sharpen.xml
@@ -0,0 +1,7 @@
+<llsd>
+    <array>
+        <array>
+            <string>sharpen</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/slantedscreen.xml b/indra/integration_tests/llimage_libtest/filters/slantedscreen.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6cd1a96185f12a69ba837ad4b0d2e8df10a041df
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/slantedscreen.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.015</real>
+            <real>45.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/spotlight.xml b/indra/integration_tests/llimage_libtest/filters/spotlight.xml
new file mode 100644
index 0000000000000000000000000000000000000000..203130bdeeda720f51dc50fe0e24f7cd971888e7
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/spotlight.xml
@@ -0,0 +1,45 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.8</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>saturate</string>
+            <real>1.5</real>
+        </array>
+        <array>
+            <string>fade</string>
+            <real>1.0</real>
+            <real>0.25</real>
+        </array>
+        <array>
+            <string>saturate</string>
+            <real>0.8</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>brighten</string>
+            <real>30</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/stencilgradient.xml b/indra/integration_tests/llimage_libtest/filters/stencilgradient.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d22809a9bf2a49f0a919f7301f399272782e8a45
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/stencilgradient.xml
@@ -0,0 +1,24 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>-1.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/stencilscanlines.xml b/indra/integration_tests/llimage_libtest/filters/stencilscanlines.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ce428503d17cb3d3d88de3e04810ba37487fdf5
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/stencilscanlines.xml
@@ -0,0 +1,22 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>scanlines</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.1</real>
+            <real>45.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/stenciluniform.xml b/indra/integration_tests/llimage_libtest/filters/stenciluniform.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7d72f0ed934c2e442d9a45123a1e9238bd8ebdd2
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/stenciluniform.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>uniform</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>0.5</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/stencilvignette.xml b/indra/integration_tests/llimage_libtest/filters/stencilvignette.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d30637fef595d76bc7f0c6e1abe5c9eb3f1d495a
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/stencilvignette.xml
@@ -0,0 +1,24 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>10.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/thematrix.xml b/indra/integration_tests/llimage_libtest/filters/thematrix.xml
new file mode 100755
index 0000000000000000000000000000000000000000..af9a5eced8b728584edf1a0df082d114001c27cd
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/thematrix.xml
@@ -0,0 +1,42 @@
+<llsd>
+    <array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>posterize</string>
+            <real>50.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>gradient</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.025</real>
+            <real>90.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.1</real>
+            <real>0.2</real>
+            <real>0.2</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
\ No newline at end of file
diff --git a/indra/integration_tests/llimage_libtest/filters/toycamera.xml b/indra/integration_tests/llimage_libtest/filters/toycamera.xml
new file mode 100755
index 0000000000000000000000000000000000000000..4e76f6b2fbe950921382fbb6baa16025b948fb86
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/toycamera.xml
@@ -0,0 +1,46 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>fade</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.2</real>
+            <real>3.0</real>
+        </array>
+        <array>
+            <string>linearize</string>
+            <real>0.05</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
\ No newline at end of file
diff --git a/indra/integration_tests/llimage_libtest/filters/verticalscreen.xml b/indra/integration_tests/llimage_libtest/filters/verticalscreen.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0768d1d7e17a0e77b0c5641775907f5e734a28f1
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/verticalscreen.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.015</real>
+            <real>90.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/filters/video.xml b/indra/integration_tests/llimage_libtest/filters/video.xml
new file mode 100755
index 0000000000000000000000000000000000000000..fe17f3950a18e1b647739eecd1db48700e912f96
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/filters/video.xml
@@ -0,0 +1,44 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>darken</string>
+            <real>0.15</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>uniform</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.02</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>gamma</string>
+            <real>0.25</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
index 034c816742b23090990c6446ba125117ae9ca6b0..3d27b4a5b548c6e699917e15b6888132e60631e0 100755
--- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
@@ -32,6 +32,7 @@
 
 // Linden library includes
 #include "llimage.h"
+#include "llimagefilter.h"
 #include "llimagejpeg.h"
 #include "llimagepng.h"
 #include "llimagebmp.h"
@@ -39,6 +40,8 @@
 #include "llimagej2c.h"
 #include "lldir.h"
 #include "lldiriterator.h"
+#include "v4coloru.h"
+#include "llsdserialize.h"
 
 // system libraries
 #include <iostream>
@@ -83,6 +86,8 @@ static const char USAGE[] = "\n"
 " -rev, --reversible\n"
 "        Set the compression to be lossless (reversible in j2c parlance).\n"
 "        Only valid for output j2c images.\n"
+" -f, --filter <file>\n"
+"        Apply the filter <file> to the input images.\n"
 " -log, --logmetrics <metric>\n"
 "        Log performance data for <metric>. Results in <metric>.slp\n"
 "        Note: so far, only ImageCompressionTester has been tested.\n"
@@ -99,7 +104,7 @@ static bool sAllDone = false;
 // Create an empty formatted image instance of the correct type from the filename
 LLPointer<LLImageFormatted> create_image(const std::string &filename)
 {
-	std::string exten = gDirUtilp->getExtension(filename);	
+	std::string exten = gDirUtilp->getExtension(filename);
 	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromExtension(exten);
 	return image;
 }
@@ -350,6 +355,7 @@ int main(int argc, char** argv)
 	int blocks_size = -1;
 	int levels = 0;
 	bool reversible = false;
+    std::string filter_name = "";
 
 	// Init whatever is necessary
 	ll_init_apr();
@@ -523,7 +529,26 @@ int main(int argc, char** argv)
 					break;
 			}
 		}
-		else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
+		else if (!strcmp(argv[arg], "--filter") || !strcmp(argv[arg], "-f"))
+		{
+			// '--filter' needs to be specified with a named filter argument
+			if ((arg + 1) < argc)
+			{
+				filter_name = argv[arg+1];
+			}
+			if (((arg + 1) >= argc) || (filter_name[0] == '-'))
+			{
+				// We don't have an argument left in the arg list or the next argument is another option
+				std::cout << "No --filter argument given, no filter will be applied" << std::endl;
+			}
+			else
+			{
+				arg += 1;					// Skip that arg now we know it's a valid test name
+				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
+					break;
+            }
+		}
+        else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
 		{
 			analyze_performance = true;
 		}
@@ -553,7 +578,10 @@ int main(int argc, char** argv)
 		fast_timer_log_thread = new LogThread(LLFastTimer::sLogName);
 		fast_timer_log_thread->start();
 	}
-	
+    
+    // Load the filter once and for all
+    LLImageFilter filter(filter_name);
+
 	// Perform action on each input file
 	std::list<std::string>::iterator in_file  = input_filenames.begin();
 	std::list<std::string>::iterator out_file = output_filenames.begin();
@@ -568,7 +596,10 @@ int main(int argc, char** argv)
 			std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
 			continue;
 		}
-	
+        
+        // Apply the filter
+        filter.executeFilter(raw_image);
+
 		// Save file
 		if (out_file != out_end)
 		{
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index e837b0cac2cbb25bc5d2587a7c1428d4866ec37c..293ada7548e598a182bed2402b45cba2c84f81ac 100755
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -27,6 +27,7 @@ set(llimage_SOURCE_FILES
     llimage.cpp
     llimagedimensionsinfo.cpp
     llimagedxt.cpp
+    llimagefilter.cpp
     llimagej2c.cpp
     llimagejpeg.cpp
     llimagepng.cpp
@@ -42,6 +43,7 @@ set(llimage_HEADER_FILES
     llimagebmp.h
     llimagedimensionsinfo.h
     llimagedxt.h
+    llimagefilter.h
     llimagej2c.h
     llimagejpeg.h
     llimagepng.h
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 1ca1bf55a6b717c5da191efb46f2d7a632b5f73e..d336eeaabcea413465564b5dfb299a3f88c8e18d 100755
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -452,18 +452,8 @@ void LLImageRaw::verticalFlip()
 void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
 {
 	// Find new sizes
-	S32 new_width = MIN_IMAGE_SIZE;
-	S32 new_height = MIN_IMAGE_SIZE;
-
-	while( (new_width < getWidth()) && (new_width < max_dim) )
-	{
-		new_width <<= 1;
-	}
-
-	while( (new_height < getHeight()) && (new_height < max_dim) )
-	{
-		new_height <<= 1;
-	}
+	S32 new_width  = expandDimToPowerOfTwo(getWidth(), max_dim);
+	S32 new_height = expandDimToPowerOfTwo(getHeight(), max_dim);
 
 	scale( new_width, new_height, scale_image );
 }
@@ -471,55 +461,61 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
 void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
 {
 	// Find new sizes
-	S32 new_width = max_dim;
-	S32 new_height = max_dim;
-
-	while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) )
-	{
-		new_width >>= 1;
-	}
-
-	while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) )
-	{
-		new_height >>= 1;
-	}
+	S32 new_width  = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE);
+	S32 new_height = contractDimToPowerOfTwo(getHeight(), MIN_IMAGE_SIZE);
 
 	scale( new_width, new_height, scale_image );
 }
 
-void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
+// static
+S32 LLImageRaw::biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim)
 {
 	// Strong bias towards rounding down (to save bandwidth)
 	// No bias would mean THRESHOLD == 1.5f;
-	const F32 THRESHOLD = 1.75f; 
-
+	const F32 THRESHOLD = 1.75f;
+    
 	// Find new sizes
-	S32 larger_w = max_dim;	// 2^n >= mWidth
-	S32 smaller_w = max_dim;	// 2^(n-1) <= mWidth
-	while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) )
+	S32 larger_dim  = max_dim;	// 2^n >= curr_dim
+	S32 smaller_dim = max_dim;	// 2^(n-1) <= curr_dim
+	while( (smaller_dim > curr_dim) && (smaller_dim > MIN_IMAGE_SIZE) )
 	{
-		larger_w = smaller_w;
-		smaller_w >>= 1;
+		larger_dim = smaller_dim;
+		smaller_dim >>= 1;
 	}
-	S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
+	return ( ((F32)curr_dim / (F32)smaller_dim) > THRESHOLD ) ? larger_dim : smaller_dim;
+}
 
+// static
+S32 LLImageRaw::expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim)
+{
+	S32 new_dim = MIN_IMAGE_SIZE;
+	while( (new_dim < curr_dim) && (new_dim < max_dim) )
+	{
+		new_dim <<= 1;
+	}
+    return new_dim;
+}
 
-	S32 larger_h = max_dim;	// 2^m >= mHeight
-	S32 smaller_h = max_dim;	// 2^(m-1) <= mHeight
-	while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) )
+// static
+S32 LLImageRaw::contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim)
+{
+	S32 new_dim = MAX_IMAGE_SIZE;
+	while( (new_dim > curr_dim) && (new_dim > min_dim) )
 	{
-		larger_h = smaller_h;
-		smaller_h >>= 1;
+		new_dim >>= 1;
 	}
-	S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
+    return new_dim;
+}
 
+void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
+{
+	// Find new sizes
+	S32 new_width  = biasedDimToPowerOfTwo(getWidth(),max_dim);
+	S32 new_height = biasedDimToPowerOfTwo(getHeight(),max_dim);
 
 	scale( new_width, new_height );
 }
 
-
-
-
 // Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f).  Thanks, Jim Blinn!
 inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b )
 {
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index bf441a008a0c711f6c8505d03ae281caeb8fc5e2..cd3f76f1fd0e3a0ac195874bd8611b211698fa15 100755
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -209,6 +209,9 @@ class LLImageRaw : public LLImageBase
 
 	void verticalFlip();
 
+    static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
+    static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
+    static S32 contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim = MIN_IMAGE_SIZE);
 	void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
 	void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
 	void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..3d0c488768ea0534aa99f8d58cd603ffe357081c
--- /dev/null
+++ b/indra/llimage/llimagefilter.cpp
@@ -0,0 +1,939 @@
+/** 
+ * @file llimagefilter.cpp
+ * @brief Simple Image Filtering. See https://wiki.lindenlab.com/wiki/SL_Viewer_Image_Filters for complete documentation.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2014, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llimagefilter.h"
+
+#include "llmath.h"
+#include "v3color.h"
+#include "v4coloru.h"
+#include "m3math.h"
+#include "v3math.h"
+#include "llsdserialize.h"
+#include "llstring.h"
+
+//---------------------------------------------------------------------------
+// LLImageFilter
+//---------------------------------------------------------------------------
+
+LLImageFilter::LLImageFilter(const std::string& file_path) :
+    mFilterData(LLSD::emptyArray()),
+    mImage(NULL),
+    mHistoRed(NULL),
+    mHistoGreen(NULL),
+    mHistoBlue(NULL),
+    mHistoBrightness(NULL),
+    mStencilBlendMode(STENCIL_BLEND_MODE_BLEND),
+    mStencilShape(STENCIL_SHAPE_UNIFORM),
+    mStencilGamma(1.0),
+    mStencilMin(0.0),
+    mStencilMax(1.0)
+{
+    // Load filter description from file
+	llifstream filter_xml(file_path);
+	if (filter_xml.is_open())
+	{
+		// Load and parse the file
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+		parser->parse(filter_xml, mFilterData, LLSDSerialize::SIZE_UNLIMITED);
+		filter_xml.close();
+	}
+}
+
+LLImageFilter::~LLImageFilter()
+{
+    mImage = NULL;
+    ll_aligned_free_16(mHistoRed);
+    ll_aligned_free_16(mHistoGreen);
+    ll_aligned_free_16(mHistoBlue);
+    ll_aligned_free_16(mHistoBrightness);
+}
+
+/*
+ *TODO 
+ * Rename stencil to mask
+ * Improve perf: use LUT for alpha blending in uniform case
+ * Add gradient coloring as a filter
+ */
+
+//============================================================================
+// Apply the filter data to the image passed as parameter
+//============================================================================
+
+void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image)
+{
+    mImage = raw_image;
+    
+	//std::cout << "Filter : size = " << mFilterData.size() << std::endl;
+	for (S32 i = 0; i < mFilterData.size(); ++i)
+	{
+        std::string filter_name = mFilterData[i][0].asString();
+        // Dump out the filter values (for debug)
+        //std::cout << "Filter : name = " << mFilterData[i][0].asString() << ", params = ";
+        //for (S32 j = 1; j < mFilterData[i].size(); ++j)
+        //{
+        //    std::cout << mFilterData[i][j].asString() << ", ";
+        //}
+        //std::cout << std::endl;
+        
+        if (filter_name == "stencil")
+        {
+            // Get the shape of the stencil, that is how the procedural alpha is computed geometrically
+            std::string filter_shape = mFilterData[i][1].asString();
+            EStencilShape shape = STENCIL_SHAPE_UNIFORM;
+            if (filter_shape == "uniform")
+            {
+                shape = STENCIL_SHAPE_UNIFORM;
+            }
+            else if (filter_shape == "gradient")
+            {
+                shape = STENCIL_SHAPE_GRADIENT;
+            }
+            else if (filter_shape == "vignette")
+            {
+                shape = STENCIL_SHAPE_VIGNETTE;
+            }
+            else if (filter_shape == "scanlines")
+            {
+                shape = STENCIL_SHAPE_SCAN_LINES;
+            }
+            // Get the blend mode of the stencil, that is how the effect is blended in the background through the stencil
+            std::string filter_mode  = mFilterData[i][2].asString();
+            EStencilBlendMode mode = STENCIL_BLEND_MODE_BLEND;
+            if (filter_mode == "blend")
+            {
+                mode = STENCIL_BLEND_MODE_BLEND;
+            }
+            else if (filter_mode == "add")
+            {
+                mode = STENCIL_BLEND_MODE_ADD;
+            }
+            else if (filter_mode == "add_back")
+            {
+                mode = STENCIL_BLEND_MODE_ABACK;
+            }
+            else if (filter_mode == "fade")
+            {
+                mode = STENCIL_BLEND_MODE_FADE;
+            }
+            // Get the float params: mandatory min, max then the optional parameters (4 max)
+            F32 min = (F32)(mFilterData[i][3].asReal());
+            F32 max = (F32)(mFilterData[i][4].asReal());
+            F32 params[4] = {0.0, 0.0, 0.0, 0.0};
+            for (S32 j = 5; (j < mFilterData[i].size()) && (j < 9); j++)
+            {
+                params[j-5] = (F32)(mFilterData[i][j].asReal());
+            }
+            // Set the stencil
+            setStencil(shape,mode,min,max,params);
+        }
+        else if (filter_name == "sepia")
+        {
+            filterSepia();
+        }
+        else if (filter_name == "grayscale")
+        {
+            filterGrayScale();
+        }
+        else if (filter_name == "saturate")
+        {
+            filterSaturate((float)(mFilterData[i][1].asReal()));
+        }
+        else if (filter_name == "rotate")
+        {
+            filterRotate((float)(mFilterData[i][1].asReal()));
+        }
+        else if (filter_name == "gamma")
+        {
+            LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
+            filterGamma((float)(mFilterData[i][1].asReal()),color);
+        }
+        else if (filter_name == "colorize")
+        {
+            LLColor3 color((float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()));
+            LLColor3 alpha((F32)(mFilterData[i][4].asReal()),(float)(mFilterData[i][5].asReal()),(float)(mFilterData[i][6].asReal()));
+            filterColorize(color,alpha);
+        }
+        else if (filter_name == "contrast")
+        {
+            LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
+            filterContrast((float)(mFilterData[i][1].asReal()),color);
+        }
+        else if (filter_name == "brighten")
+        {
+            LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
+            filterBrightness((float)(mFilterData[i][1].asReal()),color);
+        }
+        else if (filter_name == "darken")
+        {
+            LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
+            filterBrightness((float)(-mFilterData[i][1].asReal()),color);
+        }
+        else if (filter_name == "linearize")
+        {
+            LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
+            filterLinearize((float)(mFilterData[i][1].asReal()),color);
+        }
+        else if (filter_name == "posterize")
+        {
+            LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
+            filterEqualize((S32)(mFilterData[i][1].asReal()),color);
+        }
+        else if (filter_name == "screen")
+        {
+            std::string screen_name = mFilterData[i][1].asString();
+            EScreenMode mode = SCREEN_MODE_2DSINE;
+            if (screen_name == "2Dsine")
+            {
+                mode = SCREEN_MODE_2DSINE;
+            }
+            else if (screen_name == "line")
+            {
+                mode = SCREEN_MODE_LINE;
+            }
+            filterScreen(mode,(F32)(mFilterData[i][2].asReal()),(F32)(mFilterData[i][3].asReal()));
+        }
+        else if (filter_name == "blur")
+        {
+            LLMatrix3 kernel;
+            for (S32 i = 0; i < NUM_VALUES_IN_MAT3; i++)
+                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++)
+                    kernel.mMatrix[i][j] = 1.0;
+            convolve(kernel,true,false);
+        }
+        else if (filter_name == "sharpen")
+        {
+            LLMatrix3 kernel;
+            for (S32 k = 0; k < NUM_VALUES_IN_MAT3; k++)
+                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++)
+                    kernel.mMatrix[k][j] = -1.0;
+            kernel.mMatrix[1][1] = 9.0;
+            convolve(kernel,false,false);
+        }
+        else if (filter_name == "gradient")
+        {
+            LLMatrix3 kernel;
+            for (S32 k = 0; k < NUM_VALUES_IN_MAT3; k++)
+                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++)
+                    kernel.mMatrix[k][j] = -1.0;
+            kernel.mMatrix[1][1] = 8.0;
+            convolve(kernel,false,true);
+        }
+        else if (filter_name == "convolve")
+        {
+            LLMatrix3 kernel;
+            S32 index = 1;
+            bool normalize = (mFilterData[i][index++].asReal() > 0.0);
+            bool abs_value = (mFilterData[i][index++].asReal() > 0.0);
+            for (S32 k = 0; k < NUM_VALUES_IN_MAT3; k++)
+                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++)
+                    kernel.mMatrix[k][j] = mFilterData[i][index++].asReal();
+            convolve(kernel,normalize,abs_value);
+        }
+        else if (filter_name == "colortransform")
+        {
+            LLMatrix3 transform;
+            S32 index = 1;
+            for (S32 k = 0; k < NUM_VALUES_IN_MAT3; k++)
+                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++)
+                    transform.mMatrix[k][j] = mFilterData[i][index++].asReal();
+            transform.transpose();
+            colorTransform(transform);
+        }
+        else
+        {
+            llwarns << "Filter unknown, cannot execute filter command : " << filter_name << llendl;
+        }
+    }
+}
+
+//============================================================================
+// Filter Primitives
+//============================================================================
+
+void LLImageFilter::blendStencil(F32 alpha, U8* pixel, U8 red, U8 green, U8 blue)
+{
+    F32 inv_alpha = 1.0 - alpha;
+    switch (mStencilBlendMode)
+    {
+        case STENCIL_BLEND_MODE_BLEND:
+            // Classic blend of incoming color with the background image
+            pixel[VRED]   = inv_alpha * pixel[VRED]   + alpha * red;
+            pixel[VGREEN] = inv_alpha * pixel[VGREEN] + alpha * green;
+            pixel[VBLUE]  = inv_alpha * pixel[VBLUE]  + alpha * blue;
+            break;
+        case STENCIL_BLEND_MODE_ADD:
+            // Add incoming color to the background image
+            pixel[VRED]   = llclampb(pixel[VRED]   + alpha * red);
+            pixel[VGREEN] = llclampb(pixel[VGREEN] + alpha * green);
+            pixel[VBLUE]  = llclampb(pixel[VBLUE]  + alpha * blue);
+            break;
+        case STENCIL_BLEND_MODE_ABACK:
+            // Add back background image to the incoming color
+            pixel[VRED]   = llclampb(inv_alpha * pixel[VRED]   + red);
+            pixel[VGREEN] = llclampb(inv_alpha * pixel[VGREEN] + green);
+            pixel[VBLUE]  = llclampb(inv_alpha * pixel[VBLUE]  + blue);
+            break;
+        case STENCIL_BLEND_MODE_FADE:
+            // Fade incoming color to black
+            pixel[VRED]   = alpha * red;
+            pixel[VGREEN] = alpha * green;
+            pixel[VBLUE]  = alpha * blue;
+            break;
+    }
+}
+
+void LLImageFilter::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue)
+{
+	const S32 components = mImage->getComponents();
+	llassert( components >= 1 && components <= 4 );
+    
+	S32 width  = mImage->getWidth();
+    S32 height = mImage->getHeight();
+    
+	U8* dst_data = mImage->getData();
+	for (S32 j = 0; j < height; j++)
+	{
+        for (S32 i = 0; i < width; i++)
+        {
+            // Blend LUT value
+            blendStencil(getStencilAlpha(i,j), dst_data, lut_red[dst_data[VRED]], lut_green[dst_data[VGREEN]], lut_blue[dst_data[VBLUE]]);
+            dst_data += components;
+        }
+	}
+}
+
+void LLImageFilter::colorTransform(const LLMatrix3 &transform)
+{
+	const S32 components = mImage->getComponents();
+	llassert( components >= 1 && components <= 4 );
+    
+	S32 width  = mImage->getWidth();
+    S32 height = mImage->getHeight();
+    
+	U8* dst_data = mImage->getData();
+	for (S32 j = 0; j < height; j++)
+	{
+        for (S32 i = 0; i < width; i++)
+        {
+            // Compute transform
+            LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE]));
+            LLVector3 dst = src * transform;
+            dst.clamp(0.0f,255.0f);
+            
+            // Blend result
+            blendStencil(getStencilAlpha(i,j), dst_data, dst.mV[VRED], dst.mV[VGREEN], dst.mV[VBLUE]);
+            dst_data += components;
+        }
+	}
+}
+
+void LLImageFilter::convolve(const LLMatrix3 &kernel, bool normalize, bool abs_value)
+{
+	const S32 components = mImage->getComponents();
+	llassert( components >= 1 && components <= 4 );
+    
+    // Compute normalization factors
+    F32 kernel_min = 0.0;
+    F32 kernel_max = 0.0;
+    for (S32 i = 0; i < NUM_VALUES_IN_MAT3; i++)
+    {
+        for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++)
+        {
+            if (kernel.mMatrix[i][j] >= 0.0)
+                kernel_max += kernel.mMatrix[i][j];
+            else
+                kernel_min += kernel.mMatrix[i][j];
+        }
+    }
+    if (abs_value)
+    {
+        kernel_max = llabs(kernel_max);
+        kernel_min = llabs(kernel_min);
+        kernel_max = llmax(kernel_max,kernel_min);
+        kernel_min = 0.0;
+    }
+    F32 kernel_range = kernel_max - kernel_min;
+    
+    // Allocate temporary buffers and initialize algorithm's data
+	S32 width  = mImage->getWidth();
+    S32 height = mImage->getHeight();
+    
+	U8* dst_data = mImage->getData();
+
+	S32 buffer_size = width * components;
+	llassert_always(buffer_size > 0);
+	std::vector<U8> even_buffer(buffer_size);
+	std::vector<U8> odd_buffer(buffer_size);
+	
+    U8* south_data = dst_data + buffer_size;
+    U8* east_west_data;
+    U8* north_data;
+    
+    // Line 0 : we set the line to 0 (debatable)
+    memcpy( &even_buffer[0], dst_data, buffer_size );	/* Flawfinder: ignore */
+    for (S32 i = 0; i < width; i++)
+    {
+        blendStencil(getStencilAlpha(i,0), dst_data, 0, 0, 0);
+        dst_data += components;
+    }
+    south_data += buffer_size;
+    
+    // All other lines
+    for (S32 j = 1; j < (height-1); j++)
+	{
+        // We need to buffer 2 lines. We flip north and east-west (current) to avoid moving too much memory around
+        if (j % 2)
+        {
+            memcpy( &odd_buffer[0], dst_data, buffer_size );	/* Flawfinder: ignore */
+            east_west_data = &odd_buffer[0];
+            north_data = &even_buffer[0];
+        }
+        else
+        {
+            memcpy( &even_buffer[0], dst_data, buffer_size );	/* Flawfinder: ignore */
+            east_west_data = &even_buffer[0];
+            north_data = &odd_buffer[0];
+        }
+        // First pixel : set to 0
+        blendStencil(getStencilAlpha(0,j), dst_data, 0, 0, 0);
+        dst_data += components;
+        // Set pointers to kernel
+        U8* NW = north_data;
+        U8* N = NW+components;
+        U8* NE = N+components;
+        U8* W = east_west_data;
+        U8* C = W+components;
+        U8* E = C+components;
+        U8* SW = south_data;
+        U8* S = SW+components;
+        U8* SE = S+components;
+        // All other pixels
+        for (S32 i = 1; i < (width-1); i++)
+        {
+            // Compute convolution
+            LLVector3 dst;
+            dst.mV[VRED] = (kernel.mMatrix[0][0]*NW[VRED] + kernel.mMatrix[0][1]*N[VRED] + kernel.mMatrix[0][2]*NE[VRED] +
+                            kernel.mMatrix[1][0]*W[VRED]  + kernel.mMatrix[1][1]*C[VRED] + kernel.mMatrix[1][2]*E[VRED] +
+                            kernel.mMatrix[2][0]*SW[VRED] + kernel.mMatrix[2][1]*S[VRED] + kernel.mMatrix[2][2]*SE[VRED]);
+            dst.mV[VGREEN] = (kernel.mMatrix[0][0]*NW[VGREEN] + kernel.mMatrix[0][1]*N[VGREEN] + kernel.mMatrix[0][2]*NE[VGREEN] +
+                              kernel.mMatrix[1][0]*W[VGREEN]  + kernel.mMatrix[1][1]*C[VGREEN] + kernel.mMatrix[1][2]*E[VGREEN] +
+                              kernel.mMatrix[2][0]*SW[VGREEN] + kernel.mMatrix[2][1]*S[VGREEN] + kernel.mMatrix[2][2]*SE[VGREEN]);
+            dst.mV[VBLUE] = (kernel.mMatrix[0][0]*NW[VBLUE] + kernel.mMatrix[0][1]*N[VBLUE] + kernel.mMatrix[0][2]*NE[VBLUE] +
+                             kernel.mMatrix[1][0]*W[VBLUE]  + kernel.mMatrix[1][1]*C[VBLUE] + kernel.mMatrix[1][2]*E[VBLUE] +
+                             kernel.mMatrix[2][0]*SW[VBLUE] + kernel.mMatrix[2][1]*S[VBLUE] + kernel.mMatrix[2][2]*SE[VBLUE]);
+            if (abs_value)
+            {
+                dst.mV[VRED]   = llabs(dst.mV[VRED]);
+                dst.mV[VGREEN] = llabs(dst.mV[VGREEN]);
+                dst.mV[VBLUE]  = llabs(dst.mV[VBLUE]);
+            }
+            if (normalize)
+            {
+                dst.mV[VRED]   = (dst.mV[VRED] - kernel_min)/kernel_range;
+                dst.mV[VGREEN] = (dst.mV[VGREEN] - kernel_min)/kernel_range;
+                dst.mV[VBLUE]  = (dst.mV[VBLUE] - kernel_min)/kernel_range;
+            }
+            dst.clamp(0.0f,255.0f);
+            
+            // Blend result
+            blendStencil(getStencilAlpha(i,j), dst_data, dst.mV[VRED], dst.mV[VGREEN], dst.mV[VBLUE]);
+            
+            // Next pixel
+            dst_data += components;
+            NW += components;
+            N += components;
+            NE += components;
+            W += components;
+            C += components;
+            E += components;
+            SW += components;
+            S += components;
+            SE += components;
+        }
+        // Last pixel : set to 0
+        blendStencil(getStencilAlpha(width-1,j), dst_data, 0, 0, 0);
+        dst_data += components;
+        south_data += buffer_size;
+	}
+    
+    // Last line
+    for (S32 i = 0; i < width; i++)
+    {
+        blendStencil(getStencilAlpha(i,0), dst_data, 0, 0, 0);
+        dst_data += components;
+    }
+}
+
+void LLImageFilter::filterScreen(EScreenMode mode, const F32 wave_length, const F32 angle)
+{
+	const S32 components = mImage->getComponents();
+	llassert( components >= 1 && components <= 4 );
+    
+	S32 width  = mImage->getWidth();
+    S32 height = mImage->getHeight();
+    
+    F32 wave_length_pixels = wave_length * (F32)(height) / 2.0;
+    F32 sin = sinf(angle*DEG_TO_RAD);
+    F32 cos = cosf(angle*DEG_TO_RAD);
+
+    // Precompute the gamma table : gives us the gray level to use when cutting outside the screen (prevents strong aliasing on the screen)
+    U8 gamma[256];
+    for (S32 i = 0; i < 256; i++)
+    {
+        F32 gamma_i = llclampf((float)(powf((float)(i)/255.0,1.0/4.0)));
+        gamma[i] = (U8)(255.0 * gamma_i);
+    }
+    
+	U8* dst_data = mImage->getData();
+	for (S32 j = 0; j < height; j++)
+	{
+        for (S32 i = 0; i < width; i++)
+        {
+            // Compute screen value
+            F32 value = 0.0;
+            F32 di = 0.0;
+            F32 dj = 0.0;
+            switch (mode)
+            {
+                case SCREEN_MODE_2DSINE:
+                    di =  cos*i + sin*j;
+                    dj = -sin*i + cos*j;
+                    value = (sinf(2*F_PI*di/wave_length_pixels)*sinf(2*F_PI*dj/wave_length_pixels)+1.0)*255.0/2.0;
+                    break;
+                case SCREEN_MODE_LINE:
+                    dj = sin*i - cos*j;
+                    value = (sinf(2*F_PI*dj/wave_length_pixels)+1.0)*255.0/2.0;
+                    break;
+            }
+            U8 dst_value = (dst_data[VRED] >= (U8)(value) ? gamma[dst_data[VRED] - (U8)(value)] : 0);
+            
+            // Blend result
+            blendStencil(getStencilAlpha(i,j), dst_data, dst_value, dst_value, dst_value);
+            dst_data += components;
+        }
+	}
+}
+
+//============================================================================
+// Procedural Stencils
+//============================================================================
+void LLImageFilter::setStencil(EStencilShape shape, EStencilBlendMode mode, F32 min, F32 max, F32* params)
+{
+    mStencilShape = shape;
+    mStencilBlendMode = mode;
+    mStencilMin = llmin(llmax(min, -1.0f), 1.0f);
+    mStencilMax = llmin(llmax(max, -1.0f), 1.0f);
+    
+    // Each shape will interpret the 4 params differenly.
+    // We compute each systematically, though, clearly, values are meaningless when the shape doesn't correspond to the parameters
+    mStencilCenterX = (S32)(mImage->getWidth()  + params[0] * (F32)(mImage->getHeight()))/2;
+    mStencilCenterY = (S32)(mImage->getHeight() + params[1] * (F32)(mImage->getHeight()))/2;
+    mStencilWidth = (S32)(params[2] * (F32)(mImage->getHeight()))/2;
+    mStencilGamma = (params[3] <= 0.0 ? 1.0 : params[3]);
+
+    mStencilWavelength = (params[0] <= 0.0 ? 10.0 : params[0] * (F32)(mImage->getHeight()) / 2.0);
+    mStencilSine   = sinf(params[1]*DEG_TO_RAD);
+    mStencilCosine = cosf(params[1]*DEG_TO_RAD);
+
+    mStencilStartX = ((F32)(mImage->getWidth())  + params[0] * (F32)(mImage->getHeight()))/2.0;
+    mStencilStartY = ((F32)(mImage->getHeight()) + params[1] * (F32)(mImage->getHeight()))/2.0;
+    F32 end_x      = ((F32)(mImage->getWidth())  + params[2] * (F32)(mImage->getHeight()))/2.0;
+    F32 end_y      = ((F32)(mImage->getHeight()) + params[3] * (F32)(mImage->getHeight()))/2.0;
+    mStencilGradX  = end_x - mStencilStartX;
+    mStencilGradY  = end_y - mStencilStartY;
+    mStencilGradN  = mStencilGradX*mStencilGradX + mStencilGradY*mStencilGradY;
+}
+
+F32 LLImageFilter::getStencilAlpha(S32 i, S32 j)
+{
+    F32 alpha = 1.0;    // That init actually takes care of the STENCIL_SHAPE_UNIFORM case...
+    if (mStencilShape == STENCIL_SHAPE_VIGNETTE)
+    {
+        // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges
+        // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0
+        F32 d_center_square = (i - mStencilCenterX)*(i - mStencilCenterX) + (j - mStencilCenterY)*(j - mStencilCenterY);
+        alpha = powf(F_E, -(powf((d_center_square/(mStencilWidth*mStencilWidth)),mStencilGamma)/2.0f));
+    }
+    else if (mStencilShape == STENCIL_SHAPE_SCAN_LINES)
+    {
+        // alpha varies according to a squared sine function.
+        F32 d = mStencilSine*i - mStencilCosine*j;
+        alpha = (sinf(2*F_PI*d/mStencilWavelength) > 0.0 ? 1.0 : 0.0);
+    }
+    else if (mStencilShape == STENCIL_SHAPE_GRADIENT)
+    {
+        alpha = (((F32)(i) - mStencilStartX)*mStencilGradX + ((F32)(j) - mStencilStartY)*mStencilGradY) / mStencilGradN;
+        alpha = llclampf(alpha);
+    }
+    
+    // We rescale alpha between min and max
+    return (mStencilMin + alpha * (mStencilMax - mStencilMin));
+}
+
+//============================================================================
+// Histograms
+//============================================================================
+
+U32* LLImageFilter::getBrightnessHistogram()
+{
+    if (!mHistoBrightness)
+    {
+        computeHistograms();
+    }
+    return mHistoBrightness;
+}
+
+void LLImageFilter::computeHistograms()
+{
+ 	const S32 components = mImage->getComponents();
+	llassert( components >= 1 && components <= 4 );
+    
+    // Allocate memory for the histograms
+    if (!mHistoRed)
+    {
+        mHistoRed = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+    }
+    if (!mHistoGreen)
+    {
+        mHistoGreen = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+    }
+    if (!mHistoBlue)
+    {
+        mHistoBlue = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+    }
+    if (!mHistoBrightness)
+    {
+        mHistoBrightness = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+    }
+    
+    // Initialize them
+    for (S32 i = 0; i < 256; i++)
+    {
+        mHistoRed[i] = 0;
+        mHistoGreen[i] = 0;
+        mHistoBlue[i] = 0;
+        mHistoBrightness[i] = 0;
+    }
+    
+    // Compute them
+	S32 pixels = mImage->getWidth() * mImage->getHeight();
+	U8* dst_data = mImage->getData();
+	for (S32 i = 0; i < pixels; i++)
+	{
+        mHistoRed[dst_data[VRED]]++;
+        mHistoGreen[dst_data[VGREEN]]++;
+        mHistoBlue[dst_data[VBLUE]]++;
+        // Note: this is a very simple shorthand for brightness but it's OK for our use
+        S32 brightness = ((S32)(dst_data[VRED]) + (S32)(dst_data[VGREEN]) + (S32)(dst_data[VBLUE])) / 3;
+        mHistoBrightness[brightness]++;
+        // next pixel...
+		dst_data += components;
+	}
+}
+
+//============================================================================
+// Secondary Filters
+//============================================================================
+
+void LLImageFilter::filterGrayScale()
+{
+    LLMatrix3 gray_scale;
+    LLVector3 luminosity(0.2125, 0.7154, 0.0721);
+    gray_scale.setRows(luminosity, luminosity, luminosity);
+    gray_scale.transpose();
+    colorTransform(gray_scale);
+}
+
+void LLImageFilter::filterSepia()
+{
+    LLMatrix3 sepia;
+    sepia.setRows(LLVector3(0.3588, 0.7044, 0.1368),
+                  LLVector3(0.2990, 0.5870, 0.1140),
+                  LLVector3(0.2392, 0.4696, 0.0912));
+    sepia.transpose();
+    colorTransform(sepia);
+}
+
+void LLImageFilter::filterSaturate(F32 saturation)
+{
+    // Matrix to Lij
+    LLMatrix3 r_a;
+    LLMatrix3 r_b;
+    
+    // 45 degre rotation around z
+    r_a.setRows(LLVector3( OO_SQRT2,  OO_SQRT2, 0.0),
+                LLVector3(-OO_SQRT2,  OO_SQRT2, 0.0),
+                LLVector3( 0.0,       0.0,      1.0));
+    // 54.73 degre rotation around y
+    float oo_sqrt3 = 1.0f / F_SQRT3;
+    float sin_54 = F_SQRT2 * oo_sqrt3;
+    r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54),
+                LLVector3(0.0,      1.0,  0.0),
+                LLVector3(sin_54,   0.0,  oo_sqrt3));
+    
+    // Coordinate conversion
+    LLMatrix3 Lij = r_b * r_a;
+    LLMatrix3 Lij_inv = Lij;
+    Lij_inv.transpose();
+    
+    // Local saturation transform
+    LLMatrix3 s;
+    s.setRows(LLVector3(saturation, 0.0,  0.0),
+              LLVector3(0.0,  saturation, 0.0),
+              LLVector3(0.0,        0.0,  1.0));
+    
+    // Global saturation transform
+    LLMatrix3 transfo = Lij_inv * s * Lij;
+    colorTransform(transfo);
+}
+
+void LLImageFilter::filterRotate(F32 angle)
+{
+    // Matrix to Lij
+    LLMatrix3 r_a;
+    LLMatrix3 r_b;
+    
+    // 45 degre rotation around z
+    r_a.setRows(LLVector3( OO_SQRT2,  OO_SQRT2, 0.0),
+                LLVector3(-OO_SQRT2,  OO_SQRT2, 0.0),
+                LLVector3( 0.0,       0.0,      1.0));
+    // 54.73 degre rotation around y
+    float oo_sqrt3 = 1.0f / F_SQRT3;
+    float sin_54 = F_SQRT2 * oo_sqrt3;
+    r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54),
+                LLVector3(0.0,      1.0,  0.0),
+                LLVector3(sin_54,   0.0,  oo_sqrt3));
+    
+    // Coordinate conversion
+    LLMatrix3 Lij = r_b * r_a;
+    LLMatrix3 Lij_inv = Lij;
+    Lij_inv.transpose();
+    
+    // Local color rotation transform
+    LLMatrix3 r;
+    angle *= DEG_TO_RAD;
+    r.setRows(LLVector3( cosf(angle), sinf(angle), 0.0),
+              LLVector3(-sinf(angle), cosf(angle), 0.0),
+              LLVector3( 0.0,         0.0,         1.0));
+    
+    // Global color rotation transform
+    LLMatrix3 transfo = Lij_inv * r * Lij;
+    colorTransform(transfo);
+}
+
+void LLImageFilter::filterGamma(F32 gamma, const LLColor3& alpha)
+{
+    U8 gamma_red_lut[256];
+    U8 gamma_green_lut[256];
+    U8 gamma_blue_lut[256];
+    
+    for (S32 i = 0; i < 256; i++)
+    {
+        F32 gamma_i = llclampf((float)(powf((float)(i)/255.0,1.0/gamma)));
+        // Blend in with alpha values
+        gamma_red_lut[i]   = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i);
+        gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i);
+        gamma_blue_lut[i]  = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0 * gamma_i);
+    }
+    
+    colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut);
+}
+
+void LLImageFilter::filterLinearize(F32 tail, const LLColor3& alpha)
+{
+    // Get the histogram
+    U32* histo = getBrightnessHistogram();
+    
+    // Compute cumulated histogram
+    U32 cumulated_histo[256];
+    cumulated_histo[0] = histo[0];
+    for (S32 i = 1; i < 256; i++)
+    {
+        cumulated_histo[i] = cumulated_histo[i-1] + histo[i];
+    }
+    
+    // Compute min and max counts minus tail
+    tail = llclampf(tail);
+    S32 total = cumulated_histo[255];
+    S32 min_c = (S32)((F32)(total) * tail);
+    S32 max_c = (S32)((F32)(total) * (1.0 - tail));
+    
+    // Find min and max values
+    S32 min_v = 0;
+    while (cumulated_histo[min_v] < min_c)
+    {
+        min_v++;
+    }
+    S32 max_v = 255;
+    while (cumulated_histo[max_v] > max_c)
+    {
+        max_v--;
+    }
+    
+    // Compute linear lookup table
+    U8 linear_red_lut[256];
+    U8 linear_green_lut[256];
+    U8 linear_blue_lut[256];
+    if (max_v == min_v)
+    {
+        // Degenerated binary split case
+        for (S32 i = 0; i < 256; i++)
+        {
+            U8 value_i = (i < min_v ? 0 : 255);
+            // Blend in with alpha values
+            linear_red_lut[i]   = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+            linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+            linear_blue_lut[i]  = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+        }
+    }
+    else
+    {
+        // Linearize between min and max
+        F32 slope = 255.0 / (F32)(max_v - min_v);
+        F32 translate = -min_v * slope;
+        for (S32 i = 0; i < 256; i++)
+        {
+            U8 value_i = (U8)(llclampb((S32)(slope*i + translate)));
+            // Blend in with alpha values
+            linear_red_lut[i]   = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+            linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+            linear_blue_lut[i]  = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+        }
+    }
+    
+    // Apply lookup table
+    colorCorrect(linear_red_lut,linear_green_lut,linear_blue_lut);
+}
+
+void LLImageFilter::filterEqualize(S32 nb_classes, const LLColor3& alpha)
+{
+    // Regularize the parameter: must be between 2 and 255
+    nb_classes = llmax(nb_classes,2);
+    nb_classes = llclampb(nb_classes);
+    
+    // Get the histogram
+    U32* histo = getBrightnessHistogram();
+    
+    // Compute cumulated histogram
+    U32 cumulated_histo[256];
+    cumulated_histo[0] = histo[0];
+    for (S32 i = 1; i < 256; i++)
+    {
+        cumulated_histo[i] = cumulated_histo[i-1] + histo[i];
+    }
+    
+    // Compute deltas
+    S32 total = cumulated_histo[255];
+    S32 delta_count = total / nb_classes;
+    S32 current_count = delta_count;
+    S32 delta_value = 256 / (nb_classes - 1);
+    S32 current_value = 0;
+    
+    // Compute equalized lookup table
+    U8 equalize_red_lut[256];
+    U8 equalize_green_lut[256];
+    U8 equalize_blue_lut[256];
+    for (S32 i = 0; i < 256; i++)
+    {
+        // Blend in current_value with alpha values
+        equalize_red_lut[i]   = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value);
+        equalize_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value);
+        equalize_blue_lut[i]  = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value);
+        if (cumulated_histo[i] >= current_count)
+        {
+            current_count += delta_count;
+            current_value += delta_value;
+            current_value = llclampb(current_value);
+        }
+    }
+    
+    // Apply lookup table
+    colorCorrect(equalize_red_lut,equalize_green_lut,equalize_blue_lut);
+}
+
+void LLImageFilter::filterColorize(const LLColor3& color, const LLColor3& alpha)
+{
+    U8 red_lut[256];
+    U8 green_lut[256];
+    U8 blue_lut[256];
+    
+    F32 red_composite   =  255.0 * alpha.mV[0] * color.mV[0];
+    F32 green_composite =  255.0 * alpha.mV[1] * color.mV[1];
+    F32 blue_composite  =  255.0 * alpha.mV[2] * color.mV[2];
+    
+    for (S32 i = 0; i < 256; i++)
+    {
+        red_lut[i]   = (U8)(llclampb((S32)((1.0 - alpha.mV[0]) * (F32)(i) + red_composite)));
+        green_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[1]) * (F32)(i) + green_composite)));
+        blue_lut[i]  = (U8)(llclampb((S32)((1.0 - alpha.mV[2]) * (F32)(i) + blue_composite)));
+    }
+    
+    colorCorrect(red_lut,green_lut,blue_lut);
+}
+
+void LLImageFilter::filterContrast(F32 slope, const LLColor3& alpha)
+{
+    U8 contrast_red_lut[256];
+    U8 contrast_green_lut[256];
+    U8 contrast_blue_lut[256];
+    
+    F32 translate = 128.0 * (1.0 - slope);
+    
+    for (S32 i = 0; i < 256; i++)
+    {
+        U8 value_i = (U8)(llclampb((S32)(slope*i + translate)));
+        // Blend in with alpha values
+        contrast_red_lut[i]   = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+        contrast_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+        contrast_blue_lut[i]  = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+    }
+    
+    colorCorrect(contrast_red_lut,contrast_green_lut,contrast_blue_lut);
+}
+
+void LLImageFilter::filterBrightness(F32 add, const LLColor3& alpha)
+{
+    U8 brightness_red_lut[256];
+    U8 brightness_green_lut[256];
+    U8 brightness_blue_lut[256];
+    
+    S32 add_value = (S32)(add * 255.0);
+    
+    for (S32 i = 0; i < 256; i++)
+    {
+        U8 value_i = (U8)(llclampb(i + add_value));
+        // Blend in with alpha values
+        brightness_red_lut[i]   = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+        brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+        brightness_blue_lut[i]  = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+    }
+    
+    colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut);
+}
+
+//============================================================================
diff --git a/indra/llimage/llimagefilter.h b/indra/llimage/llimagefilter.h
new file mode 100755
index 0000000000000000000000000000000000000000..16ec395f766763490fd8bc415a4a4f880cf4ed0e
--- /dev/null
+++ b/indra/llimage/llimagefilter.h
@@ -0,0 +1,137 @@
+/** 
+ * @file llimagefilter.h
+ * @brief Simple Image Filtering. See https://wiki.lindenlab.com/wiki/SL_Viewer_Image_Filters for complete documentation.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2014, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLIMAGEFILTER_H
+#define LL_LLIMAGEFILTER_H
+
+#include "llsd.h"
+#include "llimage.h"
+
+class LLImageRaw;
+class LLColor4U;
+class LLColor3;
+class LLMatrix3;
+
+typedef enum e_stencil_blend_mode
+{
+	STENCIL_BLEND_MODE_BLEND = 0,
+	STENCIL_BLEND_MODE_ADD   = 1,
+	STENCIL_BLEND_MODE_ABACK = 2,
+	STENCIL_BLEND_MODE_FADE  = 3
+} EStencilBlendMode;
+
+typedef enum e_stencil_shape
+{
+	STENCIL_SHAPE_UNIFORM    = 0,
+	STENCIL_SHAPE_GRADIENT   = 1,
+	STENCIL_SHAPE_VIGNETTE   = 2,
+	STENCIL_SHAPE_SCAN_LINES = 3
+} EStencilShape;
+
+typedef enum e_screen_mode
+{
+	SCREEN_MODE_2DSINE   = 0,
+	SCREEN_MODE_LINE     = 1
+} EScreenMode;
+
+//============================================================================
+// LLImageFilter 
+//============================================================================
+
+class LLImageFilter
+{
+public:
+    LLImageFilter(const std::string& file_path);
+    ~LLImageFilter();
+    
+    void executeFilter(LLPointer<LLImageRaw> raw_image);
+    
+private:
+    // Filter Operations : Transforms
+    void filterGrayScale();                         // Convert to grayscale
+    void filterSepia();                             // Convert to sepia
+    void filterSaturate(F32 saturation);            // < 1.0 desaturates, > 1.0 saturates
+    void filterRotate(F32 angle);                   // Rotates hue according to angle, angle in degrees
+    
+    // Filter Operations : Color Corrections
+    // When specified, the LLColor3 alpha parameter indicates the intensity of the effect for each color channel
+    // acting in effect as an alpha blending factor different for each channel. For instance (1.0,0.0,0.0) will apply
+    // the effect only to the Red channel. Intermediate values blends the effect with the source color.
+    void filterGamma(F32 gamma, const LLColor3& alpha);         // Apply gamma to each channel
+    void filterLinearize(F32 tail, const LLColor3& alpha);      // Use histogram to linearize constrast between min and max values minus tail
+    void filterEqualize(S32 nb_classes, const LLColor3& alpha); // Use histogram to equalize constrast between nb_classes throughout the image
+    void filterColorize(const LLColor3& color, const LLColor3& alpha);  // Colorize with color and alpha per channel
+    void filterContrast(F32 slope, const LLColor3& alpha);      // Change contrast according to slope: > 1.0 more contrast, < 1.0 less contrast
+    void filterBrightness(F32 add, const LLColor3& alpha);      // Change brightness according to add: > 0 brighter, < 0 darker
+    
+    // Filter Primitives
+    void colorTransform(const LLMatrix3 &transform);
+    void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue);
+    void filterScreen(EScreenMode mode, const F32 wave_length, const F32 angle);
+    void blendStencil(F32 alpha, U8* pixel, U8 red, U8 green, U8 blue);
+    void convolve(const LLMatrix3 &kernel, bool normalize, bool abs_value);
+
+    // Procedural Stencils
+    void setStencil(EStencilShape shape, EStencilBlendMode mode, F32 min, F32 max, F32* params);
+    F32 getStencilAlpha(S32 i, S32 j);
+
+    // Histograms
+    U32* getBrightnessHistogram();
+    void computeHistograms();
+
+    LLSD mFilterData;
+    LLPointer<LLImageRaw> mImage;
+
+    // Histograms (if we ever happen to need them)
+    U32 *mHistoRed;
+    U32 *mHistoGreen;
+    U32 *mHistoBlue;
+    U32 *mHistoBrightness;
+    
+    // Current Stencil Settings
+    EStencilBlendMode mStencilBlendMode;
+    EStencilShape mStencilShape;
+    F32 mStencilMin;
+    F32 mStencilMax;
+    
+    S32 mStencilCenterX;
+    S32 mStencilCenterY;
+    S32 mStencilWidth;
+    F32 mStencilGamma;
+    
+    F32 mStencilWavelength;
+    F32 mStencilSine;
+    F32 mStencilCosine;
+    
+    F32 mStencilStartX;
+    F32 mStencilStartY;
+    F32 mStencilGradX;
+    F32 mStencilGradY;
+    F32 mStencilGradN;
+};
+
+
+#endif
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 40b177670892405d1d289d924ef895e608fba28f..02eb21917c8bbaa19795abc28851e704a26c49b2 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -199,6 +199,7 @@ set(viewer_SOURCE_FILES
     llfilteredwearablelist.cpp
     llfirstuse.cpp
     llflexibleobject.cpp
+    llflickrconnect.cpp
     llfloaterabout.cpp
     llfloaterbvhpreview.cpp
     llfloaterauction.cpp
@@ -207,6 +208,7 @@ set(viewer_SOURCE_FILES
     llfloateravatarpicker.cpp
     llfloateravatartextures.cpp
     llfloaterbeacons.cpp
+    llfloaterbigpreview.cpp
     llfloaterbuildoptions.cpp
     llfloaterbulkpermission.cpp
     llfloaterbump.cpp
@@ -228,6 +230,8 @@ set(viewer_SOURCE_FILES
     llfloatereditwater.cpp
     llfloaterenvironmentsettings.cpp
     llfloaterevent.cpp
+    llfloaterfacebook.cpp
+    llfloaterflickr.cpp
     llfloaterfonttest.cpp
     llfloatergesture.cpp
     llfloatergodtools.cpp
@@ -279,7 +283,6 @@ set(viewer_SOURCE_FILES
     llfloatersettingsdebug.cpp
     llfloatersidepanelcontainer.cpp
     llfloatersnapshot.cpp
-    llfloatersocial.cpp
     llfloatersounddevices.cpp
     llfloaterspellchecksettings.cpp
     llfloatertelehub.cpp
@@ -291,6 +294,7 @@ set(viewer_SOURCE_FILES
     llfloatertos.cpp
     llfloatertoybox.cpp
     llfloatertranslationsettings.cpp
+    llfloatertwitter.cpp
     llfloateruipreview.cpp
     llfloaterurlentry.cpp
     llfloatervoiceeffect.cpp
@@ -328,6 +332,7 @@ set(viewer_SOURCE_FILES
     llhudrender.cpp
     llhudtext.cpp
     llhudview.cpp
+    llimagefiltersmanager.cpp
     llimhandler.cpp
     llimview.cpp
     llinspect.cpp
@@ -573,6 +578,7 @@ set(viewer_SOURCE_FILES
     lltransientdockablefloater.cpp
     lltransientfloatermgr.cpp
     lltranslate.cpp
+    lltwitterconnect.cpp
     lluilistener.cpp
     lluploaddialog.cpp
     lluploadfloaterobservers.cpp
@@ -794,6 +800,7 @@ set(viewer_HEADER_FILES
     llfilteredwearablelist.h
     llfirstuse.h
     llflexibleobject.h
+    llflickrconnect.h
     llfloaterabout.h
     llfloaterbvhpreview.h
     llfloaterauction.h
@@ -802,6 +809,7 @@ set(viewer_HEADER_FILES
     llfloateravatarpicker.h
     llfloateravatartextures.h
     llfloaterbeacons.h
+    llfloaterbigpreview.h
     llfloaterbuildoptions.h
     llfloaterbulkpermission.h
     llfloaterbump.h
@@ -823,6 +831,8 @@ set(viewer_HEADER_FILES
     llfloatereditwater.h
     llfloaterenvironmentsettings.h
     llfloaterevent.h
+    llfloaterfacebook.h
+    llfloaterflickr.h
     llfloaterfonttest.h
     llfloatergesture.h
     llfloatergodtools.h
@@ -877,7 +887,6 @@ set(viewer_HEADER_FILES
     llfloatersettingsdebug.h
     llfloatersidepanelcontainer.h
     llfloatersnapshot.h
-    llfloatersocial.h
     llfloatersounddevices.h
     llfloaterspellchecksettings.h
     llfloatertelehub.h
@@ -889,6 +898,7 @@ set(viewer_HEADER_FILES
     llfloatertos.h
     llfloatertoybox.h
     llfloatertranslationsettings.h
+    llfloatertwitter.h
     llfloateruipreview.h
     llfloaterurlentry.h
     llfloatervoiceeffect.h
@@ -925,6 +935,7 @@ set(viewer_HEADER_FILES
     llhudrender.h
     llhudtext.h
     llhudview.h
+    llimagefiltersmanager.h
     llimview.h
     llinspect.h
     llinspectavatar.h
@@ -1159,6 +1170,7 @@ set(viewer_HEADER_FILES
     lltransientdockablefloater.h
     lltransientfloatermgr.h
     lltranslate.h
+    lltwitterconnect.h
     lluiconstants.h
     lluilistener.h
     lluploaddialog.h
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index f06fb9e9156b751b9baf03ccda308f325d4cb825..584a914c296b21f1d3857a0d09365a73fb64ede2 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.7.10
+3.7.11
diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml
index 60c942094aad44fcc98f66c0a29ae3da1975dfd2..7b329e2092a0fc7dbc1b318d3145fd325fd2d3b2 100755
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -216,15 +216,35 @@
            is_running_function="Floater.IsOpen"
            is_running_parameters="snapshot"
            />
-  <command name="social"
+  <command name="facebook"
            available_in_toybox="true"
-           icon="Command_Social_Icon"
-           label_ref="Command_Social_Label"
-           tooltip_ref="Command_Social_Tooltip"
+           icon="Command_Facebook_Icon"
+           label_ref="Command_Facebook_Label"
+           tooltip_ref="Command_Facebook_Tooltip"
            execute_function="Floater.ToggleOrBringToFront"
-           execute_parameters="social"
+           execute_parameters="facebook"
            is_running_function="Floater.IsOpen"
-           is_running_parameters="social"
+           is_running_parameters="facebook"
+           />
+  <command name="flickr"
+           available_in_toybox="true"
+           icon="Command_Flickr_Icon"
+           label_ref="Command_Flickr_Label"
+           tooltip_ref="Command_Flickr_Tooltip"
+           execute_function="Floater.ToggleOrBringToFront"
+           execute_parameters="flickr"
+           is_running_function="Floater.IsOpen"
+           is_running_parameters="flickr"
+           />
+  <command name="twitter"
+           available_in_toybox="true"
+           icon="Command_Twitter_Icon"
+           label_ref="Command_Twitter_Label"
+           tooltip_ref="Command_Twitter_Tooltip"
+           execute_function="Floater.ToggleOrBringToFront"
+           execute_parameters="twitter"
+           is_running_function="Floater.IsOpen"
+           is_running_parameters="twitter"
            />
   <command name="speak"
            available_in_toybox="true"
diff --git a/indra/newview/app_settings/filters/Autocontrast.xml b/indra/newview/app_settings/filters/Autocontrast.xml
new file mode 100755
index 0000000000000000000000000000000000000000..ec3d7561bdcf6e662397f21cde040ed26897752b
--- /dev/null
+++ b/indra/newview/app_settings/filters/Autocontrast.xml
@@ -0,0 +1,11 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/BlackAndWhite.xml b/indra/newview/app_settings/filters/BlackAndWhite.xml
new file mode 100644
index 0000000000000000000000000000000000000000..101ed8233ab550e0809be18fedf9b55ebcbe108b
--- /dev/null
+++ b/indra/newview/app_settings/filters/BlackAndWhite.xml
@@ -0,0 +1,21 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.8</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Colors1970.xml b/indra/newview/app_settings/filters/Colors1970.xml
new file mode 100644
index 0000000000000000000000000000000000000000..730d907fa76ff6e5c74f41ab6f2524bb40524c9c
--- /dev/null
+++ b/indra/newview/app_settings/filters/Colors1970.xml
@@ -0,0 +1,47 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.8</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.3</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>10.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.1</real>
+            <real>0.1</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Intense.xml b/indra/newview/app_settings/filters/Intense.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b77f07a0374b0f6143b59761758483b7ecc80453
--- /dev/null
+++ b/indra/newview/app_settings/filters/Intense.xml
@@ -0,0 +1,8 @@
+<llsd>
+    <array>
+        <array>
+            <string>saturate</string>
+            <real>3.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/LensFlare.xml b/indra/newview/app_settings/filters/LensFlare.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9aef6eea403402b4f2de04a7c4c5cfb78f05a7a
--- /dev/null
+++ b/indra/newview/app_settings/filters/LensFlare.xml
@@ -0,0 +1,131 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>add</string>
+            <real>0.5</real>
+            <real>0.0</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>-1.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.1</real>
+            <real>0.1</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.5</real>
+            <real>5.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.6</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>-1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>5.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.6</real>
+            <real>0.6</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>-0.5</real>
+            <real>0.10</real>
+            <real>20.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.7</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.6</real>
+            <real>-0.6</real>
+            <real>0.05</real>
+            <real>20.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.7</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>0.4</real>
+            <real>-0.4</real>
+            <real>0.025</real>
+            <real>20.0</real>
+        </array>
+        <array>
+            <string>colorize</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>0.7</real>
+            <real>0.0</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Miniature.xml b/indra/newview/app_settings/filters/Miniature.xml
new file mode 100755
index 0000000000000000000000000000000000000000..9aa8a87c6f470e7b581a3773a233ce6eaf5f83a7
--- /dev/null
+++ b/indra/newview/app_settings/filters/Miniature.xml
@@ -0,0 +1,118 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.02</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.02</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>saturate</string>
+            <real>1.2</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>0.0</real>
+            <real>0.25</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.25</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>sharpen</string>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>-1.0</real>
+            <real>0.0</real>
+            <real>-0.25</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>gradient</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.25</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
\ No newline at end of file
diff --git a/indra/newview/app_settings/filters/Newspaper.xml b/indra/newview/app_settings/filters/Newspaper.xml
new file mode 100755
index 0000000000000000000000000000000000000000..6cfe3192814664e186b87ec77b9b36efba341c8b
--- /dev/null
+++ b/indra/newview/app_settings/filters/Newspaper.xml
@@ -0,0 +1,20 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>2Dsine</string>
+            <real>0.02</real>
+            <real>0.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Sepia.xml b/indra/newview/app_settings/filters/Sepia.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3d577b2998115d6660619732d5bdf89b00819b9d
--- /dev/null
+++ b/indra/newview/app_settings/filters/Sepia.xml
@@ -0,0 +1,32 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.01</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>0.8</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>fade</string>
+            <real>0.5</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>4.0</real>
+        </array>
+        <array>
+            <string>sepia</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Spotlight.xml b/indra/newview/app_settings/filters/Spotlight.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0e2e0ad68c0fc4abace1dc38b9ed58c74e8822a7
--- /dev/null
+++ b/indra/newview/app_settings/filters/Spotlight.xml
@@ -0,0 +1,47 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.4</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>add</string>
+            <real>-0.8</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Toycamera.xml b/indra/newview/app_settings/filters/Toycamera.xml
new file mode 100755
index 0000000000000000000000000000000000000000..4e76f6b2fbe950921382fbb6baa16025b948fb86
--- /dev/null
+++ b/indra/newview/app_settings/filters/Toycamera.xml
@@ -0,0 +1,46 @@
+<llsd>
+    <array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>fade</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>1.2</real>
+            <real>3.0</real>
+        </array>
+        <array>
+            <string>linearize</string>
+            <real>0.05</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>grayscale</string>
+        </array>
+        <array>
+            <string>contrast</string>
+            <real>1.1</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>vignette</string>
+            <string>blend</string>
+            <real>1.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.0</real>
+            <real>0.5</real>
+            <real>2.0</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
\ No newline at end of file
diff --git a/indra/newview/app_settings/filters/Video.xml b/indra/newview/app_settings/filters/Video.xml
new file mode 100755
index 0000000000000000000000000000000000000000..fe17f3950a18e1b647739eecd1db48700e912f96
--- /dev/null
+++ b/indra/newview/app_settings/filters/Video.xml
@@ -0,0 +1,44 @@
+<llsd>
+    <array>
+        <array>
+            <string>linearize</string>
+            <real>0.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>darken</string>
+            <real>0.15</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>stencil</string>
+            <string>uniform</string>
+            <string>add</string>
+            <real>0.0</real>
+            <real>0.5</real>
+        </array>
+        <array>
+            <string>screen</string>
+            <string>line</string>
+            <real>0.02</real>
+            <real>0.0</real>
+        </array>
+        <array>
+            <string>gamma</string>
+            <real>0.25</real>
+            <real>1.0</real>
+            <real>1.0</real>
+            <real>1.0</real>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+        <array>
+            <string>blur</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c5d7689b9563e39586d71e67f43cd5023bdba6ff..1068247833bd5f68f78261b4619f6a57e2b6cb73 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11495,6 +11495,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>SnapshotFiltersEnabled</key>
+    <map>
+        <key>Comment</key>
+        <string>Enable filters in the Snapshot Advanced panel (experimental).</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>Boolean</string>
+        <key>Value</key>
+        <integer>0</integer>
+    </map>
     <key>SnapshotFormat</key>
     <map>
       <key>Comment</key>
@@ -13313,7 +13324,7 @@
     <key>SocialPhotoResolution</key>
     <map>
       <key>Comment</key>
-      <string>Default resolution when sharing photo using the social floater</string>
+      <string>Default resolution when sharing photo using the social floaters</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml
index 86f99128156335e29c9951d10754a7541094062e..d61aee9a14060b5748f14b928992fad5d6248772 100755
--- a/indra/newview/app_settings/toolbars.xml
+++ b/indra/newview/app_settings/toolbars.xml
@@ -6,7 +6,6 @@
     <command name="speak"/>
     <command name="destinations"/>
     <command name="people"/>
-    <command name="social"/>
     <command name="profile"/>
     <command name="move"/>
     <command name="view"/>
@@ -22,5 +21,6 @@
     <command name="voice"/>
     <command name="minimap"/>
     <command name="snapshot"/>
+    <command name="facebook"/>
   </left_toolbar>
 </toolbars>
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
index e2fa117453fae7d9db2c44006e4863fbe4e83bfc..28319564e456863841255be346c1a780b220a4d3 100755
--- a/indra/newview/llfacebookconnect.cpp
+++ b/indra/newview/llfacebookconnect.cpp
@@ -28,6 +28,8 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llfacebookconnect.h"
+#include "llflickrconnect.h"
+#include "lltwitterconnect.h"
 
 #include "llagent.h"
 #include "llcallingcard.h"			// for LLAvatarTracker
@@ -58,7 +60,7 @@ void log_facebook_connect_error(const std::string& request, U32 status, const st
     }
 }
 
-void toast_user_for_success()
+void toast_user_for_facebook_success()
 {
 	LLSD args;
     args["MESSAGE"] = LLTrans::getString("facebook_post_success");
@@ -74,23 +76,46 @@ class LLFacebookConnectHandler : public LLCommandHandler
     
 	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
 	{
-		if (tokens.size() > 0)
+		if (tokens.size() >= 1)
 		{
 			if (tokens[0].asString() == "connect")
 			{
-				// this command probably came from the fbc_web browser, so close it
-				LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web");
-				if (fbc_web)
+				if (tokens.size() >= 2 && tokens[1].asString() == "flickr")
 				{
-					fbc_web->closeFloater();
+					// this command probably came from the flickr_web browser, so close it
+					LLFloaterReg::hideInstance("flickr_web");
+
+					// connect to flickr
+					if (query_map.has("oauth_token"))
+					{
+						LLFlickrConnect::instance().connectToFlickr(query_map["oauth_token"], query_map.get("oauth_verifier"));
+					}
+					return true;
 				}
-
-				// connect to facebook
-				if (query_map.has("code"))
+				else if (tokens.size() >= 2 && tokens[1].asString() == "twitter")
+				{
+					// this command probably came from the twitter_web browser, so close it
+					LLFloaterReg::hideInstance("twitter_web");
+
+					// connect to twitter
+					if (query_map.has("oauth_token"))
+					{
+						LLTwitterConnect::instance().connectToTwitter(query_map["oauth_token"], query_map.get("oauth_verifier"));
+					}
+					return true;
+				}
+				else //if (tokens.size() >= 2 && tokens[1].asString() == "facebook")
 				{
-                    LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state"));
+					// this command probably came from the fbc_web browser, so close it
+					LLFloaterReg::hideInstance("fbc_web");
+
+					// connect to facebook
+					if (query_map.has("code"))
+					{
+						LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state"));
+					}
+					return true;
 				}
-				return true;
 			}
 		}
 		return false;
@@ -156,7 +181,7 @@ class LLFacebookShareResponder : public LLHTTPClient::Responder
 
 	/* virtual */ void httpSuccess()
 	{
-		toast_user_for_success();
+		toast_user_for_facebook_success();
 		LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
 		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED);
 	}
@@ -302,9 +327,16 @@ class LLFacebookInfoResponder : public LLHTTPClient::Responder
 	{
 		if ( HTTP_FOUND == getStatus() )
 		{
-			LL_INFOS() << "Facebook: Info received" << LL_ENDL;
-			LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << getContent() << LL_ENDL;
-			LLFacebookConnect::instance().storeInfo(getContent());
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+				LLFacebookConnect::instance().openFacebookWeb(location);
+			}
 		}
 		else
 		{
@@ -371,10 +403,12 @@ void LLFacebookConnect::openFacebookWeb(std::string url)
 {
 	// Open the URL in an internal browser window without navigation UI
 	LLFloaterWebContent::Params p;
-    p.url(url).show_chrome(true);
-    p.url(url).allow_address_entry(false);
-    p.url(url).allow_back_forward_navigation(false);
-    p.url(url).trusted_content(true);
+    p.url(url);
+    p.show_chrome(true);
+    p.allow_address_entry(false);
+    p.allow_back_forward_navigation(false);
+    p.trusted_content(true);
+    p.clean_browser(true);
 	LLFloater *floater = LLFloaterReg::showInstance("fbc_web", p);
 	//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
 	//So when showing the internal web browser, set focus to it's containing floater "fbc_web". When a mouse event 
@@ -391,7 +425,8 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b
     LLViewerRegion *regionp = gAgent.getRegion();
     if (regionp)
     {
-        url = regionp->getCapability("FacebookConnect");
+		//url = "http://pdp15.lindenlab.com/fbc/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO
+		url = regionp->getCapability("FacebookConnect");
         url += route;
     
         if (include_read_from_master && mReadFromMaster)
@@ -406,9 +441,13 @@ void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const st
 {
 	LLSD body;
 	if (!auth_code.empty())
+    {
 		body["code"] = auth_code;
+    }
 	if (!auth_state.empty())
+    {
 		body["state"] = auth_state;
+    }
     
 	LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder());
 }
@@ -452,15 +491,25 @@ void LLFacebookConnect::postCheckin(const std::string& location, const std::stri
 {
 	LLSD body;
 	if (!location.empty())
+    {
 		body["location"] = location;
+    }
 	if (!name.empty())
+    {
 		body["name"] = name;
+    }
 	if (!description.empty())
+    {
 		body["description"] = description;
+    }
 	if (!image.empty())
+    {
 		body["image"] = image;
+    }
 	if (!message.empty())
+    {
 		body["message"] = message;
+    }
 
 	// Note: we can use that route for different publish action. We should be able to use the same responder.
 	LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder());
@@ -507,7 +556,7 @@ void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std:
 			<< caption << "\r\n";
 
 	body	<< "--" << boundary << "\r\n"
-			<< "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << imageFormat << "\"\r\n"
+			<< "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
 			<< "Content-Type: image/" << imageFormat << "\r\n\r\n";
 
 	// Insert the image data.
@@ -599,12 +648,13 @@ void LLFacebookConnect::setConnectionState(LLFacebookConnect::EConnectionState c
 
 	if (mConnectionState != connection_state)
 	{
+		// set the connection state before notifying watchers
+		mConnectionState = connection_state;
+
 		LLSD state_info;
 		state_info["enum"] = connection_state;
 		sStateWatcher->post(state_info);
 	}
-	
-	mConnectionState = connection_state;
 }
 
 void LLFacebookConnect::setConnected(bool connected)
diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h
index a77ac2416738b6ad6c8693aa91e00dc912fa59f8..c157db21781b7ff101297656f62dd5e4b0e128c2 100644
--- a/indra/newview/llfacebookconnect.h
+++ b/indra/newview/llfacebookconnect.h
@@ -89,7 +89,7 @@ class LLFacebookConnect : public LLSingleton<LLFacebookConnect>
 	LLFacebookConnect();
 	~LLFacebookConnect() {};
  	std::string getFacebookConnectURL(const std::string& route = "", bool include_read_from_master = false);
-   
+
     EConnectionState mConnectionState;
 	BOOL mConnected;
 	LLSD mInfo;
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index a7f5cd9dacde14ce1906551daaac20f16735fcd3..5debf7174473ea99a6a6168cd124a50a979afc0e 100755
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -167,7 +167,8 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
 	BOOL res = TRUE;
 	switch (filter)
 	{
-	case FFLOAD_ALL:
+    case FFLOAD_ALL:
+    case FFLOAD_EXE:
 		mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \
 		SOUND_FILTER \
 		IMAGE_FILTER \
@@ -580,6 +581,10 @@ std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) //
             allowedv->push_back("tpic");
             allowedv->push_back("png");
             break;
+        case FFLOAD_EXE:
+            allowedv->push_back("app");
+            allowedv->push_back("exe");
+            break;
         case FFLOAD_WAV:
             allowedv->push_back("wav");
             break;
@@ -778,7 +783,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
         mPickOptions &= ~F_FILE;
     }
 
-	if(filter == FFLOAD_ALL)	// allow application bundles etc. to be traversed; important for DEV-16869, but generally useful
+	if (filter == FFLOAD_ALL)	// allow application bundles etc. to be traversed; important for DEV-16869, but generally useful
 	{
         mPickOptions |= F_NAV_SUPPORT;
 	}
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index f6a700d1c6e772ceb54b41c4671df16accc2dc63..0e0cec39439ee916b598281ff82947b9f57afa46 100755
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -87,7 +87,8 @@ class LLFilePicker
 		FFLOAD_COLLADA = 10,
 		FFLOAD_SCRIPT = 11,
 		FFLOAD_DICTIONARY = 12,
-        FFLOAD_DIRECTORY = 13   //To call from lldirpicker. 
+        FFLOAD_DIRECTORY = 13,   // To call from lldirpicker.
+        FFLOAD_EXE = 14          // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin
 	};
 
 	enum ESaveFilter
diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b7158962648ccaff0c5efa76880995d8000f120b
--- /dev/null
+++ b/indra/newview/llflickrconnect.cpp
@@ -0,0 +1,509 @@
+/** 
+ * @file llflickrconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Flickr Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llflickrconnect.h"
+
+#include "llagent.h"
+#include "llcallingcard.h"			// for LLAvatarTracker
+#include "llcommandhandler.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
+#include "llurlaction.h"
+#include "llimagepng.h"
+#include "llimagejpeg.h"
+#include "lltrans.h"
+#include "llevents.h"
+#include "llviewerregion.h"
+
+#include "llfloaterwebcontent.h"
+#include "llfloaterreg.h"
+
+boost::scoped_ptr<LLEventPump> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState"));
+boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo"));
+boost::scoped_ptr<LLEventPump> LLFlickrConnect::sContentWatcher(new LLEventStream("FlickrConnectContent"));
+
+// Local functions
+void log_flickr_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
+{
+    // Note: 302 (redirect) is *not* an error that warrants logging
+    if (status != 302)
+    {
+		LL_WARNS("FlickrConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL;
+    }
+}
+
+void toast_user_for_flickr_success()
+{
+	LLSD args;
+    args["MESSAGE"] = LLTrans::getString("flickr_post_success");
+    LLNotificationsUtil::add("FlickrConnect", args);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrConnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrConnectResponder);
+public:
+	
+    LLFlickrConnectResponder()
+    {
+        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+    }
+    
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
+        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		if ( HTTP_FOUND == getStatus() )
+		{
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+                LLFlickrConnect::instance().openFlickrWeb(location);
+			}
+		}
+		else
+		{
+			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+			const LLSD& content = getContent();
+			log_flickr_connect_error("Connect", getStatus(), getReason(),
+                                      content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrShareResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrShareResponder);
+public:
+    
+	LLFlickrShareResponder()
+	{
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTING);
+	}
+	
+	/* virtual */ void httpSuccess()
+	{
+        toast_user_for_flickr_success();
+		LL_DEBUGS("FlickrConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
+        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTED);
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		if ( HTTP_FOUND == getStatus() )
+		{
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+                LLFlickrConnect::instance().openFlickrWeb(location);
+			}
+		}
+		else if ( HTTP_NOT_FOUND == getStatus() )
+		{
+			LLFlickrConnect::instance().connectToFlickr();
+		}
+		else
+		{
+			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED);
+			const LLSD& content = getContent();
+			log_flickr_connect_error("Share", getStatus(), getReason(),
+                                      content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrDisconnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrDisconnectResponder);
+public:
+ 
+	LLFlickrDisconnectResponder()
+	{
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING);
+	}
+
+	void setUserDisconnected()
+	{
+		// Clear data
+		LLFlickrConnect::instance().clearInfo();
+
+		//Notify state change
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
+	}
+
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL;
+		setUserDisconnected();
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		//User not found so already disconnected
+		if ( HTTP_NOT_FOUND == getStatus() )
+		{
+			LL_DEBUGS("FlickrConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;
+			setUserDisconnected();
+		}
+		else
+		{
+			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
+			LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED);
+			const LLSD& content = getContent();
+			log_flickr_connect_error("Disconnect", getStatus(), getReason(),
+                                      content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrConnectedResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrConnectedResponder);
+public:
+    
+	LLFlickrConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+    {
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+    }
+    
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
+        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		// show the facebook login page if not connected yet
+		if ( HTTP_NOT_FOUND == getStatus() )
+		{
+			LL_DEBUGS("FlickrConnect") << "Not connected. " << dumpResponse() << LL_ENDL;
+			if (mAutoConnect)
+			{
+                LLFlickrConnect::instance().connectToFlickr();
+			}
+			else
+			{
+                LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
+			}
+		}
+		else
+		{
+			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+			const LLSD& content = getContent();
+			log_flickr_connect_error("Connected", getStatus(), getReason(),
+                                      content.get("error_code"), content.get("error_description"));
+		}
+	}
+    
+private:
+	bool mAutoConnect;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrInfoResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrInfoResponder);
+public:
+
+	/* virtual */ void httpSuccess()
+	{
+		LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL;
+		LL_DEBUGS("FlickrConnect") << "Getting Flickr info successful. " << dumpResponse() << LL_ENDL;
+        LLFlickrConnect::instance().storeInfo(getContent());
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		if ( HTTP_FOUND == getStatus() )
+		{
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+                LLFlickrConnect::instance().openFlickrWeb(location);
+			}
+		}
+		else
+		{
+			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
+			const LLSD& content = getContent();
+			log_flickr_connect_error("Info", getStatus(), getReason(),
+                                      content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+LLFlickrConnect::LLFlickrConnect()
+:	mConnectionState(FLICKR_NOT_CONNECTED),
+	mConnected(false),
+	mInfo(),
+	mRefreshInfo(false),
+	mReadFromMaster(false)
+{
+}
+
+void LLFlickrConnect::openFlickrWeb(std::string url)
+{
+	// Open the URL in an internal browser window without navigation UI
+	LLFloaterWebContent::Params p;
+    p.url(url);
+    p.show_chrome(true);
+    p.allow_address_entry(false);
+    p.allow_back_forward_navigation(false);
+    p.trusted_content(true);
+    p.clean_browser(true);
+	LLFloater *floater = LLFloaterReg::showInstance("flickr_web", p);
+	//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
+	//So when showing the internal web browser, set focus to it's containing floater "flickr_web". When a mouse event 
+	//occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus.
+	//flickr_web floater contains the "webbrowser" panel.    JIRA: ACME-744
+	gFocusMgr.setKeyboardFocus( floater );
+
+	//LLUrlAction::openURLExternal(url);
+}
+
+std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool include_read_from_master)
+{
+    std::string url("");
+    LLViewerRegion *regionp = gAgent.getRegion();
+    if (regionp)
+    {
+		//url = "http://pdp15.lindenlab.com/flickr/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO
+        url = regionp->getCapability("FlickrConnect");
+        url += route;
+    
+        if (include_read_from_master && mReadFromMaster)
+        {
+            url += "?read_from_master=true";
+        }
+    }
+	return url;
+}
+
+void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier)
+{
+	LLSD body;
+	if (!request_token.empty())
+		body["request_token"] = request_token;
+	if (!oauth_verifier.empty())
+		body["oauth_verifier"] = oauth_verifier;
+    
+	LLHTTPClient::put(getFlickrConnectURL("/connection"), body, new LLFlickrConnectResponder());
+}
+
+void LLFlickrConnect::disconnectFromFlickr()
+{
+	LLHTTPClient::del(getFlickrConnectURL("/connection"), new LLFlickrDisconnectResponder());
+}
+
+void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect)
+{
+	const bool follow_redirects = false;
+	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	LLHTTPClient::get(getFlickrConnectURL("/connection", true), new LLFlickrConnectedResponder(auto_connect),
+						LLSD(), timeout, follow_redirects);
+}
+
+void LLFlickrConnect::loadFlickrInfo()
+{
+	if(mRefreshInfo)
+	{
+		const bool follow_redirects = false;
+		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+		LLHTTPClient::get(getFlickrConnectURL("/info", true), new LLFlickrInfoResponder(),
+			LLSD(), timeout, follow_redirects);
+	}
+}
+
+void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level)
+{
+	LLSD body;
+	body["image"] = image_url;
+	body["title"] = title;
+	body["description"] = description;
+	body["tags"] = tags;
+	body["safety_level"] = safety_level;
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::post(getFlickrConnectURL("/share/photo", true), body, new LLFlickrShareResponder());
+}
+
+void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level)
+{
+	std::string imageFormat;
+	if (dynamic_cast<LLImagePNG*>(image.get()))
+	{
+		imageFormat = "png";
+	}
+	else if (dynamic_cast<LLImageJPEG*>(image.get()))
+	{
+		imageFormat = "jpg";
+	}
+	else
+	{
+		llwarns << "Image to upload is not a PNG or JPEG" << llendl;
+		return;
+	}
+	
+	// All this code is mostly copied from LLWebProfile::post()
+	const std::string boundary = "----------------------------0123abcdefab";
+
+	LLSD headers;
+	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+
+	std::ostringstream body;
+
+	// *NOTE: The order seems to matter.
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"title\"\r\n\r\n"
+			<< title << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"description\"\r\n\r\n"
+			<< description << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"tags\"\r\n\r\n"
+			<< tags << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n"
+			<< safety_level << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
+			<< "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+	// Insert the image data.
+	// *FIX: Treating this as a string will probably screw it up ...
+	U8* image_data = image->getData();
+	for (S32 i = 0; i < image->getDataSize(); ++i)
+	{
+		body << image_data[i];
+	}
+
+	body <<	"\r\n--" << boundary << "--\r\n";
+
+	// postRaw() takes ownership of the buffer and releases it later.
+	size_t size = body.str().size();
+	U8 *data = new U8[size];
+	memcpy(data, body.str().data(), size);
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::postRaw(getFlickrConnectURL("/share/photo", true), data, size, new LLFlickrShareResponder(), headers);
+}
+
+void LLFlickrConnect::storeInfo(const LLSD& info)
+{
+	mInfo = info;
+	mRefreshInfo = false;
+
+	sInfoWatcher->post(info);
+}
+
+const LLSD& LLFlickrConnect::getInfo() const
+{
+	return mInfo;
+}
+
+void LLFlickrConnect::clearInfo()
+{
+	mInfo = LLSD();
+}
+
+void LLFlickrConnect::setDataDirty()
+{
+	mRefreshInfo = true;
+}
+
+void LLFlickrConnect::setConnectionState(LLFlickrConnect::EConnectionState connection_state)
+{
+	if(connection_state == FLICKR_CONNECTED)
+	{
+		mReadFromMaster = true;
+		setConnected(true);
+		setDataDirty();
+	}
+	else if(connection_state == FLICKR_NOT_CONNECTED)
+	{
+		setConnected(false);
+	}
+	else if(connection_state == FLICKR_POSTED)
+	{
+		mReadFromMaster = false;
+	}
+
+	if (mConnectionState != connection_state)
+	{
+		// set the connection state before notifying watchers
+		mConnectionState = connection_state;
+
+		LLSD state_info;
+		state_info["enum"] = connection_state;
+		sStateWatcher->post(state_info);
+	}
+}
+
+void LLFlickrConnect::setConnected(bool connected)
+{
+	mConnected = connected;
+}
diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h
new file mode 100644
index 0000000000000000000000000000000000000000..b127e6e10405deb936e49b310b555fe1bd29d5da
--- /dev/null
+++ b/indra/newview/llflickrconnect.h
@@ -0,0 +1,98 @@
+/** 
+ * @file llflickrconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Flickr Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLICKRCONNECT_H
+#define LL_LLFLICKRCONNECT_H
+
+#include "llsingleton.h"
+#include "llimage.h"
+
+class LLEventPump;
+
+/**
+ * @class LLFlickrConnect
+ *
+ * Manages authentication to, and interaction with, a web service allowing the
+ * the viewer to upload photos to Flickr.
+ */
+class LLFlickrConnect : public LLSingleton<LLFlickrConnect>
+{
+	LOG_CLASS(LLFlickrConnect);
+public:
+    enum EConnectionState
+	{
+		FLICKR_NOT_CONNECTED = 0,
+		FLICKR_CONNECTION_IN_PROGRESS = 1,
+		FLICKR_CONNECTED = 2,
+		FLICKR_CONNECTION_FAILED = 3,
+		FLICKR_POSTING = 4,
+		FLICKR_POSTED = 5,
+		FLICKR_POST_FAILED = 6,
+		FLICKR_DISCONNECTING = 7,
+		FLICKR_DISCONNECT_FAILED = 8
+	};
+	
+	void connectToFlickr(const std::string& request_token = "", const std::string& oauth_verifier = "");	// Initiate the complete Flickr connection. Please use checkConnectionToFlickr() in normal use.
+	void disconnectFromFlickr();																			// Disconnect from the Flickr service.
+    void checkConnectionToFlickr(bool auto_connect = false);												// Check if an access token is available on the Flickr service. If not, call connectToFlickr().
+    
+	void loadFlickrInfo();
+	void uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level);
+	void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level);
+	
+	void storeInfo(const LLSD& info);
+	const LLSD& getInfo() const;
+	void clearInfo();
+	void setDataDirty();
+    
+    void setConnectionState(EConnectionState connection_state);
+	void setConnected(bool connected);
+	bool isConnected() { return mConnected; }
+	bool isTransactionOngoing() { return ((mConnectionState == FLICKR_CONNECTION_IN_PROGRESS) || (mConnectionState == FLICKR_POSTING) || (mConnectionState == FLICKR_DISCONNECTING)); }
+    EConnectionState getConnectionState() { return mConnectionState; }
+    
+    void openFlickrWeb(std::string url);
+
+private:
+	friend class LLSingleton<LLFlickrConnect>;
+
+	LLFlickrConnect();
+	~LLFlickrConnect() {};
+ 	std::string getFlickrConnectURL(const std::string& route = "", bool include_read_from_master = false);
+
+    EConnectionState mConnectionState;
+	BOOL mConnected;
+	LLSD mInfo;
+	bool mRefreshInfo;
+	bool mReadFromMaster;
+	
+	static boost::scoped_ptr<LLEventPump> sStateWatcher;
+	static boost::scoped_ptr<LLEventPump> sInfoWatcher;
+	static boost::scoped_ptr<LLEventPump> sContentWatcher;
+};
+
+#endif // LL_LLFLICKRCONNECT_H
diff --git a/indra/newview/llfloaterbigpreview.cpp b/indra/newview/llfloaterbigpreview.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b516e9dd0154c4960766f1a270b8043df61a8299
--- /dev/null
+++ b/indra/newview/llfloaterbigpreview.cpp
@@ -0,0 +1,110 @@
+/** 
+* @file llfloaterbigpreview.cpp
+* @brief Display of extended (big) preview for snapshots and SL Share
+* @author merov@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterbigpreview.h"
+#include "llsnapshotlivepreview.h"
+
+///////////////////////
+//LLFloaterBigPreview//
+///////////////////////
+
+LLFloaterBigPreview::LLFloaterBigPreview(const LLSD& key) : LLFloater(key),
+    mPreviewPlaceholder(NULL),
+    mFloaterOwner(NULL)
+{
+}
+
+LLFloaterBigPreview::~LLFloaterBigPreview()
+{
+	if (mPreviewHandle.get())
+	{
+		mPreviewHandle.get()->die();
+	}
+}
+
+void LLFloaterBigPreview::onCancel()
+{
+    closeFloater();
+}
+
+void LLFloaterBigPreview::closeOnFloaterOwnerClosing(LLFloater* floaterp)
+{
+    if (isFloaterOwner(floaterp))
+    {
+        closeFloater();
+    }
+}
+
+BOOL LLFloaterBigPreview::postBuild()
+{
+	mPreviewPlaceholder = getChild<LLUICtrl>("big_preview_placeholder");
+	return LLFloater::postBuild();
+}
+
+void LLFloaterBigPreview::draw()
+{
+	LLFloater::draw();
+
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+    
+    // Display the preview if one is available
+	if (previewp && previewp->getBigThumbnailImage())
+	{
+        // Get the preview rect
+		const LLRect& preview_rect = mPreviewPlaceholder->getRect();
+        
+        // Get the preview texture size
+		S32 thumbnail_w = previewp->getBigThumbnailWidth();
+		S32 thumbnail_h = previewp->getBigThumbnailHeight();
+        
+        // Compute the scaling ratio and the size of the final texture in the rect: we want to prevent anisotropic scaling (distorted in x and y)
+        F32 ratio = llmax((F32)(thumbnail_w)/(F32)(preview_rect.getWidth()), (F32)(thumbnail_h)/(F32)(preview_rect.getHeight()));
+        thumbnail_w = (S32)((F32)(thumbnail_w)/ratio);
+        thumbnail_h = (S32)((F32)(thumbnail_h)/ratio);
+        
+		// Compute the preview offset within the preview rect: we want to center that preview in the available rect
+		const S32 local_offset_x = (preview_rect.getWidth()  - thumbnail_w) / 2 ;
+		const S32 local_offset_y = (preview_rect.getHeight() - thumbnail_h) / 2 ;
+        
+		// Compute preview offset within the floater rect
+		S32 offset_x = preview_rect.mLeft   + local_offset_x;
+		S32 offset_y = preview_rect.mBottom + local_offset_y;
+                
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		// Apply floater transparency to the texture unless the floater is focused.
+		F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+		LLColor4 color = LLColor4::white;
+        
+        // Draw the preview texture
+		gl_draw_scaled_image(offset_x, offset_y,
+                             thumbnail_w, thumbnail_h,
+                             previewp->getBigThumbnailImage(), color % alpha);
+	}
+}
+
diff --git a/indra/newview/llfloaterbigpreview.h b/indra/newview/llfloaterbigpreview.h
new file mode 100644
index 0000000000000000000000000000000000000000..63c6784d36ead97349c3de495c53fbed90650363
--- /dev/null
+++ b/indra/newview/llfloaterbigpreview.h
@@ -0,0 +1,54 @@
+/** 
+* @file   llfloaterbigpreview.h
+* @brief  Display of extended (big) preview for snapshots and SL Share
+* @author merov@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLFLOATERBIGPREVIEW_H
+#define LL_LLFLOATERBIGPREVIEW_H
+
+#include "llfloater.h"
+
+class LLFloaterBigPreview : public LLFloater
+{
+public:
+	LLFloaterBigPreview(const LLSD& key);
+    ~LLFloaterBigPreview();
+    
+	BOOL postBuild();
+	void draw();
+	void onCancel();
+
+    void setPreview(LLView* previewp) { mPreviewHandle = previewp->getHandle(); }
+    void setFloaterOwner(LLFloater* floaterp) { mFloaterOwner = floaterp; }
+    bool isFloaterOwner(LLFloater* floaterp) const { return (mFloaterOwner == floaterp); }
+    void closeOnFloaterOwnerClosing(LLFloater* floaterp);
+	
+private:
+	LLHandle<LLView> mPreviewHandle;
+	LLUICtrl*  mPreviewPlaceholder;
+    LLFloater* mFloaterOwner;
+};
+
+#endif // LL_LLFLOATERBIGPREVIEW_H
+
diff --git a/indra/newview/llfloatersocial.cpp b/indra/newview/llfloaterfacebook.cpp
similarity index 57%
rename from indra/newview/llfloatersocial.cpp
rename to indra/newview/llfloaterfacebook.cpp
index ea3d72e116e962f2e26dcdbe5fcb4a57a7d1a15b..9e3f917eae9f98407b0beded1e1592679d36016f 100644
--- a/indra/newview/llfloatersocial.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -1,6 +1,6 @@
 /** 
-* @file llfloatersocial.cpp
-* @brief Implementation of llfloatersocial
+* @file llfloaterfacebook.cpp
+* @brief Implementation of llfloaterfacebook
 * @author Gilbert@lindenlab.com
 *
 * $LicenseInfo:firstyear=2013&license=viewerlgpl$
@@ -27,15 +27,17 @@
 
 #include "llviewerprecompiledheaders.h"
 
-#include "llfloatersocial.h"
+#include "llfloaterfacebook.h"
 
 #include "llagent.h"
 #include "llagentui.h"
 #include "llcheckboxctrl.h"
 #include "llcombobox.h"
 #include "llfacebookconnect.h"
+#include "llfloaterbigpreview.h"
 #include "llfloaterreg.h"
 #include "lliconctrl.h"
+#include "llimagefiltersmanager.h"
 #include "llresmgr.h"		// LLLocale
 #include "llsdserialize.h"
 #include "llloadingindicator.h"
@@ -46,11 +48,17 @@
 #include "llviewerregion.h"
 #include "llviewercontrol.h"
 #include "llviewermedia.h"
-
-static LLPanelInjector<LLSocialStatusPanel> t_panel_status("llsocialstatuspanel");
-static LLPanelInjector<LLSocialPhotoPanel> t_panel_photo("llsocialphotopanel");
-static LLPanelInjector<LLSocialCheckinPanel> t_panel_checkin("llsocialcheckinpanel");
-static LLPanelInjector<LLSocialAccountPanel> t_panel_account("llsocialaccountpanel");
+#include "lltabcontainer.h"
+#include "llavatarlist.h"
+#include "llpanelpeoplemenus.h"
+#include "llaccordionctrl.h"
+#include "llaccordionctrltab.h"
+
+static LLPanelInjector<LLFacebookStatusPanel> t_panel_status("llfacebookstatuspanel");
+static LLPanelInjector<LLFacebookPhotoPanel> t_panel_photo("llfacebookphotopanel");
+static LLPanelInjector<LLFacebookCheckinPanel> t_panel_checkin("llfacebookcheckinpanel");
+static LLPanelInjector<LLFacebookFriendsPanel> t_panel_friends("llfacebookfriendspanel");
+static LLPanelInjector<LLFacebookAccountPanel> t_panel_account("llfacebookaccountpanel");
 
 const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
 const std::string DEFAULT_CHECKIN_LOCATION_URL = "http://maps.secondlife.com/";
@@ -58,12 +66,17 @@ const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazo
 const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare";
 const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare";
 
+const S32 MAX_QUALITY = 100;        // Max quality value for jpeg images
+const S32 MIN_QUALITY = 0;          // Min quality value for jpeg images
+const S32 TARGET_DATA_SIZE = 95000; // Size of the image (compressed) we're trying to send to Facebook
+
 std::string get_map_url()
 {
     LLVector3d center_agent;
-    if (gAgent.getRegion())
+    LLViewerRegion *regionp = gAgent.getRegion();
+    if (regionp)
     {
-        center_agent = gAgent.getRegion()->getCenterGlobal();
+        center_agent = regionp->getCenterGlobal();
     }
     int x_pos = center_agent[0] / 256.0;
     int y_pos = center_agent[1] / 256.0;
@@ -71,19 +84,27 @@ std::string get_map_url()
     return map_url;
 }
 
+// Compute target jpeg quality : see https://wiki.lindenlab.com/wiki/Facebook_Image_Quality for details
+S32 compute_jpeg_quality(S32 width, S32 height)
+{
+    F32 target_compression_ratio = (F32)(width * height * 3) / (F32)(TARGET_DATA_SIZE);
+    S32 quality = (S32)(110.0f - (2.0f * target_compression_ratio));
+    return llclamp(quality,MIN_QUALITY,MAX_QUALITY);
+}
+
 ///////////////////////////
-//LLSocialStatusPanel//////
+//LLFacebookStatusPanel//////
 ///////////////////////////
 
-LLSocialStatusPanel::LLSocialStatusPanel() :
+LLFacebookStatusPanel::LLFacebookStatusPanel() :
 	mMessageTextEditor(NULL),
 	mPostButton(NULL),
     mCancelButton(NULL)
 {
-	mCommitCallbackRegistrar.add("SocialSharing.SendStatus", boost::bind(&LLSocialStatusPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.SendStatus", boost::bind(&LLFacebookStatusPanel::onSend, this));
 }
 
-BOOL LLSocialStatusPanel::postBuild()
+BOOL LLFacebookStatusPanel::postBuild()
 {
 	mMessageTextEditor = getChild<LLUICtrl>("status_message");
 	mPostButton = getChild<LLUICtrl>("post_status_btn");
@@ -92,7 +113,7 @@ BOOL LLSocialStatusPanel::postBuild()
 	return LLPanel::postBuild();
 }
 
-void LLSocialStatusPanel::draw()
+void LLFacebookStatusPanel::draw()
 {
     if (mMessageTextEditor && mPostButton && mCancelButton)
 	{
@@ -106,10 +127,10 @@ void LLSocialStatusPanel::draw()
 	LLPanel::draw();
 }
 
-void LLSocialStatusPanel::onSend()
+void LLFacebookStatusPanel::onSend()
 {
-	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel"); // just in case it is already listening
-	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialStatusPanel", boost::bind(&LLSocialStatusPanel::onFacebookConnectStateChange, this, _1));
+	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookStatusPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookStatusPanel", boost::bind(&LLFacebookStatusPanel::onFacebookConnectStateChange, this, _1));
 		
 	// Connect to Facebook if necessary and then post
 	if (LLFacebookConnect::instance().isConnected())
@@ -122,7 +143,7 @@ void LLSocialStatusPanel::onSend()
 	}
 }
 
-bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookStatusPanel::onFacebookConnectStateChange(const LLSD& data)
 {
 	switch (data.get("enum").asInteger())
 	{
@@ -131,7 +152,7 @@ bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
 			break;
 
 		case LLFacebookConnect::FB_POSTED:
-			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel");
+			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookStatusPanel");
 			clearAndClose();
 			break;
 	}
@@ -139,7 +160,7 @@ bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
 	return false;
 }
 
-void LLSocialStatusPanel::sendStatus()
+void LLFacebookStatusPanel::sendStatus()
 {
 	std::string message = mMessageTextEditor->getValue().asString();
 	if (!message.empty())
@@ -148,7 +169,7 @@ void LLSocialStatusPanel::sendStatus()
 	}
 }
 
-void LLSocialStatusPanel::clearAndClose()
+void LLFacebookStatusPanel::clearAndClose()
 {
 	mMessageTextEditor->setValue("");
 
@@ -160,23 +181,27 @@ void LLSocialStatusPanel::clearAndClose()
 }
 
 ///////////////////////////
-//LLSocialPhotoPanel///////
+//LLFacebookPhotoPanel///////
 ///////////////////////////
 
-LLSocialPhotoPanel::LLSocialPhotoPanel() :
+LLFacebookPhotoPanel::LLFacebookPhotoPanel() :
 mSnapshotPanel(NULL),
 mResolutionComboBox(NULL),
 mRefreshBtn(NULL),
+mBtnPreview(NULL),
 mWorkingLabel(NULL),
 mThumbnailPlaceholder(NULL),
 mCaptionTextBox(NULL),
-mPostButton(NULL)
+mPostButton(NULL),
+mBigPreviewFloater(NULL),
+mQuality(MAX_QUALITY)
 {
-	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLSocialPhotoPanel::onSend, this));
-	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLSocialPhotoPanel::onClickNewSnapshot, this));
+	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLFacebookPhotoPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLFacebookPhotoPanel::onClickNewSnapshot, this));
+	mCommitCallbackRegistrar.add("SocialSharing.BigPreview", boost::bind(&LLFacebookPhotoPanel::onClickBigPreview, this));
 }
 
-LLSocialPhotoPanel::~LLSocialPhotoPanel()
+LLFacebookPhotoPanel::~LLFacebookPhotoPanel()
 {
 	if(mPreviewHandle.get())
 	{
@@ -184,24 +209,65 @@ LLSocialPhotoPanel::~LLSocialPhotoPanel()
 	}
 }
 
-BOOL LLSocialPhotoPanel::postBuild()
+BOOL LLFacebookPhotoPanel::postBuild()
 {
-	setVisibleCallback(boost::bind(&LLSocialPhotoPanel::onVisibilityChanged, this, _2));
+	setVisibleCallback(boost::bind(&LLFacebookPhotoPanel::onVisibilityChange, this, _2));
 	
 	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
 	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
-	mResolutionComboBox->setCommitCallback(boost::bind(&LLSocialPhotoPanel::updateResolution, this, TRUE));
+	mResolutionComboBox->setValue("[i1200,i630]"); // hardcoded defaults ftw!
+	mResolutionComboBox->setCommitCallback(boost::bind(&LLFacebookPhotoPanel::updateResolution, this, TRUE));
+	mFilterComboBox = getChild<LLUICtrl>("filters_combobox");
+	mFilterComboBox->setCommitCallback(boost::bind(&LLFacebookPhotoPanel::updateResolution, this, TRUE));
 	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
+	mBtnPreview = getChild<LLButton>("big_preview_btn");
     mWorkingLabel = getChild<LLUICtrl>("working_lbl");
 	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
 	mCaptionTextBox = getChild<LLUICtrl>("photo_caption");
 	mPostButton = getChild<LLUICtrl>("post_photo_btn");
 	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
+	mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+
+	// Update filter list
+    std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList();
+	LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+    for (U32 i = 0; i < filter_list.size(); i++)
+	{
+        filterbox->add(filter_list[i]);
+    }
 
 	return LLPanel::postBuild();
 }
 
-void LLSocialPhotoPanel::draw()
+// virtual
+S32 LLFacebookPhotoPanel::notify(const LLSD& info)
+{
+	if (info.has("snapshot-updating"))
+	{
+        // Disable the Post button and whatever else while the snapshot is not updated
+        // updateControls();
+		return 1;
+	}
+    
+	if (info.has("snapshot-updated"))
+	{
+        // Enable the send/post/save buttons.
+        updateControls();
+        
+		// The refresh button is initially hidden. We show it after the first update,
+		// i.e. after snapshot is taken
+		LLUICtrl * refresh_button = getRefreshBtn();
+		if (!refresh_button->getVisible())
+		{
+			refresh_button->setVisible(true);
+		}
+		return 1;
+	}
+    
+	return 0;
+}
+
+void LLFacebookPhotoPanel::draw()
 { 
 	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
 
@@ -210,9 +276,21 @@ void LLSocialPhotoPanel::draw()
     mCancelButton->setEnabled(no_ongoing_connection);
     mCaptionTextBox->setEnabled(no_ongoing_connection);
     mResolutionComboBox->setEnabled(no_ongoing_connection);
+    mFilterComboBox->setEnabled(no_ongoing_connection);
     mRefreshBtn->setEnabled(no_ongoing_connection);
+    mBtnPreview->setEnabled(no_ongoing_connection);
+	
+    // Reassign the preview floater if we have the focus and the preview exists
+    if (hasFocus() && isPreviewVisible())
+    {
+        attachPreview();
+    }
+    
+    // Toggle the button state as appropriate
+    bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType<LLFloater>()));
+	mBtnPreview->setToggleState(preview_active);
     
-    // Display the preview if one is available
+    // Display the thumbnail if one is available
 	if (previewp && previewp->getThumbnailImage())
 	{
 		const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect();
@@ -239,8 +317,6 @@ void LLSocialPhotoPanel::draw()
 		gl_draw_scaled_image(offset_x, offset_y, 
 			thumbnail_w, thumbnail_h,
 			previewp->getThumbnailImage(), color % alpha);
-
-		previewp->drawPreviewRect(offset_x, offset_y) ;
 	}
 
     // Update the visibility of the working (computing preview) label
@@ -253,15 +329,14 @@ void LLSocialPhotoPanel::draw()
 	LLPanel::draw();
 }
 
-LLSnapshotLivePreview* LLSocialPhotoPanel::getPreviewView()
+LLSnapshotLivePreview* LLFacebookPhotoPanel::getPreviewView()
 {
 	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
 	return previewp;
 }
 
-void LLSocialPhotoPanel::onVisibilityChanged(const LLSD& new_visibility)
+void LLFacebookPhotoPanel::onVisibilityChange(BOOL visible)
 {
-	bool visible = new_visibility.asBoolean();
 	if (visible)
 	{
 		if (mPreviewHandle.get())
@@ -269,7 +344,7 @@ void LLSocialPhotoPanel::onVisibilityChanged(const LLSD& new_visibility)
 			LLSnapshotLivePreview* preview = getPreviewView();
 			if(preview)
 			{
-				LL_DEBUGS() << "opened, updating snapshot" << LL_ENDL;
+				lldebugs << "opened, updating snapshot" << llendl;
 				preview->updateSnapshot(TRUE);
 			}
 		}
@@ -280,10 +355,15 @@ void LLSocialPhotoPanel::onVisibilityChanged(const LLSD& new_visibility)
 			p.rect(full_screen_rect);
 			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
 			mPreviewHandle = previewp->getHandle();	
+            mQuality = MAX_QUALITY;
 
+            previewp->setContainer(this);
 			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
 			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
-			//previewp->setSnapshotQuality(98);
+			previewp->setSnapshotQuality(mQuality, false);
+            previewp->setThumbnailSubsampled(TRUE);     // We want the preview to reflect the *saved* image
+            previewp->setAllowRenderUI(FALSE);          // We do not want the rendered UI in our snapshots
+            previewp->setAllowFullScreenPreview(FALSE);  // No full screen preview in SL Share mode
 			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
 
 			updateControls();
@@ -291,21 +371,48 @@ void LLSocialPhotoPanel::onVisibilityChanged(const LLSD& new_visibility)
 	}
 }
 
-void LLSocialPhotoPanel::onClickNewSnapshot()
+void LLFacebookPhotoPanel::onClickNewSnapshot()
 {
 	LLSnapshotLivePreview* previewp = getPreviewView();
 	if (previewp)
 	{
-		//setStatus(Impl::STATUS_READY);
-		LL_DEBUGS() << "updating snapshot" << LL_ENDL;
 		previewp->updateSnapshot(TRUE);
 	}
 }
 
-void LLSocialPhotoPanel::onSend()
+void LLFacebookPhotoPanel::onClickBigPreview()
+{
+    // Toggle the preview
+    if (isPreviewVisible())
+    {
+        LLFloaterReg::hideInstance("big_preview");
+    }
+    else
+    {
+        attachPreview();
+        LLFloaterReg::showInstance("big_preview");
+    }
+}
+
+bool LLFacebookPhotoPanel::isPreviewVisible()
+{
+    return (mBigPreviewFloater && mBigPreviewFloater->getVisible());
+}
+
+void LLFacebookPhotoPanel::attachPreview()
+{
+    if (mBigPreviewFloater)
+    {
+        LLSnapshotLivePreview* previewp = getPreviewView();
+        mBigPreviewFloater->setPreview(previewp);
+        mBigPreviewFloater->setFloaterOwner(getParentByType<LLFloater>());
+    }
+}
+
+void LLFacebookPhotoPanel::onSend()
 {
-	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel"); // just in case it is already listening
-	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialPhotoPanel", boost::bind(&LLSocialPhotoPanel::onFacebookConnectStateChange, this, _1));
+	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookPhotoPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookPhotoPanel", boost::bind(&LLFacebookPhotoPanel::onFacebookConnectStateChange, this, _1));
 	
 	// Connect to Facebook if necessary and then post
 	if (LLFacebookConnect::instance().isConnected())
@@ -318,7 +425,7 @@ void LLSocialPhotoPanel::onSend()
 	}
 }
 
-bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
 {
 	switch (data.get("enum").asInteger())
 	{
@@ -327,7 +434,7 @@ bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
 			break;
 
 		case LLFacebookConnect::FB_POSTED:
-			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel");
+			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookPhotoPanel");
 			clearAndClose();
 			break;
 	}
@@ -335,7 +442,7 @@ bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
 	return false;
 }
 
-void LLSocialPhotoPanel::sendPhoto()
+void LLFacebookPhotoPanel::sendPhoto()
 {
 	// Get the caption
 	std::string caption = mCaptionTextBox->getValue().asString();
@@ -349,7 +456,7 @@ void LLSocialPhotoPanel::sendPhoto()
 	updateControls();
 }
 
-void LLSocialPhotoPanel::clearAndClose()
+void LLFacebookPhotoPanel::clearAndClose()
 {
 	mCaptionTextBox->setValue("");
 
@@ -357,39 +464,28 @@ void LLSocialPhotoPanel::clearAndClose()
 	if (floater)
 	{
 		floater->closeFloater();
+        if (mBigPreviewFloater)
+        {
+            mBigPreviewFloater->closeOnFloaterOwnerClosing(floater);
+        }
 	}
 }
 
-void LLSocialPhotoPanel::updateControls()
+void LLFacebookPhotoPanel::updateControls()
 {
 	LLSnapshotLivePreview* previewp = getPreviewView();
-	BOOL got_bytes = previewp && previewp->getDataSize() > 0;
 	BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
-	LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD);
-
+    
 	// *TODO: Separate maximum size for Web images from postcards
-	LL_DEBUGS() << "Is snapshot up-to-date? " << got_snap << LL_ENDL;
-
-	LLLocale locale(LLLocale::USER_LOCALE);
-	std::string bytes_string;
-	if (got_snap)
-	{
-		LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
-	}
-
-	//getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string
-	getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown");
-	getChild<LLUICtrl>("file_size_label")->setColor(
-		shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD 
-		&& got_bytes
-		&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" ));
-
+	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
+    
 	updateResolution(FALSE);
 }
 
-void LLSocialPhotoPanel::updateResolution(BOOL do_update)
+void LLFacebookPhotoPanel::updateResolution(BOOL do_update)
 {
 	LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+	LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
 
 	std::string sdstring = combobox->getSelectedValue();
 	LLSD sdres;
@@ -399,6 +495,9 @@ void LLSocialPhotoPanel::updateResolution(BOOL do_update)
 	S32 width = sdres[0];
 	S32 height = sdres[1];
 
+    // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale
+    std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : "");
+
 	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
 	if (previewp && combobox->getCurrentIndex() >= 0)
 	{
@@ -408,40 +507,48 @@ void LLSocialPhotoPanel::updateResolution(BOOL do_update)
 		if (width == 0 || height == 0)
 		{
 			// take resolution from current window size
-			LL_DEBUGS() << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << LL_ENDL;
+			lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl;
 			previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
 		}
 		else
 		{
 			// use the resolution from the selected pre-canned drop-down choice
-			LL_DEBUGS() << "Setting preview res selected from combo: " << width << "x" << height << LL_ENDL;
+			lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl;
 			previewp->setSize(width, height);
 		}
 
 		checkAspectRatio(width);
 
 		previewp->getSize(width, height);
+        
+        // Recompute quality setting
+        mQuality = compute_jpeg_quality(width, height);
+        previewp->setSnapshotQuality(mQuality, false);
 		
-		if(original_width != width || original_height != height)
+		if (original_width != width || original_height != height)
 		{
 			previewp->setSize(width, height);
-
-			// hide old preview as the aspect ratio could be wrong
-			LL_DEBUGS() << "updating thumbnail" << LL_ENDL;
-			
-			previewp->updateSnapshot(FALSE, TRUE);
-			if(do_update)
+			if (do_update)
 			{
-				LL_DEBUGS() << "Will update controls" << LL_ENDL;
+                previewp->updateSnapshot(TRUE);
+				updateControls();
+			}
+		}
+        // Get the old filter, compare to the current one "filter_name" and set if changed
+        std::string original_filter = previewp->getFilter();
+		if (original_filter != filter_name)
+		{
+            previewp->setFilter(filter_name);
+			if (do_update)
+			{
+                previewp->updateSnapshot(FALSE, TRUE);
 				updateControls();
-                LLSocialPhotoPanel::onClickNewSnapshot();
 			}
 		}
-		
 	}
 }
 
-void LLSocialPhotoPanel::checkAspectRatio(S32 index)
+void LLFacebookPhotoPanel::checkAspectRatio(S32 index)
 {
 	LLSnapshotLivePreview *previewp = getPreviewView() ;
 
@@ -462,23 +569,23 @@ void LLSocialPhotoPanel::checkAspectRatio(S32 index)
 	}
 }
 
-LLUICtrl* LLSocialPhotoPanel::getRefreshBtn()
+LLUICtrl* LLFacebookPhotoPanel::getRefreshBtn()
 {
 	return mRefreshBtn;
 }
 
 ////////////////////////
-//LLSocialCheckinPanel//
+//LLFacebookCheckinPanel//
 ////////////////////////
 
-LLSocialCheckinPanel::LLSocialCheckinPanel() :
+LLFacebookCheckinPanel::LLFacebookCheckinPanel() :
     mMapUrl(""),
     mReloadingMapTexture(false)
 {
-	mCommitCallbackRegistrar.add("SocialSharing.SendCheckin", boost::bind(&LLSocialCheckinPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.SendCheckin", boost::bind(&LLFacebookCheckinPanel::onSend, this));
 }
 
-BOOL LLSocialCheckinPanel::postBuild()
+BOOL LLFacebookCheckinPanel::postBuild()
 {
     // Keep pointers to widgets so we don't traverse the UI hierarchy too often
 	mPostButton = getChild<LLUICtrl>("post_place_btn");
@@ -492,7 +599,7 @@ BOOL LLSocialCheckinPanel::postBuild()
 	return LLPanel::postBuild();
 }
 
-void LLSocialCheckinPanel::draw()
+void LLFacebookCheckinPanel::draw()
 {
     bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing());
     mPostButton->setEnabled(no_ongoing_connection);
@@ -533,10 +640,10 @@ void LLSocialCheckinPanel::draw()
 	LLPanel::draw();
 }
 
-void LLSocialCheckinPanel::onSend()
+void LLFacebookCheckinPanel::onSend()
 {
-	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel"); // just in case it is already listening
-	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialCheckinPanel", boost::bind(&LLSocialCheckinPanel::onFacebookConnectStateChange, this, _1));
+	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookCheckinPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookCheckinPanel", boost::bind(&LLFacebookCheckinPanel::onFacebookConnectStateChange, this, _1));
 	
 	// Connect to Facebook if necessary and then post
 	if (LLFacebookConnect::instance().isConnected())
@@ -549,7 +656,7 @@ void LLSocialCheckinPanel::onSend()
 	}
 }
 
-bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
 {
 	switch (data.get("enum").asInteger())
 	{
@@ -558,7 +665,7 @@ bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
 			break;
 
 		case LLFacebookConnect::FB_POSTED:
-			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel");
+			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookCheckinPanel");
 			clearAndClose();
 			break;
 	}
@@ -566,7 +673,7 @@ bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
 	return false;
 }
 
-void LLSocialCheckinPanel::sendCheckin()
+void LLFacebookCheckinPanel::sendCheckin()
 {
 	// Get the location SLURL
 	LLSLURL slurl;
@@ -584,7 +691,12 @@ void LLSocialCheckinPanel::sendCheckin()
 	slurl_string += DEFAULT_CHECKIN_QUERY_PARAMETERS;
     
 	// Get the region name
-	std::string region_name = gAgent.getRegion()->getName();
+	std::string region_name("");
+    LLViewerRegion *regionp = gAgent.getRegion();
+    if (regionp)
+    {
+        region_name = regionp->getName();
+    }
     
 	// Get the region description
 	std::string description;
@@ -601,7 +713,7 @@ void LLSocialCheckinPanel::sendCheckin()
 	LLFacebookConnect::instance().postCheckin(slurl_string, region_name, description, map_url, caption);
 }
 
-void LLSocialCheckinPanel::clearAndClose()
+void LLFacebookCheckinPanel::clearAndClose()
 {
 	mMessageTextEditor->setValue("");
 
@@ -613,23 +725,186 @@ void LLSocialCheckinPanel::clearAndClose()
 }
 
 ///////////////////////////
-//LLSocialAccountPanel//////
+//LLFacebookFriendsPanel//////
 ///////////////////////////
 
-LLSocialAccountPanel::LLSocialAccountPanel() : 
+LLFacebookFriendsPanel::LLFacebookFriendsPanel() : 
+mFriendsStatusCaption(NULL),
+mSecondLifeFriends(NULL),
+mSuggestedFriends(NULL)
+{
+}
+
+LLFacebookFriendsPanel::~LLFacebookFriendsPanel()
+{
+    LLAvatarTracker::instance().removeObserver(this);
+}
+
+BOOL LLFacebookFriendsPanel::postBuild()
+{
+	mFriendsStatusCaption = getChild<LLTextBox>("facebook_friends_status");
+
+	mSecondLifeFriends = getChild<LLAvatarList>("second_life_friends");
+	mSecondLifeFriends->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
+	
+	mSuggestedFriends = getChild<LLAvatarList>("suggested_friends");
+	mSuggestedFriends->setContextMenu(&LLPanelPeopleMenus::gSuggestedFriendsContextMenu);
+	
+	setVisibleCallback(boost::bind(&LLFacebookFriendsPanel::updateFacebookList, this, _2));
+
+    LLAvatarTracker::instance().addObserver(this);
+    
+	return LLPanel::postBuild();
+}
+
+bool LLFacebookFriendsPanel::updateSuggestedFriendList()
+{
+	const LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
+	uuid_vec_t& second_life_friends = mSecondLifeFriends->getIDs();
+	second_life_friends.clear();
+	uuid_vec_t& suggested_friends = mSuggestedFriends->getIDs();
+	suggested_friends.clear();
+
+	//Add suggested friends
+	LLSD friends = LLFacebookConnect::instance().getContent();
+	for (LLSD::array_const_iterator i = friends.beginArray(); i != friends.endArray(); ++i)
+	{
+		LLUUID agent_id = (*i).asUUID();
+		if (agent_id.notNull())
+		{
+			bool second_life_buddy = av_tracker.isBuddy(agent_id);
+			if (second_life_buddy)
+			{
+				second_life_friends.push_back(agent_id);
+			}
+			else
+			{
+				//FB+SL but not SL friend
+				suggested_friends.push_back(agent_id);
+			}
+		}
+	}
+
+	//Force a refresh when there aren't any filter matches (prevent displaying content that shouldn't display)
+	mSecondLifeFriends->setDirty(true, !mSecondLifeFriends->filterHasMatches());
+	mSuggestedFriends->setDirty(true, !mSuggestedFriends->filterHasMatches());
+	showFriendsAccordionsIfNeeded();
+
+	return false;
+}
+
+void LLFacebookFriendsPanel::showFriendsAccordionsIfNeeded()
+{
+    // Show / hide the status text : needs to be done *before* showing / hidding the accordions
+    if (!mSecondLifeFriends->filterHasMatches() && !mSuggestedFriends->filterHasMatches())
+    {
+        // Show some explanation text if the lists are empty...
+        mFriendsStatusCaption->setVisible(true);
+        if (LLFacebookConnect::instance().isConnected())
+        {
+            //...you're connected to FB but have no friends :(
+            mFriendsStatusCaption->setText(getString("facebook_friends_empty"));
+        }
+        else
+        {
+            //...you're not connected to FB
+            mFriendsStatusCaption->setText(getString("facebook_friends_no_connected"));
+        }
+        // Hide the lists
+        getChild<LLAccordionCtrl>("friends_accordion")->setVisible(false);
+        getChild<LLAccordionCtrlTab>("tab_second_life_friends")->setVisible(false);
+        getChild<LLAccordionCtrlTab>("tab_suggested_friends")->setVisible(false);
+    }
+    else
+    {
+        // We have something in the lists, hide the explanatory text
+        mFriendsStatusCaption->setVisible(false);
+        
+        // Show the lists
+        LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
+        accordion->setVisible(true);
+        
+        // Expand and show accordions if needed, else - hide them
+        getChild<LLAccordionCtrlTab>("tab_second_life_friends")->setVisible(mSecondLifeFriends->filterHasMatches());
+        getChild<LLAccordionCtrlTab>("tab_suggested_friends")->setVisible(mSuggestedFriends->filterHasMatches());
+        
+        // Rearrange accordions
+        accordion->arrange();
+    }
+}
+
+void LLFacebookFriendsPanel::changed(U32 mask)
+{
+	if (mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE))
+	{
+        LLFacebookConnect::instance().loadFacebookFriends();
+		updateFacebookList(true);
+	}
+}
+
+
+void LLFacebookFriendsPanel::updateFacebookList(bool visible)
+{
+	if (visible)
+	{
+        // We want this to be called to fetch the friends list once a connection is established
+		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookFriendsPanel");
+		LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookFriendsPanel", boost::bind(&LLFacebookFriendsPanel::onConnectedToFacebook, this, _1));
+        
+        // We then want this to be called to update the displayed lists once the list of friends is received
+		LLEventPumps::instance().obtain("FacebookConnectContent").stopListening("LLFacebookFriendsPanel"); // just in case it is already listening
+		LLEventPumps::instance().obtain("FacebookConnectContent").listen("LLFacebookFriendsPanel", boost::bind(&LLFacebookFriendsPanel::updateSuggestedFriendList, this));
+        
+		// Try to connect to Facebook
+        if ((LLFacebookConnect::instance().getConnectionState() == LLFacebookConnect::FB_NOT_CONNECTED) ||
+            (LLFacebookConnect::instance().getConnectionState() == LLFacebookConnect::FB_CONNECTION_FAILED))
+        {
+            LLFacebookConnect::instance().checkConnectionToFacebook();
+        }
+		// Loads FB friends
+		if (LLFacebookConnect::instance().isConnected())
+		{
+			LLFacebookConnect::instance().loadFacebookFriends();
+		}
+        // Sort the FB friends and update the lists
+		updateSuggestedFriendList();
+	}
+}
+
+bool LLFacebookFriendsPanel::onConnectedToFacebook(const LLSD& data)
+{
+	LLSD::Integer connection_state = data.get("enum").asInteger();
+
+	if (connection_state == LLFacebookConnect::FB_CONNECTED)
+	{
+		LLFacebookConnect::instance().loadFacebookFriends();
+	}
+	else if (connection_state == LLFacebookConnect::FB_NOT_CONNECTED)
+	{
+		updateSuggestedFriendList();
+	}
+
+	return false;
+}
+
+///////////////////////////
+//LLFacebookAccountPanel//////
+///////////////////////////
+
+LLFacebookAccountPanel::LLFacebookAccountPanel() : 
 mAccountCaptionLabel(NULL),
 mAccountNameLabel(NULL),
 mPanelButtons(NULL),
 mConnectButton(NULL),
 mDisconnectButton(NULL)
 {
-	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLSocialAccountPanel::onConnect, this));
-	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLSocialAccountPanel::onDisconnect, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLFacebookAccountPanel::onConnect, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLFacebookAccountPanel::onDisconnect, this));
 
-	setVisibleCallback(boost::bind(&LLSocialAccountPanel::onVisibilityChanged, this, _2));
+	setVisibleCallback(boost::bind(&LLFacebookAccountPanel::onVisibilityChange, this, _2));
 }
 
-BOOL LLSocialAccountPanel::postBuild()
+BOOL LLFacebookAccountPanel::postBuild()
 {
 	mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
 	mAccountNameLabel = getChild<LLTextBox>("account_name_label");
@@ -640,7 +915,7 @@ BOOL LLSocialAccountPanel::postBuild()
 	return LLPanel::postBuild();
 }
 
-void LLSocialAccountPanel::draw()
+void LLFacebookAccountPanel::draw()
 {
 	LLFacebookConnect::EConnectionState connection_state = LLFacebookConnect::instance().getConnectionState();
 
@@ -655,17 +930,15 @@ void LLSocialAccountPanel::draw()
 	LLPanel::draw();
 }
 
-void LLSocialAccountPanel::onVisibilityChanged(const LLSD& new_visibility)
+void LLFacebookAccountPanel::onVisibilityChange(BOOL visible)
 {
-	bool visible = new_visibility.asBoolean();
-
 	if(visible)
 	{
-		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel");
-		LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectStateChange, this, _1));
+		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookAccountPanel");
+		LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookAccountPanel", boost::bind(&LLFacebookAccountPanel::onFacebookConnectStateChange, this, _1));
 
-		LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel");
-		LLEventPumps::instance().obtain("FacebookConnectInfo").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectInfoChange, this));
+		LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLFacebookAccountPanel");
+		LLEventPumps::instance().obtain("FacebookConnectInfo").listen("LLFacebookAccountPanel", boost::bind(&LLFacebookAccountPanel::onFacebookConnectInfoChange, this));
 
 		//Connected
 		if(LLFacebookConnect::instance().isConnected())
@@ -685,12 +958,12 @@ void LLSocialAccountPanel::onVisibilityChanged(const LLSD& new_visibility)
 	}
 	else
 	{
-		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel");
-		LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel");
+		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookAccountPanel");
+		LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLFacebookAccountPanel");
 	}
 }
 
-bool LLSocialAccountPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookAccountPanel::onFacebookConnectStateChange(const LLSD& data)
 {
 	if(LLFacebookConnect::instance().isConnected())
 	{
@@ -708,7 +981,7 @@ bool LLSocialAccountPanel::onFacebookConnectStateChange(const LLSD& data)
 	return false;
 }
 
-bool LLSocialAccountPanel::onFacebookConnectInfoChange()
+bool LLFacebookAccountPanel::onFacebookConnectInfoChange()
 {
 	LLSD info = LLFacebookConnect::instance().getInfo();
 	std::string clickable_name;
@@ -724,7 +997,7 @@ bool LLSocialAccountPanel::onFacebookConnectInfoChange()
 	return false;
 }
 
-void LLSocialAccountPanel::showConnectButton()
+void LLFacebookAccountPanel::showConnectButton()
 {
 	if(!mConnectButton->getVisible())
 	{
@@ -733,7 +1006,7 @@ void LLSocialAccountPanel::showConnectButton()
 	}
 }
 
-void LLSocialAccountPanel::hideConnectButton()
+void LLFacebookAccountPanel::hideConnectButton()
 {
 	if(mConnectButton->getVisible())
 	{
@@ -742,14 +1015,14 @@ void LLSocialAccountPanel::hideConnectButton()
 	}
 }
 
-void LLSocialAccountPanel::showDisconnectedLayout()
+void LLFacebookAccountPanel::showDisconnectedLayout()
 {
 	mAccountCaptionLabel->setText(getString("facebook_disconnected"));
 	mAccountNameLabel->setText(std::string(""));
 	showConnectButton();
 }
 
-void LLSocialAccountPanel::showConnectedLayout()
+void LLFacebookAccountPanel::showConnectedLayout()
 {
 	LLFacebookConnect::instance().loadFacebookInfo();
 
@@ -757,7 +1030,7 @@ void LLSocialAccountPanel::showConnectedLayout()
 	hideConnectButton();
 }
 
-void LLSocialAccountPanel::onConnect()
+void LLFacebookAccountPanel::onConnect()
 {
 	LLFacebookConnect::instance().checkConnectionToFacebook(true);
 
@@ -765,7 +1038,7 @@ void LLSocialAccountPanel::onConnect()
 	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com"); 
 }
 
-void LLSocialAccountPanel::onDisconnect()
+void LLFacebookAccountPanel::onDisconnect()
 {
 	LLFacebookConnect::instance().disconnectFromFacebook();
 
@@ -773,27 +1046,42 @@ void LLSocialAccountPanel::onDisconnect()
 }
 
 ////////////////////////
-//LLFloaterSocial///////
+//LLFloaterFacebook///////
 ////////////////////////
 
-LLFloaterSocial::LLFloaterSocial(const LLSD& key) : LLFloater(key),
-    mSocialPhotoPanel(NULL),
+LLFloaterFacebook::LLFloaterFacebook(const LLSD& key) : LLFloater(key),
+    mFacebookPhotoPanel(NULL),
     mStatusErrorText(NULL),
     mStatusLoadingText(NULL),
     mStatusLoadingIndicator(NULL)
 {
-	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterSocial::onCancel, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterFacebook::onCancel, this));
 }
 
-void LLFloaterSocial::onCancel()
+void LLFloaterFacebook::onClose(bool app_quitting)
 {
+    LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+    if (big_preview_floater)
+    {
+        big_preview_floater->closeOnFloaterOwnerClosing(this);
+    }
+	LLFloater::onClose(app_quitting);
+}
+
+void LLFloaterFacebook::onCancel()
+{
+    LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+    if (big_preview_floater)
+    {
+        big_preview_floater->closeOnFloaterOwnerClosing(this);
+    }
     closeFloater();
 }
 
-BOOL LLFloaterSocial::postBuild()
+BOOL LLFloaterFacebook::postBuild()
 {
     // Keep tab of the Photo Panel
-	mSocialPhotoPanel = static_cast<LLSocialPhotoPanel*>(getChild<LLUICtrl>("panel_social_photo"));
+	mFacebookPhotoPanel = static_cast<LLFacebookPhotoPanel*>(getChild<LLUICtrl>("panel_facebook_photo"));
     // Connection status widgets
     mStatusErrorText = getChild<LLTextBox>("connection_error_text");
     mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
@@ -801,39 +1089,19 @@ BOOL LLFloaterSocial::postBuild()
 	return LLFloater::postBuild();
 }
 
-// static
-void LLFloaterSocial::preUpdate()
+void LLFloaterFacebook::showPhotoPanel()
 {
-	LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");
-	if (instance)
+	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mFacebookPhotoPanel->getParent());
+	if (!parent)
 	{
-		//Will set file size text to 'unknown'
-		instance->mSocialPhotoPanel->updateControls();
+		llwarns << "Cannot find panel container" << llendl;
+		return;
 	}
-}
-
-// static
-void LLFloaterSocial::postUpdate()
-{
-	LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");
-	if (instance)
-	{
-		//Will set the file size text
-		instance->mSocialPhotoPanel->updateControls();
 
-		// The refresh button is initially hidden. We show it after the first update,
-		// i.e. after snapshot is taken
-		LLUICtrl * refresh_button = instance->mSocialPhotoPanel->getRefreshBtn();
-
-		if (!refresh_button->getVisible())
-		{
-			refresh_button->setVisible(true);
-		}
-		
-	}
+	parent->selectTabPanel(mFacebookPhotoPanel);
 }
 
-void LLFloaterSocial::draw()
+void LLFloaterFacebook::draw()
 {
     if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
     {
diff --git a/indra/newview/llfloatersocial.h b/indra/newview/llfloaterfacebook.h
similarity index 66%
rename from indra/newview/llfloatersocial.h
rename to indra/newview/llfloaterfacebook.h
index 585b265d9f17ed83eff87f00362441e304d3c450..34356412d6e7021f95eba8d1ae550484a318c99b 100644
--- a/indra/newview/llfloatersocial.h
+++ b/indra/newview/llfloaterfacebook.h
@@ -1,6 +1,6 @@
 /** 
-* @file   llfloatersocial.h
-* @brief  Header file for llfloatersocial
+* @file   llfloaterfacebook.h
+* @brief  Header file for llfloaterfacebook
 * @author Gilbert@lindenlab.com
 *
 * $LicenseInfo:firstyear=2013&license=viewerlgpl$
@@ -24,9 +24,10 @@
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */
-#ifndef LL_LLFLOATERSOCIAL_H
-#define LL_LLFLOATERSOCIAL_H
+#ifndef LL_LLFLOATERFACEBOOK_H
+#define LL_LLFLOATERFACEBOOK_H
 
+#include "llcallingcard.h"
 #include "llfloater.h"
 #include "lltextbox.h"
 #include "llviewertexture.h"
@@ -34,11 +35,13 @@
 class LLIconCtrl;
 class LLCheckBoxCtrl;
 class LLSnapshotLivePreview;
+class LLAvatarList;
+class LLFloaterBigPreview;
 
-class LLSocialStatusPanel : public LLPanel
+class LLFacebookStatusPanel : public LLPanel
 {
 public:
-    LLSocialStatusPanel();
+    LLFacebookStatusPanel();
 	BOOL postBuild();
 	void draw();
     void onSend();
@@ -53,19 +56,21 @@ class LLSocialStatusPanel : public LLPanel
 	LLUICtrl* mCancelButton;
 };
 
-class LLSocialPhotoPanel : public LLPanel
+class LLFacebookPhotoPanel : public LLPanel
 {
 public:
-	LLSocialPhotoPanel();
-	~LLSocialPhotoPanel();
+	LLFacebookPhotoPanel();
+	~LLFacebookPhotoPanel();
 
 	BOOL postBuild();
 	void draw();
 
 	LLSnapshotLivePreview* getPreviewView();
-	void onVisibilityChanged(const LLSD& new_visibility);
+	void onVisibilityChange(BOOL new_visibility);
+    void onClickBigPreview();
 	void onClickNewSnapshot();
 	void onSend();
+	S32 notify(const LLSD& info);
 	bool onFacebookConnectStateChange(const LLSD& data);
 
 	void sendPhoto();
@@ -77,22 +82,31 @@ class LLSocialPhotoPanel : public LLPanel
 	LLUICtrl* getRefreshBtn();
 
 private:
+    bool isPreviewVisible();
+    void attachPreview();
+    
 	LLHandle<LLView> mPreviewHandle;
 
 	LLUICtrl * mSnapshotPanel;
 	LLUICtrl * mResolutionComboBox;
+	LLUICtrl * mFilterComboBox;
 	LLUICtrl * mRefreshBtn;
 	LLUICtrl * mWorkingLabel;
 	LLUICtrl * mThumbnailPlaceholder;
 	LLUICtrl * mCaptionTextBox;
 	LLUICtrl * mPostButton;
-	LLUICtrl* mCancelButton;
+	LLUICtrl * mCancelButton;
+	LLButton * mBtnPreview;
+    
+    LLFloaterBigPreview * mBigPreviewFloater;
+    
+    S32 mQuality;       // Compression quality
 };
 
-class LLSocialCheckinPanel : public LLPanel
+class LLFacebookCheckinPanel : public LLPanel
 {
 public:
-    LLSocialCheckinPanel();
+    LLFacebookCheckinPanel();
 	BOOL postBuild();
 	void draw();
     void onSend();
@@ -114,15 +128,34 @@ class LLSocialCheckinPanel : public LLPanel
     bool mReloadingMapTexture;
 };
 
-class LLSocialAccountPanel : public LLPanel
+class LLFacebookFriendsPanel : public LLPanel, public LLFriendObserver
+{
+public:
+	LLFacebookFriendsPanel();
+	~LLFacebookFriendsPanel();
+	BOOL postBuild();
+	virtual void changed(U32 mask);
+
+private:
+	bool updateSuggestedFriendList();
+	void showFriendsAccordionsIfNeeded();
+	void updateFacebookList(bool visible);
+	bool onConnectedToFacebook(const LLSD& data);
+	
+	LLTextBox * mFriendsStatusCaption;
+	LLAvatarList* mSecondLifeFriends;
+	LLAvatarList* mSuggestedFriends;
+};
+
+class LLFacebookAccountPanel : public LLPanel
 {
 public:
-	LLSocialAccountPanel();
+	LLFacebookAccountPanel();
 	BOOL postBuild();
 	void draw();
 
 private:
-	void onVisibilityChanged(const LLSD& new_visibility);
+	void onVisibilityChange(BOOL new_visibility);
 	bool onFacebookConnectStateChange(const LLSD& data);
 	bool onFacebookConnectInfoChange();
 	void onConnect();
@@ -141,24 +174,23 @@ class LLSocialAccountPanel : public LLPanel
 	LLUICtrl * mDisconnectButton;
 };
 
-
-class LLFloaterSocial : public LLFloater
+class LLFloaterFacebook : public LLFloater
 {
 public:
-	LLFloaterSocial(const LLSD& key);
+	LLFloaterFacebook(const LLSD& key);
 	BOOL postBuild();
 	void draw();
+	void onClose(bool app_quitting);
 	void onCancel();
-
-	static void preUpdate();
-	static void postUpdate();
+	
+	void showPhotoPanel();
 
 private:
-	LLSocialPhotoPanel* mSocialPhotoPanel;
+	LLFacebookPhotoPanel* mFacebookPhotoPanel;
     LLTextBox* mStatusErrorText;
     LLTextBox* mStatusLoadingText;
     LLUICtrl*  mStatusLoadingIndicator;
 };
 
-#endif // LL_LLFLOATERSOCIAL_H
+#endif // LL_LLFLOATERFACEBOOK_H
 
diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4e6d98ecfabc5362ab07c498f863316eb2122bec
--- /dev/null
+++ b/indra/newview/llfloaterflickr.cpp
@@ -0,0 +1,798 @@
+/** 
+* @file llfloaterflickr.cpp
+* @brief Implementation of llfloaterflickr
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterflickr.h"
+
+#include "llagent.h"
+#include "llagentui.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "llflickrconnect.h"
+#include "llfloaterreg.h"
+#include "lliconctrl.h"
+#include "llimagefiltersmanager.h"
+#include "llresmgr.h"		// LLLocale
+#include "llsdserialize.h"
+#include "llloadingindicator.h"
+#include "llplugincookiestore.h"
+#include "llslurl.h"
+#include "lltrans.h"
+#include "llsnapshotlivepreview.h"
+#include "llfloaterbigpreview.h"
+#include "llviewerregion.h"
+#include "llviewercontrol.h"
+#include "llviewermedia.h"
+#include "lltabcontainer.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+
+static LLPanelInjector<LLFlickrPhotoPanel> t_panel_photo("llflickrphotopanel");
+static LLPanelInjector<LLFlickrAccountPanel> t_panel_account("llflickraccountpanel");
+
+const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
+const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=flickr&utm_medium=photo&utm_campaign=slshare";
+const std::string DEFAULT_TAG_TEXT = "secondlife ";
+const std::string FLICKR_MACHINE_TAGS_NAMESPACE = "secondlife";
+
+///////////////////////////
+//LLFlickrPhotoPanel///////
+///////////////////////////
+
+LLFlickrPhotoPanel::LLFlickrPhotoPanel() :
+mSnapshotPanel(NULL),
+mResolutionComboBox(NULL),
+mRefreshBtn(NULL),
+mBtnPreview(NULL),
+mWorkingLabel(NULL),
+mThumbnailPlaceholder(NULL),
+mTitleTextBox(NULL),
+mDescriptionTextBox(NULL),
+mLocationCheckbox(NULL),
+mTagsTextBox(NULL),
+mRatingComboBox(NULL),
+mBigPreviewFloater(NULL),
+mPostButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLFlickrPhotoPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLFlickrPhotoPanel::onClickNewSnapshot, this));
+	mCommitCallbackRegistrar.add("SocialSharing.BigPreview", boost::bind(&LLFlickrPhotoPanel::onClickBigPreview, this));
+}
+
+LLFlickrPhotoPanel::~LLFlickrPhotoPanel()
+{
+	if(mPreviewHandle.get())
+	{
+		mPreviewHandle.get()->die();
+	}
+}
+
+BOOL LLFlickrPhotoPanel::postBuild()
+{
+	setVisibleCallback(boost::bind(&LLFlickrPhotoPanel::onVisibilityChange, this, _2));
+	
+	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
+	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
+	mResolutionComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE));
+	mFilterComboBox = getChild<LLUICtrl>("filters_combobox");
+	mFilterComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE));
+	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
+	mBtnPreview = getChild<LLButton>("big_preview_btn");
+    mWorkingLabel = getChild<LLUICtrl>("working_lbl");
+	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
+	mTitleTextBox = getChild<LLUICtrl>("photo_title");
+	mDescriptionTextBox = getChild<LLUICtrl>("photo_description");
+	mLocationCheckbox = getChild<LLUICtrl>("add_location_cb");
+	mTagsTextBox = getChild<LLUICtrl>("photo_tags");
+	mTagsTextBox->setValue(DEFAULT_TAG_TEXT);
+	mRatingComboBox = getChild<LLUICtrl>("rating_combobox");
+	mPostButton = getChild<LLUICtrl>("post_photo_btn");
+	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
+	mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+
+	// Update filter list
+    std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList();
+	LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+    for (U32 i = 0; i < filter_list.size(); i++) 
+	{
+        filterbox->add(filter_list[i]);
+    }
+
+	return LLPanel::postBuild();
+}
+
+// virtual
+S32 LLFlickrPhotoPanel::notify(const LLSD& info)
+{
+	if (info.has("snapshot-updating"))
+	{
+        // Disable the Post button and whatever else while the snapshot is not updated
+        // updateControls();
+		return 1;
+	}
+    
+	if (info.has("snapshot-updated"))
+	{
+        // Enable the send/post/save buttons.
+        updateControls();
+        
+		// The refresh button is initially hidden. We show it after the first update,
+		// i.e. after snapshot is taken
+		LLUICtrl * refresh_button = getRefreshBtn();
+		if (!refresh_button->getVisible())
+		{
+			refresh_button->setVisible(true);
+		}
+		return 1;
+	}
+    
+	return 0;
+}
+
+void LLFlickrPhotoPanel::draw()
+{ 
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+
+    // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts)
+    bool no_ongoing_connection = !(LLFlickrConnect::instance().isTransactionOngoing());
+    mCancelButton->setEnabled(no_ongoing_connection);
+    mTitleTextBox->setEnabled(no_ongoing_connection);
+    mDescriptionTextBox->setEnabled(no_ongoing_connection);
+    mTagsTextBox->setEnabled(no_ongoing_connection);
+    mRatingComboBox->setEnabled(no_ongoing_connection);
+    mResolutionComboBox->setEnabled(no_ongoing_connection);
+    mFilterComboBox->setEnabled(no_ongoing_connection);
+    mRefreshBtn->setEnabled(no_ongoing_connection);
+    mBtnPreview->setEnabled(no_ongoing_connection);
+    mLocationCheckbox->setEnabled(no_ongoing_connection);
+    
+    // Reassign the preview floater if we have the focus and the preview exists
+    if (hasFocus() && isPreviewVisible())
+    {
+        attachPreview();
+    }
+    
+    // Toggle the button state as appropriate
+    bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType<LLFloater>()));
+	mBtnPreview->setToggleState(preview_active);
+    
+    // Display the preview if one is available
+	if (previewp && previewp->getThumbnailImage())
+	{
+		const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect();
+		const S32 thumbnail_w = previewp->getThumbnailWidth();
+		const S32 thumbnail_h = previewp->getThumbnailHeight();
+
+		// calc preview offset within the preview rect
+		const S32 local_offset_x = (thumbnail_rect.getWidth()  - thumbnail_w) / 2 ;
+		const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ;
+
+		// calc preview offset within the floater rect
+        // Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater.
+        // This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity.
+        // *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time.
+		S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1;
+		S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39;
+        
+		mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>());
+        
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		// Apply floater transparency to the texture unless the floater is focused.
+		F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+		LLColor4 color = LLColor4::white;
+		gl_draw_scaled_image(offset_x, offset_y, 
+			thumbnail_w, thumbnail_h,
+			previewp->getThumbnailImage(), color % alpha);
+	}
+
+    // Update the visibility of the working (computing preview) label
+    mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate()));
+    
+    // Enable Post if we have a preview to send and no on going connection being processed
+    mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate()));
+    
+    // Draw the rest of the panel on top of it
+	LLPanel::draw();
+}
+
+LLSnapshotLivePreview* LLFlickrPhotoPanel::getPreviewView()
+{
+	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
+	return previewp;
+}
+
+void LLFlickrPhotoPanel::onVisibilityChange(BOOL visible)
+{
+	if (visible)
+	{
+		if (mPreviewHandle.get())
+		{
+			LLSnapshotLivePreview* preview = getPreviewView();
+			if(preview)
+			{
+				lldebugs << "opened, updating snapshot" << llendl;
+				preview->updateSnapshot(TRUE);
+			}
+		}
+		else
+		{
+			LLRect full_screen_rect = getRootView()->getRect();
+			LLSnapshotLivePreview::Params p;
+			p.rect(full_screen_rect);
+			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
+			mPreviewHandle = previewp->getHandle();
+
+            previewp->setContainer(this);
+			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
+			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG);
+            previewp->setThumbnailSubsampled(TRUE);     // We want the preview to reflect the *saved* image
+            previewp->setAllowRenderUI(FALSE);          // We do not want the rendered UI in our snapshots
+            previewp->setAllowFullScreenPreview(FALSE);  // No full screen preview in SL Share mode
+			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
+
+			updateControls();
+		}
+	}
+}
+
+void LLFlickrPhotoPanel::onClickNewSnapshot()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	if (previewp)
+	{
+		previewp->updateSnapshot(TRUE);
+	}
+}
+
+void LLFlickrPhotoPanel::onClickBigPreview()
+{
+    // Toggle the preview
+    if (isPreviewVisible())
+    {
+        LLFloaterReg::hideInstance("big_preview");
+    }
+    else
+    {
+        attachPreview();
+        LLFloaterReg::showInstance("big_preview");
+    }
+}
+
+bool LLFlickrPhotoPanel::isPreviewVisible()
+{
+    return (mBigPreviewFloater && mBigPreviewFloater->getVisible());
+}
+
+void LLFlickrPhotoPanel::attachPreview()
+{
+    if (mBigPreviewFloater)
+    {
+        LLSnapshotLivePreview* previewp = getPreviewView();
+        mBigPreviewFloater->setPreview(previewp);
+        mBigPreviewFloater->setFloaterOwner(getParentByType<LLFloater>());
+    }
+}
+
+void LLFlickrPhotoPanel::onSend()
+{
+	LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrPhotoPanel", boost::bind(&LLFlickrPhotoPanel::onFlickrConnectStateChange, this, _1));
+	
+	// Connect to Flickr if necessary and then post
+	if (LLFlickrConnect::instance().isConnected())
+	{
+		sendPhoto();
+	}
+	else
+	{
+		LLFlickrConnect::instance().checkConnectionToFlickr(true);
+	}
+}
+
+bool LLFlickrPhotoPanel::onFlickrConnectStateChange(const LLSD& data)
+{
+	switch (data.get("enum").asInteger())
+	{
+		case LLFlickrConnect::FLICKR_CONNECTED:
+			sendPhoto();
+			break;
+
+		case LLFlickrConnect::FLICKR_POSTED:
+			LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel");
+			clearAndClose();
+			break;
+	}
+
+	return false;
+}
+
+void LLFlickrPhotoPanel::sendPhoto()
+{
+	// Get the title, description, and tags
+	std::string title = mTitleTextBox->getValue().asString();
+	std::string description = mDescriptionTextBox->getValue().asString();
+	std::string tags = mTagsTextBox->getValue().asString();
+
+	// Add the location if required
+	bool add_location = mLocationCheckbox->getValue().asBoolean();
+	if (add_location)
+	{
+		// Get the SLURL for the location
+		LLSLURL slurl;
+		LLAgentUI::buildSLURL(slurl);
+		std::string slurl_string = slurl.getSLURLString();
+
+		// Add query parameters so Google Analytics can track incoming clicks!
+		slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS;
+
+		std::string photo_link_text = "Visit this location";// at [] in Second Life";
+		std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName();
+		if (!parcel_name.empty())
+		{
+			photo_link_text += " at " + parcel_name;
+		}
+		photo_link_text += " in Second Life";
+
+		slurl_string = "<a href=\"" + slurl_string + "\">" + photo_link_text + "</a>";
+
+		// Add it to the description (pretty crude, but we don't have a better option with photos)
+		if (description.empty())
+			description = slurl_string;
+		else
+			description = description + "\n\n" + slurl_string;
+
+		// Also add special "machine tags" with location metadata
+		const LLVector3& agent_pos_region = gAgent.getPositionAgent();
+		LLViewerRegion* region = gAgent.getRegion();
+		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+		if (region && parcel)
+		{
+			S32 pos_x = S32(agent_pos_region.mV[VX]);
+			S32 pos_y = S32(agent_pos_region.mV[VY]);
+			S32 pos_z = S32(agent_pos_region.mV[VZ]);
+			
+			std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName();
+			std::string region_name = region->getName();
+			
+			if (!region_name.empty())
+			{
+				tags += llformat(" \"%s:region=%s\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), region_name.c_str());
+			}
+			if (!parcel_name.empty())
+			{
+				tags += llformat(" \"%s:parcel=%s\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), parcel_name.c_str());
+			}
+			tags += llformat(" \"%s:x=%d\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), pos_x);
+			tags += llformat(" \"%s:y=%d\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), pos_y);
+			tags += llformat(" \"%s:z=%d\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), pos_z);
+		}
+	}
+
+	// Get the content rating
+	int content_rating = mRatingComboBox->getValue().asInteger();
+
+	// Get the image
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	
+	// Post to Flickr
+	LLFlickrConnect::instance().uploadPhoto(previewp->getFormattedImage(), title, description, tags, content_rating);
+
+	updateControls();
+}
+
+void LLFlickrPhotoPanel::clearAndClose()
+{
+	mTitleTextBox->setValue("");
+	mDescriptionTextBox->setValue("");
+
+	LLFloater* floater = getParentByType<LLFloater>();
+	if (floater)
+	{
+		floater->closeFloater();
+        if (mBigPreviewFloater)
+        {
+            mBigPreviewFloater->closeOnFloaterOwnerClosing(floater);
+        }
+	}
+}
+
+void LLFlickrPhotoPanel::updateControls()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
+
+	// *TODO: Separate maximum size for Web images from postcards
+	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
+
+	updateResolution(FALSE);
+}
+
+void LLFlickrPhotoPanel::updateResolution(BOOL do_update)
+{
+	LLComboBox* combobox  = static_cast<LLComboBox *>(mResolutionComboBox);
+	LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+
+	std::string sdstring = combobox->getSelectedValue();
+	LLSD sdres;
+	std::stringstream sstream(sdstring);
+	LLSDSerialize::fromNotation(sdres, sstream, sdstring.size());
+
+	S32 width = sdres[0];
+	S32 height = sdres[1];
+    
+    // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale 
+    std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : "");
+
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+	if (previewp && combobox->getCurrentIndex() >= 0)
+	{
+		S32 original_width = 0 , original_height = 0 ;
+		previewp->getSize(original_width, original_height) ;
+
+		if (width == 0 || height == 0)
+		{
+			// take resolution from current window size
+			lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl;
+			previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
+		}
+		else
+		{
+			// use the resolution from the selected pre-canned drop-down choice
+			lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl;
+			previewp->setSize(width, height);
+		}
+
+		checkAspectRatio(width);
+
+		previewp->getSize(width, height);
+		if ((original_width != width) || (original_height != height))
+		{
+			previewp->setSize(width, height);
+			if (do_update)
+			{
+                previewp->updateSnapshot(TRUE);
+				updateControls();
+			}
+		}
+        // Get the old filter, compare to the current one "filter_name" and set if changed
+        std::string original_filter = previewp->getFilter();
+		if (original_filter != filter_name)
+		{
+            previewp->setFilter(filter_name);
+			if (do_update)
+			{
+                previewp->updateSnapshot(FALSE, TRUE);
+				updateControls();
+			}
+		}
+	}
+}
+
+void LLFlickrPhotoPanel::checkAspectRatio(S32 index)
+{
+	LLSnapshotLivePreview *previewp = getPreviewView() ;
+
+	BOOL keep_aspect = FALSE;
+
+	if (0 == index) // current window size
+	{
+		keep_aspect = TRUE;
+	}
+	else // predefined resolution
+	{
+		keep_aspect = FALSE;
+	}
+
+	if (previewp)
+	{
+		previewp->mKeepAspectRatio = keep_aspect;
+	}
+}
+
+LLUICtrl* LLFlickrPhotoPanel::getRefreshBtn()
+{
+	return mRefreshBtn;
+}
+
+///////////////////////////
+//LLFlickrAccountPanel//////
+///////////////////////////
+
+LLFlickrAccountPanel::LLFlickrAccountPanel() : 
+mAccountCaptionLabel(NULL),
+mAccountNameLabel(NULL),
+mPanelButtons(NULL),
+mConnectButton(NULL),
+mDisconnectButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLFlickrAccountPanel::onConnect, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLFlickrAccountPanel::onDisconnect, this));
+
+	setVisibleCallback(boost::bind(&LLFlickrAccountPanel::onVisibilityChange, this, _2));
+}
+
+BOOL LLFlickrAccountPanel::postBuild()
+{
+	mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
+	mAccountNameLabel = getChild<LLTextBox>("account_name_label");
+	mPanelButtons = getChild<LLUICtrl>("panel_buttons");
+	mConnectButton = getChild<LLUICtrl>("connect_btn");
+	mDisconnectButton = getChild<LLUICtrl>("disconnect_btn");
+
+	return LLPanel::postBuild();
+}
+
+void LLFlickrAccountPanel::draw()
+{
+	LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState();
+
+	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress
+	bool disconnecting = connection_state == LLFlickrConnect::FLICKR_DISCONNECTING;
+	mDisconnectButton->setEnabled(!disconnecting);
+
+	//Disable the 'connect' button when a connection is in progress
+	bool connecting = connection_state == LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS;
+	mConnectButton->setEnabled(!connecting);
+
+	LLPanel::draw();
+}
+
+void LLFlickrAccountPanel::onVisibilityChange(BOOL visible)
+{
+	if(visible)
+	{
+		LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel");
+		LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectStateChange, this, _1));
+
+		LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel");
+		LLEventPumps::instance().obtain("FlickrConnectInfo").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectInfoChange, this));
+
+		//Connected
+		if(LLFlickrConnect::instance().isConnected())
+		{
+			showConnectedLayout();
+		}
+		//Check if connected (show disconnected layout in meantime)
+		else
+		{
+			showDisconnectedLayout();
+		}
+        if ((LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_NOT_CONNECTED) ||
+            (LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_CONNECTION_FAILED))
+        {
+            LLFlickrConnect::instance().checkConnectionToFlickr();
+        }
+	}
+	else
+	{
+		LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel");
+		LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel");
+	}
+}
+
+bool LLFlickrAccountPanel::onFlickrConnectStateChange(const LLSD& data)
+{
+	if(LLFlickrConnect::instance().isConnected())
+	{
+		//In process of disconnecting so leave the layout as is
+		if(data.get("enum").asInteger() != LLFlickrConnect::FLICKR_DISCONNECTING)
+		{
+			showConnectedLayout();
+		}
+	}
+	else
+	{
+		showDisconnectedLayout();
+	}
+
+	return false;
+}
+
+bool LLFlickrAccountPanel::onFlickrConnectInfoChange()
+{
+	LLSD info = LLFlickrConnect::instance().getInfo();
+	std::string clickable_name;
+
+	//Strings of format [http://www.somewebsite.com Click Me] become clickable text
+	if(info.has("link") && info.has("name"))
+	{
+		clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]";
+	}
+
+	mAccountNameLabel->setText(clickable_name);
+
+	return false;
+}
+
+void LLFlickrAccountPanel::showConnectButton()
+{
+	if(!mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(TRUE);
+		mDisconnectButton->setVisible(FALSE);
+	}
+}
+
+void LLFlickrAccountPanel::hideConnectButton()
+{
+	if(mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(FALSE);
+		mDisconnectButton->setVisible(TRUE);
+	}
+}
+
+void LLFlickrAccountPanel::showDisconnectedLayout()
+{
+	mAccountCaptionLabel->setText(getString("flickr_disconnected"));
+	mAccountNameLabel->setText(std::string(""));
+	showConnectButton();
+}
+
+void LLFlickrAccountPanel::showConnectedLayout()
+{
+	LLFlickrConnect::instance().loadFlickrInfo();
+
+	mAccountCaptionLabel->setText(getString("flickr_connected"));
+	hideConnectButton();
+}
+
+void LLFlickrAccountPanel::onConnect()
+{
+	LLFlickrConnect::instance().checkConnectionToFlickr(true);
+
+	//Clear only the flickr browser cookies so that the flickr login screen appears
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com"); 
+}
+
+void LLFlickrAccountPanel::onDisconnect()
+{
+	LLFlickrConnect::instance().disconnectFromFlickr();
+
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com"); 
+}
+
+////////////////////////
+//LLFloaterFlickr///////
+////////////////////////
+
+LLFloaterFlickr::LLFloaterFlickr(const LLSD& key) : LLFloater(key),
+    mFlickrPhotoPanel(NULL),
+    mStatusErrorText(NULL),
+    mStatusLoadingText(NULL),
+    mStatusLoadingIndicator(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterFlickr::onCancel, this));
+}
+
+void LLFloaterFlickr::onClose(bool app_quitting)
+{
+    LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+    if (big_preview_floater)
+    {
+        big_preview_floater->closeOnFloaterOwnerClosing(this);
+    }
+	LLFloater::onClose(app_quitting);
+}
+
+void LLFloaterFlickr::onCancel()
+{
+    LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+    if (big_preview_floater)
+    {
+        big_preview_floater->closeOnFloaterOwnerClosing(this);
+    }
+    closeFloater();
+}
+
+BOOL LLFloaterFlickr::postBuild()
+{
+    // Keep tab of the Photo Panel
+	mFlickrPhotoPanel = static_cast<LLFlickrPhotoPanel*>(getChild<LLUICtrl>("panel_flickr_photo"));
+    // Connection status widgets
+    mStatusErrorText = getChild<LLTextBox>("connection_error_text");
+    mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
+    mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator");
+	return LLFloater::postBuild();
+}
+
+void LLFloaterFlickr::showPhotoPanel()
+{
+	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mFlickrPhotoPanel->getParent());
+	if (!parent)
+	{
+		llwarns << "Cannot find panel container" << llendl;
+		return;
+	}
+
+	parent->selectTabPanel(mFlickrPhotoPanel);
+}
+
+void LLFloaterFlickr::draw()
+{
+    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
+    {
+        mStatusErrorText->setVisible(false);
+        mStatusLoadingText->setVisible(false);
+        mStatusLoadingIndicator->setVisible(false);
+        LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState();
+        std::string status_text;
+        
+        switch (connection_state)
+        {
+        case LLFlickrConnect::FLICKR_NOT_CONNECTED:
+            // No status displayed when first opening the panel and no connection done
+        case LLFlickrConnect::FLICKR_CONNECTED:
+            // When successfully connected, no message is displayed
+        case LLFlickrConnect::FLICKR_POSTED:
+            // No success message to show since we actually close the floater after successful posting completion
+            break;
+        case LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS:
+            // Connection loading indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrConnecting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+            break;
+        case LLFlickrConnect::FLICKR_POSTING:
+            // Posting indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrPosting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+			break;
+        case LLFlickrConnect::FLICKR_CONNECTION_FAILED:
+            // Error connecting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrErrorConnecting");
+            mStatusErrorText->setValue(status_text);
+            break;
+        case LLFlickrConnect::FLICKR_POST_FAILED:
+            // Error posting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrErrorPosting");
+            mStatusErrorText->setValue(status_text);
+            break;
+		case LLFlickrConnect::FLICKR_DISCONNECTING:
+			// Disconnecting loading indicator
+			mStatusLoadingText->setVisible(true);
+			status_text = LLTrans::getString("SocialFlickrDisconnecting");
+			mStatusLoadingText->setValue(status_text);
+			mStatusLoadingIndicator->setVisible(true);
+			break;
+		case LLFlickrConnect::FLICKR_DISCONNECT_FAILED:
+			// Error disconnecting from the service
+			mStatusErrorText->setVisible(true);
+			status_text = LLTrans::getString("SocialFlickrErrorDisconnecting");
+			mStatusErrorText->setValue(status_text);
+			break;
+        }
+    }
+	LLFloater::draw();
+}
+
diff --git a/indra/newview/llfloaterflickr.h b/indra/newview/llfloaterflickr.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba27c9a3d8bccbebf320f4a86c9731ab3f63932f
--- /dev/null
+++ b/indra/newview/llfloaterflickr.h
@@ -0,0 +1,135 @@
+/** 
+* @file   llfloaterflickr.h
+* @brief  Header file for llfloaterflickr
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLFLOATERFLICKR_H
+#define LL_LLFLOATERFLICKR_H
+
+#include "llfloater.h"
+#include "lltextbox.h"
+#include "llviewertexture.h"
+
+class LLIconCtrl;
+class LLCheckBoxCtrl;
+class LLSnapshotLivePreview;
+class LLFloaterBigPreview;
+
+class LLFlickrPhotoPanel : public LLPanel
+{
+public:
+	LLFlickrPhotoPanel();
+	~LLFlickrPhotoPanel();
+
+	BOOL postBuild();
+	S32 notify(const LLSD& info);
+	void draw();
+
+	LLSnapshotLivePreview* getPreviewView();
+	void onVisibilityChange(BOOL new_visibility);
+	void onClickNewSnapshot();
+    void onClickBigPreview();
+	void onSend();
+	bool onFlickrConnectStateChange(const LLSD& data);
+
+	void sendPhoto();
+	void clearAndClose();
+
+	void updateControls();
+	void updateResolution(BOOL do_update);
+	void checkAspectRatio(S32 index);
+	LLUICtrl* getRefreshBtn();
+
+private:
+    bool isPreviewVisible();
+    void attachPreview();
+
+	LLHandle<LLView> mPreviewHandle;
+
+	LLUICtrl * mSnapshotPanel;
+	LLUICtrl * mResolutionComboBox;
+	LLUICtrl * mFilterComboBox;
+	LLUICtrl * mRefreshBtn;
+	LLUICtrl * mWorkingLabel;
+	LLUICtrl * mThumbnailPlaceholder;
+	LLUICtrl * mTitleTextBox;
+	LLUICtrl * mDescriptionTextBox;
+	LLUICtrl * mLocationCheckbox;
+	LLUICtrl * mTagsTextBox;
+	LLUICtrl * mRatingComboBox;
+	LLUICtrl * mPostButton;
+	LLUICtrl * mCancelButton;
+	LLButton * mBtnPreview;
+
+    LLFloaterBigPreview * mBigPreviewFloater;
+};
+
+class LLFlickrAccountPanel : public LLPanel
+{
+public:
+	LLFlickrAccountPanel();
+	BOOL postBuild();
+	void draw();
+
+private:
+	void onVisibilityChange(BOOL new_visibility);
+	bool onFlickrConnectStateChange(const LLSD& data);
+	bool onFlickrConnectInfoChange();
+	void onConnect();
+	void onUseAnotherAccount();
+	void onDisconnect();
+
+	void showConnectButton();
+	void hideConnectButton();
+	void showDisconnectedLayout();
+	void showConnectedLayout();
+
+	LLTextBox * mAccountCaptionLabel;
+	LLTextBox * mAccountNameLabel;
+	LLUICtrl * mPanelButtons;
+	LLUICtrl * mConnectButton;
+	LLUICtrl * mDisconnectButton;
+};
+
+
+class LLFloaterFlickr : public LLFloater
+{
+public:
+	LLFloaterFlickr(const LLSD& key);
+	BOOL postBuild();
+	void draw();
+	void onClose(bool app_quitting);
+	void onCancel();
+	
+	void showPhotoPanel();
+
+private:
+	LLFlickrPhotoPanel* mFlickrPhotoPanel;
+    LLTextBox* mStatusErrorText;
+    LLTextBox* mStatusLoadingText;
+    LLUICtrl*  mStatusLoadingIndicator;
+};
+
+#endif // LL_LLFLOATERFLICKR_H
+
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 3d5b297fbeb703566c2d1fd1c4f655662e46e963..960d3f35dd4bf4d8b41b4877791d8b06d85297a5 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -31,7 +31,10 @@
 #include "llagent.h"
 #include "llfacebookconnect.h"
 #include "llfloaterreg.h"
-#include "llfloatersocial.h"
+#include "llfloaterfacebook.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
+#include "llimagefiltersmanager.h"
 #include "llcheckboxctrl.h"
 #include "llcombobox.h"
 #include "llpostcard.h"
@@ -91,6 +94,7 @@ class LLFloaterSnapshot::Impl
 	}
 	static void onClickNewSnapshot(void* data);
 	static void onClickAutoSnap(LLUICtrl *ctrl, void* data);
+	static void onClickFilter(LLUICtrl *ctrl, void* data);
 	//static void onClickAdvanceSnap(LLUICtrl *ctrl, void* data);
 	static void onClickMore(void* data) ;
 	static void onClickUICheck(LLUICtrl *ctrl, void* data);
@@ -429,9 +433,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 	image_res_tb->setVisible(got_snap);
 	if (got_snap)
 	{
-		LLPointer<LLImageRaw> img = previewp->getEncodedImage();
-		image_res_tb->setTextArg("[WIDTH]", llformat("%d", img->getWidth()));
-		image_res_tb->setTextArg("[HEIGHT]", llformat("%d", img->getHeight()));
+		image_res_tb->setTextArg("[WIDTH]", llformat("%d", previewp->getEncodedImageWidth()));
+		image_res_tb->setTextArg("[HEIGHT]", llformat("%d", previewp->getEncodedImageHeight()));
 	}
 
 	floater->getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : floater->getString("unknown"));
@@ -464,8 +467,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 	  default:
 		break;
 	}
-
-	if (previewp)
+    
+    if (previewp)
 	{
 		previewp->setSnapshotType(shot_type);
 		previewp->setSnapshotFormat(shot_format);
@@ -558,6 +561,26 @@ void LLFloaterSnapshot::Impl::onClickAutoSnap(LLUICtrl *ctrl, void* data)
 	}
 }
 
+// static
+void LLFloaterSnapshot::Impl::onClickFilter(LLUICtrl *ctrl, void* data)
+{
+	LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
+	if (view)
+	{
+		updateControls(view);
+        LLSnapshotLivePreview* previewp = getPreviewView(view);
+        if (previewp)
+        {
+            checkAutoSnapshot(previewp);
+            // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale
+            LLComboBox* filterbox = static_cast<LLComboBox *>(view->getChild<LLComboBox>("filters_combobox"));
+            std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : "");
+            previewp->setFilter(filter_name);
+            previewp->updateSnapshot(FALSE, TRUE);
+        }
+	}
+}
+
 void LLFloaterSnapshot::Impl::onClickMore(void* data)
 {
 	BOOL visible = gSavedSettings.getBOOL("AdvanceSnapshot");
@@ -618,7 +641,7 @@ void LLFloaterSnapshot::Impl::applyKeepAspectCheck(LLFloaterSnapshot* view, BOOL
 
 			LL_DEBUGS() << "updating thumbnail" << LL_ENDL;
 			previewp->setSize(w, h) ;
-			previewp->updateSnapshot(FALSE, TRUE);
+			previewp->updateSnapshot(TRUE);
 			checkAutoSnapshot(previewp, TRUE);
 		}
 	}
@@ -853,7 +876,6 @@ void LLFloaterSnapshot::Impl::onImageQualityChange(LLFloaterSnapshot* view, S32
 	{
 		previewp->setSnapshotQuality(quality_val);
 	}
-	checkAutoSnapshot(previewp, TRUE);
 }
 
 // static
@@ -1052,7 +1074,26 @@ BOOL LLFloaterSnapshot::postBuild()
 
 	getChild<LLUICtrl>("auto_snapshot_check")->setValue(gSavedSettings.getBOOL("AutoSnapshot"));
 	childSetCommitCallback("auto_snapshot_check", Impl::onClickAutoSnap, this);
-	
+    
+	// Filters
+	LLComboBox* filterbox = getChild<LLComboBox>("filters_combobox");
+    if (gSavedSettings.getBOOL("SnapshotFiltersEnabled"))
+    {
+        // Update filter list if setting is on (experimental)
+        std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList();
+        for (U32 i = 0; i < filter_list.size(); i++)
+        {
+            filterbox->add(filter_list[i]);
+        }
+        childSetCommitCallback("filters_combobox", Impl::onClickFilter, this);
+    }
+    else
+    {
+        // Hide Filter UI if setting is off (default)
+        getChild<LLUICtrl>("filter_list_label")->setVisible(FALSE);
+        filterbox->setVisible(FALSE);
+    }
+    
 	LLWebProfile::setImageUploadResultCallback(boost::bind(&LLFloaterSnapshot::Impl::onSnapshotUploadFinished, _1));
 	LLPostCard::setPostResultCallback(boost::bind(&LLFloaterSnapshot::Impl::onSendingPostcardFinished, _1));
 
@@ -1082,6 +1123,7 @@ BOOL LLFloaterSnapshot::postBuild()
 	getChild<LLComboBox>("local_format_combo")->selectNthItem(0);
 
 	impl.mPreviewHandle = previewp->getHandle();
+    previewp->setContainer(this);
 	impl.updateControls(this);
 	impl.updateLayout(this);
 	
@@ -1246,6 +1288,32 @@ S32 LLFloaterSnapshot::notify(const LLSD& info)
 		impl.setStatus(Impl::STATUS_FINISHED, data["ok"].asBoolean(), data["msg"].asString());
 		return 1;
 	}
+    
+	if (info.has("snapshot-updating"))
+	{
+        // Disable the send/post/save buttons until snapshot is ready.
+        impl.updateControls(this);
+        // Force hiding the "Refresh to save" hint because we know we've just started refresh.
+        impl.setNeedRefresh(this, false);
+		return 1;
+	}
+
+	if (info.has("snapshot-updated"))
+	{
+        // Enable the send/post/save buttons.
+        impl.updateControls(this);
+        // We've just done refresh.
+        impl.setNeedRefresh(this, false);
+            
+        // The refresh button is initially hidden. We show it after the first update,
+        // i.e. when preview appears.
+        if (!mRefreshBtn->getVisible())
+        {
+            mRefreshBtn->setVisible(true);
+        }
+		return 1;
+	}    
+    
 	return 0;
 }
 
@@ -1253,9 +1321,11 @@ S32 LLFloaterSnapshot::notify(const LLSD& info)
 void LLFloaterSnapshot::update()
 {
 	LLFloaterSnapshot* inst = findInstance();
-	LLFloaterSocial* floater_social  = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); 
+	LLFloaterFacebook* floater_facebook = LLFloaterReg::findTypedInstance<LLFloaterFacebook>("facebook"); 
+	LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); 
+	LLFloaterTwitter* floater_twitter = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); 
 
-	if (!inst && !floater_social)
+	if (!inst && !floater_facebook && !floater_flickr && !floater_twitter)
 		return;
 	
 	BOOL changed = FALSE;
@@ -1328,43 +1398,6 @@ BOOL LLFloaterSnapshot::saveLocal()
 	return previewp->saveLocal();
 }
 
-// static
-void LLFloaterSnapshot::preUpdate()
-{
-	// FIXME: duplicated code
-	LLFloaterSnapshot* instance = findInstance();
-	if (instance)
-	{
-		// Disable the send/post/save buttons until snapshot is ready.
-		Impl::updateControls(instance);
-
-		// Force hiding the "Refresh to save" hint because we know we've just started refresh.
-		Impl::setNeedRefresh(instance, false);
-	}
-}
-
-// static
-void LLFloaterSnapshot::postUpdate()
-{
-	// FIXME: duplicated code
-	LLFloaterSnapshot* instance = findInstance();
-	if (instance)
-	{
-		// Enable the send/post/save buttons.
-		Impl::updateControls(instance);
-
-		// We've just done refresh.
-		Impl::setNeedRefresh(instance, false);
-
-		// The refresh button is initially hidden. We show it after the first update,
-		// i.e. when preview appears.
-		if (!instance->mRefreshBtn->getVisible())
-		{
-			instance->mRefreshBtn->setVisible(true);
-		}
-	}
-}
-
 // static
 void LLFloaterSnapshot::postSave()
 {
diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h
index c757bf21c284273a7f907b937481a71c93c61584..0bb9474bb5de72acac21028abb00c17d566a6ca2 100755
--- a/indra/newview/llfloatersnapshot.h
+++ b/indra/newview/llfloatersnapshot.h
@@ -59,8 +59,6 @@ class LLFloaterSnapshot : public LLFloater
 	static LLFloaterSnapshot* findInstance();
 	static void saveTexture();
 	static BOOL saveLocal();
-	static void preUpdate();
-	static void postUpdate();
 	static void postSave();
 	static void postPanelSwitch();
 	static LLPointer<LLImageFormatted> getImageData();
diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..78e9259919cc27c205a66f3fae023f2a40bbcab5
--- /dev/null
+++ b/indra/newview/llfloatertwitter.cpp
@@ -0,0 +1,827 @@
+/** 
+* @file llfloatertwitter.cpp
+* @brief Implementation of llfloatertwitter
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatertwitter.h"
+
+#include "llagent.h"
+#include "llagentui.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "lltwitterconnect.h"
+#include "llfloaterbigpreview.h"
+#include "llfloaterreg.h"
+#include "lliconctrl.h"
+#include "llimagefiltersmanager.h"
+#include "llresmgr.h"		// LLLocale
+#include "llsdserialize.h"
+#include "llloadingindicator.h"
+#include "llplugincookiestore.h"
+#include "llslurl.h"
+#include "lltrans.h"
+#include "llsnapshotlivepreview.h"
+#include "llviewerregion.h"
+#include "llviewercontrol.h"
+#include "llviewermedia.h"
+#include "lltabcontainer.h"
+#include "lltexteditor.h"
+
+static LLPanelInjector<LLTwitterPhotoPanel> t_panel_photo("lltwitterphotopanel");
+static LLPanelInjector<LLTwitterAccountPanel> t_panel_account("lltwitteraccountpanel");
+
+const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
+const std::string DEFAULT_PHOTO_LOCATION_URL = "http://maps.secondlife.com/";
+const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=twitter&utm_medium=photo&utm_campaign=slshare";
+const std::string DEFAULT_STATUS_TEXT = " #SecondLife";
+
+///////////////////////////
+//LLTwitterPhotoPanel///////
+///////////////////////////
+
+LLTwitterPhotoPanel::LLTwitterPhotoPanel() :
+mSnapshotPanel(NULL),
+mResolutionComboBox(NULL),
+mRefreshBtn(NULL),
+mBtnPreview(NULL),
+mWorkingLabel(NULL),
+mThumbnailPlaceholder(NULL),
+mStatusCounterLabel(NULL),
+mStatusTextBox(NULL),
+mLocationCheckbox(NULL),
+mPhotoCheckbox(NULL),
+mBigPreviewFloater(NULL),
+mPostButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLTwitterPhotoPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLTwitterPhotoPanel::onClickNewSnapshot, this));
+	mCommitCallbackRegistrar.add("SocialSharing.BigPreview", boost::bind(&LLTwitterPhotoPanel::onClickBigPreview, this));
+}
+
+LLTwitterPhotoPanel::~LLTwitterPhotoPanel()
+{
+	if(mPreviewHandle.get())
+	{
+		mPreviewHandle.get()->die();
+	}
+}
+
+BOOL LLTwitterPhotoPanel::postBuild()
+{
+	setVisibleCallback(boost::bind(&LLTwitterPhotoPanel::onVisibilityChange, this, _2));
+	
+	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
+	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
+	mResolutionComboBox->setValue("[i800,i600]"); // hardcoded defaults ftw!
+	mResolutionComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE));
+	mFilterComboBox = getChild<LLUICtrl>("filters_combobox");
+	mFilterComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE));
+	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
+	mBtnPreview = getChild<LLButton>("big_preview_btn");
+    mWorkingLabel = getChild<LLUICtrl>("working_lbl");
+	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
+	mStatusCounterLabel = getChild<LLUICtrl>("status_counter_label");
+	mStatusTextBox = getChild<LLUICtrl>("photo_status");
+	mStatusTextBox->setValue(DEFAULT_STATUS_TEXT);
+	mLocationCheckbox = getChild<LLUICtrl>("add_location_cb");
+	mLocationCheckbox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::onAddLocationToggled, this));
+	mPhotoCheckbox = getChild<LLUICtrl>("add_photo_cb");
+	mPhotoCheckbox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::onAddPhotoToggled, this));
+	mPostButton = getChild<LLUICtrl>("post_photo_btn");
+	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
+	mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+
+	// Update filter list
+    std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList();
+	LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+    for (U32 i = 0; i < filter_list.size(); i++)
+	{
+        filterbox->add(filter_list[i]);
+    }
+
+	return LLPanel::postBuild();
+}
+
+// virtual
+S32 LLTwitterPhotoPanel::notify(const LLSD& info)
+{
+	if (info.has("snapshot-updating"))
+	{
+        // Disable the Post button and whatever else while the snapshot is not updated
+        // updateControls();
+		return 1;
+	}
+    
+	if (info.has("snapshot-updated"))
+	{
+        // Enable the send/post/save buttons.
+        updateControls();
+        
+		// The refresh button is initially hidden. We show it after the first update,
+		// i.e. after snapshot is taken
+		LLUICtrl * refresh_button = getRefreshBtn();
+		if (!refresh_button->getVisible())
+		{
+			refresh_button->setVisible(true);
+		}
+		return 1;
+	}
+    
+	return 0;
+}
+
+void LLTwitterPhotoPanel::draw()
+{ 
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+
+    // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts)
+    bool no_ongoing_connection = !(LLTwitterConnect::instance().isTransactionOngoing());
+    bool photo_checked = mPhotoCheckbox->getValue().asBoolean();
+    mCancelButton->setEnabled(no_ongoing_connection);
+    mStatusTextBox->setEnabled(no_ongoing_connection);
+    mResolutionComboBox->setEnabled(no_ongoing_connection && photo_checked);
+    mFilterComboBox->setEnabled(no_ongoing_connection && photo_checked);
+    mRefreshBtn->setEnabled(no_ongoing_connection && photo_checked);
+    mBtnPreview->setEnabled(no_ongoing_connection);
+    mLocationCheckbox->setEnabled(no_ongoing_connection);
+    mPhotoCheckbox->setEnabled(no_ongoing_connection);
+
+	bool add_location = mLocationCheckbox->getValue().asBoolean();
+	bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+	updateStatusTextLength(false);
+
+    // Reassign the preview floater if we have the focus and the preview exists
+    if (hasFocus() && isPreviewVisible())
+    {
+        attachPreview();
+    }
+    
+    // Toggle the button state as appropriate
+    bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType<LLFloater>()));
+	mBtnPreview->setToggleState(preview_active);
+    
+    // Display the preview if one is available
+	if (previewp && previewp->getThumbnailImage())
+	{
+		const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect();
+		const S32 thumbnail_w = previewp->getThumbnailWidth();
+		const S32 thumbnail_h = previewp->getThumbnailHeight();
+
+		// calc preview offset within the preview rect
+		const S32 local_offset_x = (thumbnail_rect.getWidth()  - thumbnail_w) / 2 ;
+		const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ;
+
+		// calc preview offset within the floater rect
+        // Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater.
+        // This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity.
+        // *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time.
+		S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1;
+		S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39;
+        
+		mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>());
+        
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		// Apply floater transparency to the texture unless the floater is focused.
+		F32 alpha = (add_photo ? (getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency()) : 0.5f);
+		LLColor4 color = LLColor4::white;
+		gl_draw_scaled_image(offset_x, offset_y, 
+			thumbnail_w, thumbnail_h,
+			previewp->getThumbnailImage(), color % alpha);
+	}
+
+    // Update the visibility of the working (computing preview) label
+    mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate()));
+    
+    // Enable Post if we have a preview to send and no on going connection being processed
+    mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate()) && (add_photo || add_location || !mStatusTextBox->getValue().asString().empty()));
+    
+    // Draw the rest of the panel on top of it
+	LLPanel::draw();
+}
+
+LLSnapshotLivePreview* LLTwitterPhotoPanel::getPreviewView()
+{
+	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
+	return previewp;
+}
+
+void LLTwitterPhotoPanel::onVisibilityChange(BOOL visible)
+{
+	if (visible)
+	{
+		if (mPreviewHandle.get())
+		{
+			LLSnapshotLivePreview* preview = getPreviewView();
+			if(preview)
+			{
+				lldebugs << "opened, updating snapshot" << llendl;
+				preview->updateSnapshot(TRUE);
+			}
+		}
+		else
+		{
+			LLRect full_screen_rect = getRootView()->getRect();
+			LLSnapshotLivePreview::Params p;
+			p.rect(full_screen_rect);
+			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
+			mPreviewHandle = previewp->getHandle();
+
+            previewp->setContainer(this);
+			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
+			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
+            previewp->setThumbnailSubsampled(TRUE);     // We want the preview to reflect the *saved* image
+            previewp->setAllowRenderUI(FALSE);          // We do not want the rendered UI in our snapshots
+            previewp->setAllowFullScreenPreview(FALSE);  // No full screen preview in SL Share mode
+			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
+
+			updateControls();
+		}
+	}
+}
+
+void LLTwitterPhotoPanel::onAddLocationToggled()
+{
+	bool add_location = mLocationCheckbox->getValue().asBoolean();
+	updateStatusTextLength(!add_location);
+}
+
+void LLTwitterPhotoPanel::onAddPhotoToggled()
+{
+	bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+	updateStatusTextLength(!add_photo);
+}
+
+void LLTwitterPhotoPanel::onClickNewSnapshot()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	if (previewp)
+	{
+		previewp->updateSnapshot(TRUE);
+	}
+}
+
+void LLTwitterPhotoPanel::onClickBigPreview()
+{
+    // Toggle the preview
+    if (isPreviewVisible())
+    {
+        LLFloaterReg::hideInstance("big_preview");
+    }
+    else
+    {
+        attachPreview();
+        LLFloaterReg::showInstance("big_preview");
+    }
+}
+
+bool LLTwitterPhotoPanel::isPreviewVisible()
+{
+    return (mBigPreviewFloater && mBigPreviewFloater->getVisible());
+}
+
+void LLTwitterPhotoPanel::attachPreview()
+{
+    if (mBigPreviewFloater)
+    {
+        LLSnapshotLivePreview* previewp = getPreviewView();
+        mBigPreviewFloater->setPreview(previewp);
+        mBigPreviewFloater->setFloaterOwner(getParentByType<LLFloater>());
+    }
+}
+
+void LLTwitterPhotoPanel::onSend()
+{
+	LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterPhotoPanel", boost::bind(&LLTwitterPhotoPanel::onTwitterConnectStateChange, this, _1));
+	
+	// Connect to Twitter if necessary and then post
+	if (LLTwitterConnect::instance().isConnected())
+	{
+		sendPhoto();
+	}
+	else
+	{
+		LLTwitterConnect::instance().checkConnectionToTwitter(true);
+	}
+}
+
+bool LLTwitterPhotoPanel::onTwitterConnectStateChange(const LLSD& data)
+{
+	switch (data.get("enum").asInteger())
+	{
+		case LLTwitterConnect::TWITTER_CONNECTED:
+			sendPhoto();
+			break;
+
+		case LLTwitterConnect::TWITTER_POSTED:
+			LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel");
+			clearAndClose();
+			break;
+	}
+
+	return false;
+}
+
+void LLTwitterPhotoPanel::sendPhoto()
+{
+	// Get the status text
+	std::string status = mStatusTextBox->getValue().asString();
+	
+	// Add the location if required
+	bool add_location = mLocationCheckbox->getValue().asBoolean();
+	if (add_location)
+	{
+		// Get the SLURL for the location
+		LLSLURL slurl;
+		LLAgentUI::buildSLURL(slurl);
+		std::string slurl_string = slurl.getSLURLString();
+
+		// Use a valid http:// URL if the scheme is secondlife:// 
+		LLURI slurl_uri(slurl_string);
+		if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
+		{
+			slurl_string = DEFAULT_PHOTO_LOCATION_URL;
+		}
+
+		// Add query parameters so Google Analytics can track incoming clicks!
+		slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS;
+
+		// Add it to the status (pretty crude, but we don't have a better option with photos)
+		if (status.empty())
+			status = slurl_string;
+		else
+			status = status + " " + slurl_string;
+	}
+
+	// Add the photo if required
+	bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+	if (add_photo)
+	{
+		// Get the image
+		LLSnapshotLivePreview* previewp = getPreviewView();
+	
+		// Post to Twitter
+		LLTwitterConnect::instance().uploadPhoto(previewp->getFormattedImage(), status);
+	}
+	else
+	{
+		// Just post the status to Twitter
+		LLTwitterConnect::instance().updateStatus(status);
+	}
+
+	updateControls();
+}
+
+void LLTwitterPhotoPanel::clearAndClose()
+{
+	mStatusTextBox->setValue(DEFAULT_STATUS_TEXT);
+
+	LLFloater* floater = getParentByType<LLFloater>();
+	if (floater)
+	{
+		floater->closeFloater();
+        if (mBigPreviewFloater)
+        {
+            mBigPreviewFloater->closeOnFloaterOwnerClosing(floater);
+        }
+	}
+}
+
+void LLTwitterPhotoPanel::updateStatusTextLength(BOOL restore_old_status_text)
+{
+	bool add_location = mLocationCheckbox->getValue().asBoolean();
+	bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+
+	// Restrict the status text length to Twitter's character limit
+	LLTextEditor* status_text_box = dynamic_cast<LLTextEditor*>(mStatusTextBox);
+	if (status_text_box)
+	{
+		int max_status_length = 140 - (add_location ? 40 : 0) - (add_photo ? 40 : 0);
+		status_text_box->setMaxTextLength(max_status_length);
+		if (restore_old_status_text)
+		{
+			if (mOldStatusText.length() > status_text_box->getText().length() && status_text_box->getText() == mOldStatusText.substr(0, status_text_box->getText().length()))
+			{
+				status_text_box->setText(mOldStatusText);
+			}
+			if (mOldStatusText.length() <= max_status_length)
+			{
+				mOldStatusText = "";
+			}
+		}
+		if (status_text_box->getText().length() > max_status_length)
+		{
+			if (mOldStatusText.length() < status_text_box->getText().length() || status_text_box->getText() != mOldStatusText.substr(0, status_text_box->getText().length()))
+			{
+				mOldStatusText = status_text_box->getText();
+			}
+			status_text_box->setText(mOldStatusText.substr(0, max_status_length));
+		}
+
+		// Update the status character counter
+		int characters_remaining = max_status_length - status_text_box->getText().length();
+		mStatusCounterLabel->setValue(characters_remaining);
+	}
+
+}
+
+void LLTwitterPhotoPanel::updateControls()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
+    
+	// *TODO: Separate maximum size for Web images from postcards
+	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
+    
+	updateResolution(FALSE);
+}
+
+void LLTwitterPhotoPanel::updateResolution(BOOL do_update)
+{
+	LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+	LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+
+	std::string sdstring = combobox->getSelectedValue();
+	LLSD sdres;
+	std::stringstream sstream(sdstring);
+	LLSDSerialize::fromNotation(sdres, sstream, sdstring.size());
+
+	S32 width = sdres[0];
+	S32 height = sdres[1];
+
+    // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale
+    std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : "");
+
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+	if (previewp && combobox->getCurrentIndex() >= 0)
+	{
+		S32 original_width = 0 , original_height = 0 ;
+		previewp->getSize(original_width, original_height) ;
+
+		if (width == 0 || height == 0)
+		{
+			// take resolution from current window size
+			lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl;
+			previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
+		}
+		else
+		{
+			// use the resolution from the selected pre-canned drop-down choice
+			lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl;
+			previewp->setSize(width, height);
+		}
+
+		checkAspectRatio(width);
+
+		previewp->getSize(width, height);
+		
+		if (original_width != width || original_height != height)
+		{
+			previewp->setSize(width, height);
+			if (do_update)
+			{
+                previewp->updateSnapshot(TRUE);
+				updateControls();
+			}
+		}
+        // Get the old filter, compare to the current one "filter_name" and set if changed
+        std::string original_filter = previewp->getFilter();
+		if (original_filter != filter_name)
+		{
+            previewp->setFilter(filter_name);
+			if (do_update)
+			{
+                previewp->updateSnapshot(FALSE, TRUE);
+				updateControls();
+			}
+		}
+	}
+}
+
+void LLTwitterPhotoPanel::checkAspectRatio(S32 index)
+{
+	LLSnapshotLivePreview *previewp = getPreviewView() ;
+
+	BOOL keep_aspect = FALSE;
+
+	if (0 == index) // current window size
+	{
+		keep_aspect = TRUE;
+	}
+	else // predefined resolution
+	{
+		keep_aspect = FALSE;
+	}
+
+	if (previewp)
+	{
+		previewp->mKeepAspectRatio = keep_aspect;
+	}
+}
+
+LLUICtrl* LLTwitterPhotoPanel::getRefreshBtn()
+{
+	return mRefreshBtn;
+}
+
+///////////////////////////
+//LLTwitterAccountPanel//////
+///////////////////////////
+
+LLTwitterAccountPanel::LLTwitterAccountPanel() : 
+mAccountCaptionLabel(NULL),
+mAccountNameLabel(NULL),
+mPanelButtons(NULL),
+mConnectButton(NULL),
+mDisconnectButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLTwitterAccountPanel::onConnect, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLTwitterAccountPanel::onDisconnect, this));
+
+	setVisibleCallback(boost::bind(&LLTwitterAccountPanel::onVisibilityChange, this, _2));
+}
+
+BOOL LLTwitterAccountPanel::postBuild()
+{
+	mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
+	mAccountNameLabel = getChild<LLTextBox>("account_name_label");
+	mPanelButtons = getChild<LLUICtrl>("panel_buttons");
+	mConnectButton = getChild<LLUICtrl>("connect_btn");
+	mDisconnectButton = getChild<LLUICtrl>("disconnect_btn");
+
+	return LLPanel::postBuild();
+}
+
+void LLTwitterAccountPanel::draw()
+{
+	LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState();
+
+	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress
+	bool disconnecting = connection_state == LLTwitterConnect::TWITTER_DISCONNECTING;
+	mDisconnectButton->setEnabled(!disconnecting);
+
+	//Disable the 'connect' button when a connection is in progress
+	bool connecting = connection_state == LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS;
+	mConnectButton->setEnabled(!connecting);
+
+	LLPanel::draw();
+}
+
+void LLTwitterAccountPanel::onVisibilityChange(BOOL visible)
+{
+	if(visible)
+	{
+		LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel");
+		LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectStateChange, this, _1));
+
+		LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel");
+		LLEventPumps::instance().obtain("TwitterConnectInfo").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectInfoChange, this));
+
+		//Connected
+		if(LLTwitterConnect::instance().isConnected())
+		{
+			showConnectedLayout();
+		}
+		//Check if connected (show disconnected layout in meantime)
+		else
+		{
+			showDisconnectedLayout();
+		}
+        if ((LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_NOT_CONNECTED) ||
+            (LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_CONNECTION_FAILED))
+        {
+            LLTwitterConnect::instance().checkConnectionToTwitter();
+        }
+	}
+	else
+	{
+		LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel");
+		LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel");
+	}
+}
+
+bool LLTwitterAccountPanel::onTwitterConnectStateChange(const LLSD& data)
+{
+	if(LLTwitterConnect::instance().isConnected())
+	{
+		//In process of disconnecting so leave the layout as is
+		if(data.get("enum").asInteger() != LLTwitterConnect::TWITTER_DISCONNECTING)
+		{
+			showConnectedLayout();
+		}
+	}
+	else
+	{
+		showDisconnectedLayout();
+	}
+
+	return false;
+}
+
+bool LLTwitterAccountPanel::onTwitterConnectInfoChange()
+{
+	LLSD info = LLTwitterConnect::instance().getInfo();
+	std::string clickable_name;
+
+	//Strings of format [http://www.somewebsite.com Click Me] become clickable text
+	if(info.has("link") && info.has("name"))
+	{
+		clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]";
+	}
+
+	mAccountNameLabel->setText(clickable_name);
+
+	return false;
+}
+
+void LLTwitterAccountPanel::showConnectButton()
+{
+	if(!mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(TRUE);
+		mDisconnectButton->setVisible(FALSE);
+	}
+}
+
+void LLTwitterAccountPanel::hideConnectButton()
+{
+	if(mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(FALSE);
+		mDisconnectButton->setVisible(TRUE);
+	}
+}
+
+void LLTwitterAccountPanel::showDisconnectedLayout()
+{
+	mAccountCaptionLabel->setText(getString("twitter_disconnected"));
+	mAccountNameLabel->setText(std::string(""));
+	showConnectButton();
+}
+
+void LLTwitterAccountPanel::showConnectedLayout()
+{
+	LLTwitterConnect::instance().loadTwitterInfo();
+
+	mAccountCaptionLabel->setText(getString("twitter_connected"));
+	hideConnectButton();
+}
+
+void LLTwitterAccountPanel::onConnect()
+{
+	LLTwitterConnect::instance().checkConnectionToTwitter(true);
+
+	//Clear only the twitter browser cookies so that the twitter login screen appears
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com"); 
+}
+
+void LLTwitterAccountPanel::onDisconnect()
+{
+	LLTwitterConnect::instance().disconnectFromTwitter();
+
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com"); 
+}
+
+////////////////////////
+//LLFloaterTwitter///////
+////////////////////////
+
+LLFloaterTwitter::LLFloaterTwitter(const LLSD& key) : LLFloater(key),
+    mTwitterPhotoPanel(NULL),
+    mStatusErrorText(NULL),
+    mStatusLoadingText(NULL),
+    mStatusLoadingIndicator(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterTwitter::onCancel, this));
+}
+
+void LLFloaterTwitter::onClose(bool app_quitting)
+{
+    LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+    if (big_preview_floater)
+    {
+        big_preview_floater->closeOnFloaterOwnerClosing(this);
+    }
+	LLFloater::onClose(app_quitting);
+}
+
+void LLFloaterTwitter::onCancel()
+{
+    LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+    if (big_preview_floater)
+    {
+        big_preview_floater->closeOnFloaterOwnerClosing(this);
+    }
+    closeFloater();
+}
+
+BOOL LLFloaterTwitter::postBuild()
+{
+    // Keep tab of the Photo Panel
+	mTwitterPhotoPanel = static_cast<LLTwitterPhotoPanel*>(getChild<LLUICtrl>("panel_twitter_photo"));
+    // Connection status widgets
+    mStatusErrorText = getChild<LLTextBox>("connection_error_text");
+    mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
+    mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator");
+	return LLFloater::postBuild();
+}
+
+void LLFloaterTwitter::showPhotoPanel()
+{
+	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mTwitterPhotoPanel->getParent());
+	if (!parent)
+	{
+		llwarns << "Cannot find panel container" << llendl;
+		return;
+	}
+
+	parent->selectTabPanel(mTwitterPhotoPanel);
+}
+
+void LLFloaterTwitter::draw()
+{
+    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
+    {
+        mStatusErrorText->setVisible(false);
+        mStatusLoadingText->setVisible(false);
+        mStatusLoadingIndicator->setVisible(false);
+        LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState();
+        std::string status_text;
+        
+        switch (connection_state)
+        {
+        case LLTwitterConnect::TWITTER_NOT_CONNECTED:
+            // No status displayed when first opening the panel and no connection done
+        case LLTwitterConnect::TWITTER_CONNECTED:
+            // When successfully connected, no message is displayed
+        case LLTwitterConnect::TWITTER_POSTED:
+            // No success message to show since we actually close the floater after successful posting completion
+            break;
+        case LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS:
+            // Connection loading indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterConnecting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+            break;
+        case LLTwitterConnect::TWITTER_POSTING:
+            // Posting indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterPosting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+			break;
+        case LLTwitterConnect::TWITTER_CONNECTION_FAILED:
+            // Error connecting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterErrorConnecting");
+            mStatusErrorText->setValue(status_text);
+            break;
+        case LLTwitterConnect::TWITTER_POST_FAILED:
+            // Error posting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterErrorPosting");
+            mStatusErrorText->setValue(status_text);
+            break;
+		case LLTwitterConnect::TWITTER_DISCONNECTING:
+			// Disconnecting loading indicator
+			mStatusLoadingText->setVisible(true);
+			status_text = LLTrans::getString("SocialTwitterDisconnecting");
+			mStatusLoadingText->setValue(status_text);
+			mStatusLoadingIndicator->setVisible(true);
+			break;
+		case LLTwitterConnect::TWITTER_DISCONNECT_FAILED:
+			// Error disconnecting from the service
+			mStatusErrorText->setVisible(true);
+			status_text = LLTrans::getString("SocialTwitterErrorDisconnecting");
+			mStatusErrorText->setValue(status_text);
+			break;
+        }
+    }
+	LLFloater::draw();
+}
+
diff --git a/indra/newview/llfloatertwitter.h b/indra/newview/llfloatertwitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..f07ec2ca2f0ba4dcdf7a97844794d9719a83ff9b
--- /dev/null
+++ b/indra/newview/llfloatertwitter.h
@@ -0,0 +1,139 @@
+/** 
+* @file   llfloatertwitter.h
+* @brief  Header file for llfloatertwitter
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLFLOATERTWITTER_H
+#define LL_LLFLOATERTWITTER_H
+
+#include "llfloater.h"
+#include "lltextbox.h"
+#include "llviewertexture.h"
+
+class LLIconCtrl;
+class LLCheckBoxCtrl;
+class LLSnapshotLivePreview;
+class LLFloaterBigPreview;
+
+class LLTwitterPhotoPanel : public LLPanel
+{
+public:
+	LLTwitterPhotoPanel();
+	~LLTwitterPhotoPanel();
+
+	BOOL postBuild();
+	void draw();
+
+	LLSnapshotLivePreview* getPreviewView();
+	void onVisibilityChange(BOOL new_visibility);
+	void onAddLocationToggled();
+	void onAddPhotoToggled();
+    void onClickBigPreview();
+	void onClickNewSnapshot();
+	void onSend();
+	S32 notify(const LLSD& info);
+	bool onTwitterConnectStateChange(const LLSD& data);
+
+	void sendPhoto();
+	void clearAndClose();
+
+	void updateStatusTextLength(BOOL restore_old_status_text);
+	void updateControls();
+	void updateResolution(BOOL do_update);
+	void checkAspectRatio(S32 index);
+	LLUICtrl* getRefreshBtn();
+
+private:
+    bool isPreviewVisible();
+    void attachPreview();
+
+	LLHandle<LLView> mPreviewHandle;
+
+	LLUICtrl * mSnapshotPanel;
+	LLUICtrl * mResolutionComboBox;
+	LLUICtrl * mFilterComboBox;
+	LLUICtrl * mRefreshBtn;
+	LLUICtrl * mWorkingLabel;
+	LLUICtrl * mThumbnailPlaceholder;
+	LLUICtrl * mStatusCounterLabel;
+	LLUICtrl * mStatusTextBox;
+	LLUICtrl * mLocationCheckbox;
+	LLUICtrl * mPhotoCheckbox;
+	LLUICtrl * mPostButton;
+	LLUICtrl * mCancelButton;
+	LLButton * mBtnPreview;
+
+    LLFloaterBigPreview * mBigPreviewFloater;
+    
+	std::string mOldStatusText;
+};
+
+class LLTwitterAccountPanel : public LLPanel
+{
+public:
+	LLTwitterAccountPanel();
+	BOOL postBuild();
+	void draw();
+
+private:
+	void onVisibilityChange(BOOL new_visibility);
+	bool onTwitterConnectStateChange(const LLSD& data);
+	bool onTwitterConnectInfoChange();
+	void onConnect();
+	void onUseAnotherAccount();
+	void onDisconnect();
+
+	void showConnectButton();
+	void hideConnectButton();
+	void showDisconnectedLayout();
+	void showConnectedLayout();
+
+	LLTextBox * mAccountCaptionLabel;
+	LLTextBox * mAccountNameLabel;
+	LLUICtrl * mPanelButtons;
+	LLUICtrl * mConnectButton;
+	LLUICtrl * mDisconnectButton;
+};
+
+
+class LLFloaterTwitter : public LLFloater
+{
+public:
+	LLFloaterTwitter(const LLSD& key);
+	BOOL postBuild();
+	void draw();
+	void onClose(bool app_quitting);
+	void onCancel();
+
+	void showPhotoPanel();
+
+private:
+	LLTwitterPhotoPanel* mTwitterPhotoPanel;
+    LLTextBox* mStatusErrorText;
+    LLTextBox* mStatusLoadingText;
+    LLUICtrl*  mStatusLoadingIndicator;
+};
+
+#endif // LL_LLFLOATERTWITTER_H
+
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 96a70d934544bc6e57b173601520192dfc12077a..bfc36a6bfbd8dd90d726a00e732a6583e7dbcb20 100755
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -1020,12 +1020,11 @@ void LLFloaterUIPreview::onClickEditFloater()
 // Respond to button click to browse for an executable with which to edit XML files
 void LLFloaterUIPreview::onClickBrowseForEditor()
 {
-	// create load dialog box
-	LLFilePicker::ELoadFilter type = (LLFilePicker::ELoadFilter)((intptr_t)((void*)LLFilePicker::FFLOAD_ALL));	// nothing for *.exe so just use all
+	// Let the user choose an executable through the file picker dialog box
 	LLFilePicker& picker = LLFilePicker::instance();
-	if (!picker.getOpenFile(type))	// user cancelled -- do nothing
+    if (!picker.getOpenFile(LLFilePicker::FFLOAD_EXE))
 	{
-		return;
+		return; // user cancelled -- do nothing
 	}
 
 	// put the selected path into text field
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index f72adbb880d2e67ec78a1d77f079d3bfb10af378..bbfd855bc892bfb6477e46888c6a0b99a9675a3c 100755
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -31,6 +31,8 @@
 #include "llfloaterreg.h"
 #include "llhttpconstants.h"
 #include "llfacebookconnect.h"
+#include "llflickrconnect.h"
+#include "lltwitterconnect.h"
 #include "lllayoutstack.h"
 #include "llpluginclassmedia.h"
 #include "llprogressbar.h"
@@ -52,7 +54,8 @@ LLFloaterWebContent::_Params::_Params()
     allow_back_forward_navigation("allow_back_forward_navigation", true),
 	preferred_media_size("preferred_media_size"),
 	trusted_content("trusted_content", false),
-	show_page_title("show_page_title", true)
+	show_page_title("show_page_title", true),
+    clean_browser("clean_browser", false)
 {}
 
 LLFloaterWebContent::LLFloaterWebContent( const Params& params )
@@ -243,7 +246,7 @@ void LLFloaterWebContent::open_media(const Params& p)
 	LLViewerMedia::proxyWindowOpened(p.target(), p.id());
 	mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML);
 	mWebBrowser->setTarget(p.target);
-	mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML);
+	mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML, p.clean_browser);
 	
 	set_current_url(p.url);
 
@@ -254,11 +257,6 @@ void LLFloaterWebContent::open_media(const Params& p)
 	getChildView("address")->setEnabled(address_entry_enabled);
 	getChildView("popexternal")->setEnabled(address_entry_enabled);
 
-	if (!address_entry_enabled)
-	{
-		mWebBrowser->setFocus(TRUE);
-	}
-
 	if (!p.show_chrome)
 	{
 		setResizeLimits(100, 100);
@@ -304,7 +302,24 @@ void LLFloaterWebContent::onClose(bool app_quitting)
             LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
         }
     }
-    
+	// Same with Flickr
+	LLFloater* flickr_web = LLFloaterReg::getInstance("flickr_web");
+    if (flickr_web == this)
+    {
+        if (!LLFlickrConnect::instance().isConnected())
+        {
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+        }
+    }
+	// And Twitter
+	LLFloater* twitter_web = LLFloaterReg::getInstance("twitter_web");
+    if (twitter_web == this)
+    {
+        if (!LLTwitterConnect::instance().isConnected())
+        {
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+        }
+    }
 	LLViewerMedia::proxyWindowClosed(mUUID);
 	destroy();
 }
@@ -440,9 +455,6 @@ void LLFloaterWebContent::set_current_url(const std::string& url)
         mAddressCombo->remove(mCurrentURL);
         mAddressCombo->add(mDisplayURL);
         mAddressCombo->selectByValue(mDisplayURL);
-
-        // Set the focus back to the web page. When setting the url, there's no point to leave the focus anywhere else.
-		mWebBrowser->setFocus(TRUE);
     }
 }
 
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
index ad56eec8590633366bb69ac8d4edfc6dee565ae1..f5faa39e3de24a5226c15911c509f0a7dc0a990b 100755
--- a/indra/newview/llfloaterwebcontent.h
+++ b/indra/newview/llfloaterwebcontent.h
@@ -57,7 +57,8 @@ class LLFloaterWebContent :
 								allow_address_entry,
                                 allow_back_forward_navigation,
 								trusted_content,
-								show_page_title;
+								show_page_title,
+                                clean_browser;
 		Optional<LLRect>		preferred_media_size;
 
 		_Params();
diff --git a/indra/newview/llimagefiltersmanager.cpp b/indra/newview/llimagefiltersmanager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ee6b39efaca6b650f5df139399a3f2b63ad1ede2
--- /dev/null
+++ b/indra/newview/llimagefiltersmanager.cpp
@@ -0,0 +1,115 @@
+/** 
+ * @file llimagefiltersmanager.cpp
+ * @brief Load image filters list and retrieve their path. Mostly used for Flickr UI at the moment.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2014, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llimagefiltersmanager.h"
+
+#include "lldiriterator.h"
+#include "lltrans.h"
+
+std::string get_sys_dir()
+{
+	return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "filters", "");
+}
+
+//---------------------------------------------------------------------------
+// LLImageFiltersManager
+//---------------------------------------------------------------------------
+
+LLImageFiltersManager::LLImageFiltersManager()
+{
+}
+
+LLImageFiltersManager::~LLImageFiltersManager()
+{
+}
+
+// virtual static
+void LLImageFiltersManager::initSingleton()
+{
+	loadAllFilters();
+}
+
+void LLImageFiltersManager::loadAllFilters()
+{
+	// Load system (coming out of the box) filters
+	loadFiltersFromDir(get_sys_dir());
+}
+
+void LLImageFiltersManager::loadFiltersFromDir(const std::string& dir)
+{
+	mFiltersList.clear();
+
+	LLDirIterator dir_iter(dir, "*.xml");
+	while (1)
+	{
+		std::string file_name;
+		if (!dir_iter.next(file_name))
+		{
+			break; // no more files
+		}
+		
+		// Get the ".xml" out of the file name to get the filter name. That's the one known in strings.xml
+		std::string filter_name_untranslated = file_name.substr(0,file_name.length()-4);
+        
+        // Get the localized name for the filter
+        std::string	filter_name_translated;
+        bool translated = LLTrans::findString(filter_name_translated, filter_name_untranslated);
+        std::string	filter_name = (translated ? filter_name_translated: filter_name_untranslated);
+        
+        // Store the filter in the list with its associated file name
+        mFiltersList[filter_name] = file_name;
+	}
+}
+
+// Note : That method is a bit heavy handed but the list of filters is always small (10 or so)
+// and that method is typically called only once when building UI widgets.
+const std::vector<std::string> LLImageFiltersManager::getFiltersList() const
+{
+    std::vector<std::string> filter_list;
+    for (std::map<std::string,std::string>::const_iterator it = mFiltersList.begin(); it != mFiltersList.end(); ++it)
+    {
+        filter_list.push_back(it->first);
+    }
+    return filter_list;
+}
+
+std::string LLImageFiltersManager::getFilterPath(const std::string& filter_name)
+{
+    std::string path = "";
+    std::map<std::string,std::string>::const_iterator it = mFiltersList.find(filter_name);
+    if (it != mFiltersList.end())
+    {
+        // Get the file name for that filter and build the complete path
+        std::string file = it->second;
+        std::string dir = get_sys_dir();
+        path = gDirUtilp->add(dir, file);
+    }
+    return path;
+}
+
+//============================================================================
diff --git a/indra/newview/llimagefiltersmanager.h b/indra/newview/llimagefiltersmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..4751933065bfa9c8fa9635d3a5f550e10238da0d
--- /dev/null
+++ b/indra/newview/llimagefiltersmanager.h
@@ -0,0 +1,55 @@
+/** 
+ * @file llimagefiltersmanager.h
+ * @brief Load image filters list and retrieve their path. Mostly used for Flickr UI at the moment.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2014, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLIMAGEFILTERSMANAGER_H
+#define LL_LLIMAGEFILTERSMANAGER_H
+
+#include "llsingleton.h"
+
+//============================================================================
+// LLImageFiltersManager class
+
+class LLImageFiltersManager : public LLSingleton<LLImageFiltersManager>
+{
+	LOG_CLASS(LLImageFiltersManager);
+public:
+    const std::vector<std::string> getFiltersList() const;
+    std::string getFilterPath(const std::string& filter_name);
+  
+private:
+	void loadAllFilters();
+	void loadFiltersFromDir(const std::string& dir);
+    
+    friend class LLSingleton<LLImageFiltersManager>;
+	/*virtual*/ void initSingleton();
+	LLImageFiltersManager();
+	~LLImageFiltersManager();
+    
+	// List of filters : first is the user friendly localized name, second is the xml file name
+    std::map<std::string,std::string> mFiltersList;
+};
+
+#endif // LL_LLIMAGEFILTERSMANAGER_H
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 0178512cb5a0500407e4415d78555091afc337c0..086bc1c1860348ce04c26b6933ef4974ab8bd596 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -544,7 +544,7 @@ void LLMediaCtrl::clearCache()
 
 ////////////////////////////////////////////////////////////////////////////////
 //
-void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type)
+void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type, bool clean_browser)
 {
 	// don't browse to anything that starts with secondlife:// or sl://
 	const std::string protocol1 = "secondlife://";
@@ -561,7 +561,7 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type)
 	{
 		mCurrentNavUrl = url_in;
 		mMediaSource->setSize(mTextureWidth, mTextureHeight);
-		mMediaSource->navigateTo(url_in, mime_type, mime_type.empty());
+		mMediaSource->navigateTo(url_in, mime_type, mime_type.empty(), false, clean_browser);
 	}
 }
 
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index b07eb356aecf0653799c459d52b1849f8136ec0b..b6ed0f3fabd09367e27497dd0ba5c0c3558e81d8 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -95,7 +95,7 @@ class LLMediaCtrl :
 		virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);
 
 		// navigation
-		void navigateTo( std::string url_in, std::string mime_type = "");
+		void navigateTo( std::string url_in, std::string mime_type = "", bool clean_browser = false);
 		void navigateBack();
 		void navigateHome();
 		void navigateForward();	
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 9d9fb4040ddbf25071196e78aba3c733b49a2c88..5977d558d3559b2d602b753a552c1c77276b5ebd 100755
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -505,7 +505,7 @@ class LLRecentListUpdater : public LLAvatarListUpdater, public boost::signals2::
 
 LLPanelPeople::LLPanelPeople()
 	:	LLPanel(),
-		mTryToConnectToFbc(true),
+		mTryToConnectToFacebook(true),
 		mTabContainer(NULL),
 		mOnlineFriendList(NULL),
 		mAllFriendList(NULL),
@@ -865,10 +865,10 @@ void LLPanelPeople::updateFacebookList(bool visible)
 		{
 			LLFacebookConnect::instance().loadFacebookFriends();
 		}
-		else if(mTryToConnectToFbc)
+		else if(mTryToConnectToFacebook)
 		{
 			LLFacebookConnect::instance().checkConnectionToFacebook();
-			mTryToConnectToFbc = false;
+			mTryToConnectToFacebook = false;
 		}
     
 		updateSuggestedFriendList();
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 34dc3d9ab785d5672b38e98c26964b5e3864650b..55eaf74f74cb195d5a4a0cbd625502d9ccd6e19b 100755
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -57,7 +57,7 @@ class LLPanelPeople
 	// when voice is available
 	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
 
-    bool mTryToConnectToFbc;
+    bool mTryToConnectToFacebook;
 
 	// internals
 	class Updater;
diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp
index 21f95f38c0e9798effe2042d171a4ff45304ee97..743ef3e32913b32949f58ac79decf331a02a7f4a 100755
--- a/indra/newview/llpanelsnapshotoptions.cpp
+++ b/indra/newview/llpanelsnapshotoptions.cpp
@@ -31,6 +31,10 @@
 #include "llsidetraypanelcontainer.h"
 
 #include "llfloatersnapshot.h" // FIXME: create a snapshot model
+#include "llfloaterreg.h"
+#include "llfloaterfacebook.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
 
 /**
  * Provides several ways to save a snapshot.
@@ -44,6 +48,7 @@ class LLPanelSnapshotOptions
 public:
 	LLPanelSnapshotOptions();
 	~LLPanelSnapshotOptions();
+	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void onOpen(const LLSD& key);
 	/*virtual*/ void onEconomyDataChange() { updateUploadCost(); }
 
@@ -54,6 +59,9 @@ class LLPanelSnapshotOptions
 	void onSaveToEmail();
 	void onSaveToInventory();
 	void onSaveToComputer();
+	void onSendToFacebook();
+	void onSendToTwitter();
+	void onSendToFlickr();
 };
 
 static LLPanelInjector<LLPanelSnapshotOptions> panel_class("llpanelsnapshotoptions");
@@ -73,6 +81,19 @@ LLPanelSnapshotOptions::~LLPanelSnapshotOptions()
 	LLGlobalEconomy::Singleton::getInstance()->removeObserver(this);
 }
 
+// virtual
+BOOL LLPanelSnapshotOptions::postBuild()
+{
+    LLTextBox* sendToFacebookTextBox = getChild<LLTextBox>("send_to_facebook_textbox");
+    sendToFacebookTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToFacebook, this));
+    LLTextBox* sendToTwitterTextBox = getChild<LLTextBox>("send_to_twitter_textbox");
+    sendToTwitterTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToTwitter, this));
+    LLTextBox* sendToFlickrTextBox = getChild<LLTextBox>("send_to_flickr_textbox");
+    sendToFlickrTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToFlickr, this));
+
+	return LLPanel::postBuild();
+}
+
 // virtual
 void LLPanelSnapshotOptions::onOpen(const LLSD& key)
 {
@@ -118,3 +139,39 @@ void LLPanelSnapshotOptions::onSaveToComputer()
 {
 	openPanel("panel_snapshot_local");
 }
+
+void LLPanelSnapshotOptions::onSendToFacebook()
+{
+	LLFloaterReg::hideInstance("snapshot");
+
+	LLFloaterFacebook* facebook_floater = dynamic_cast<LLFloaterFacebook*>(LLFloaterReg::getInstance("facebook"));
+	if (facebook_floater)
+	{
+		facebook_floater->showPhotoPanel();
+	}
+	LLFloaterReg::showInstance("facebook");
+}
+
+void LLPanelSnapshotOptions::onSendToTwitter()
+{
+	LLFloaterReg::hideInstance("snapshot");
+
+	LLFloaterTwitter* twitter_floater = dynamic_cast<LLFloaterTwitter*>(LLFloaterReg::getInstance("twitter"));
+	if (twitter_floater)
+	{
+		twitter_floater->showPhotoPanel();
+	}
+	LLFloaterReg::showInstance("twitter");
+}
+
+void LLPanelSnapshotOptions::onSendToFlickr()
+{
+	LLFloaterReg::hideInstance("snapshot");
+
+	LLFloaterFlickr* flickr_floater = dynamic_cast<LLFloaterFlickr*>(LLFloaterReg::getInstance("flickr"));
+	if (flickr_floater)
+	{
+		flickr_floater->showPhotoPanel();
+	}
+	LLFloaterReg::showInstance("flickr");
+}
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index d8ad071ba6304b6bc69844410283c3302c99ed9e..a1965af4a5848a5088d8599fc950528d162bf328 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -34,7 +34,11 @@
 #include "lleconomy.h"
 #include "llfloaterperms.h"
 #include "llfloaterreg.h"
-#include "llfloatersocial.h"
+#include "llfloaterfacebook.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
+#include "llimagefilter.h"
+#include "llimagefiltersmanager.h"
 #include "llimagebmp.h"
 #include "llimagej2c.h"
 #include "llimagejpeg.h"
@@ -70,9 +74,11 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Param
 	mColor(1.f, 0.f, 0.f, 0.5f), 
 	mCurImageIndex(0),
 	mPreviewImage(NULL),
-	mThumbnailImage(NULL) ,
+    mThumbnailImage(NULL) ,
+    mBigThumbnailImage(NULL) ,
 	mThumbnailWidth(0),
 	mThumbnailHeight(0),
+    mThumbnailSubsampled(FALSE),
 	mPreviewImageEncoded(NULL),
 	mFormattedImage(NULL),
 	mShineCountdown(0),
@@ -86,7 +92,11 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Param
 	mCameraPos(LLViewerCamera::getInstance()->getOrigin()),
 	mCameraRot(LLViewerCamera::getInstance()->getQuaternion()),
 	mSnapshotActive(FALSE),
-	mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR)
+	mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR),
+    mFilterName(""),
+    mAllowRenderUI(TRUE),
+    mAllowFullScreenPreview(TRUE),
+    mViewContainer(NULL)
 {
 	setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality"));
 	mSnapshotDelayTimer.setTimerExpirySec(0.0f);
@@ -105,6 +115,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Param
 	mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ;
 	mThumbnailUpdateLock = FALSE ;
 	mThumbnailUpToDate   = FALSE ;
+	mBigThumbnailUpToDate = FALSE ;
 }
 
 LLSnapshotLivePreview::~LLSnapshotLivePreview()
@@ -120,14 +131,7 @@ LLSnapshotLivePreview::~LLSnapshotLivePreview()
 
 void LLSnapshotLivePreview::setMaxImageSize(S32 size) 
 {
-	if(size < MAX_SNAPSHOT_IMAGE_SIZE)
-	{
-		mMaxImageSize = size;
-	}
-	else
-	{
-		mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
-	}
+    mMaxImageSize = llmin(size,(S32)(MAX_SNAPSHOT_IMAGE_SIZE));
 }
 
 LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
@@ -135,97 +139,92 @@ LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
 	return mViewerImage[mCurImageIndex];
 }
 
-F32 LLSnapshotLivePreview::getAspect()
-{
-	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
-	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
-
-	if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
-	{
-		return image_aspect_ratio;
-	}
-	else
-	{
-		return window_aspect_ratio;
-	}
-}
-
 F32 LLSnapshotLivePreview::getImageAspect()
 {
 	if (!getCurrentImage())
 	{
 		return 0.f;
 	}
-
-	return getAspect() ;	
+	// mKeepAspectRatio) == gSavedSettings.getBOOL("KeepAspectForSnapshot"))
+    return (mKeepAspectRatio ? ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()) : ((F32)getWidth()) / ((F32)getHeight()));
 }
 
-void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay) 
+void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)
 {
-	// Invalidate current image.
-	LL_DEBUGS() << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << LL_ENDL;
-	if (getSnapshotUpToDate())
-	{
-		S32 old_image_index = mCurImageIndex;
-		mCurImageIndex = (mCurImageIndex + 1) % 2; 
-		setSize(mWidth[old_image_index], mHeight[old_image_index]);
-		mFallAnimTimer.start();		
-	}
-	mSnapshotUpToDate = FALSE; 		
-
-	// Update snapshot source rect depending on whether we keep the aspect ratio.
-	LLRect& rect = mImageRect[mCurImageIndex];
-	rect.set(0, getRect().getHeight(), getRect().getWidth(), 0);
-
-	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
-	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
-
-	if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
-	{
-		if (image_aspect_ratio > window_aspect_ratio)
-		{
-			// trim off top and bottom
-			S32 new_height = llround((F32)getRect().getWidth() / image_aspect_ratio); 
-			rect.mBottom += (getRect().getHeight() - new_height) / 2;
-			rect.mTop -= (getRect().getHeight() - new_height) / 2;
-		}
-		else if (image_aspect_ratio < window_aspect_ratio)
-		{
-			// trim off left and right
-			S32 new_width = llround((F32)getRect().getHeight() * image_aspect_ratio); 
-			rect.mLeft += (getRect().getWidth() - new_width) / 2;
-			rect.mRight -= (getRect().getWidth() - new_width) / 2;
-		}
-	}
-
-	// Stop shining animation.
-	mShineAnimTimer.stop();
+	lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl;
 
 	// Update snapshot if requested.
 	if (new_snapshot)
 	{
+        if (getSnapshotUpToDate())
+        {
+            S32 old_image_index = mCurImageIndex;
+            mCurImageIndex = (mCurImageIndex + 1) % 2; 
+            setSize(mWidth[old_image_index], mHeight[old_image_index]);
+            mFallAnimTimer.start();		
+        }
+        mSnapshotUpToDate = FALSE; 		
+
+        // Update snapshot source rect depending on whether we keep the aspect ratio.
+        LLRect& rect = mImageRect[mCurImageIndex];
+        rect.set(0, getRect().getHeight(), getRect().getWidth(), 0);
+
+        F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
+        F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
+
+        if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
+        {
+            if (image_aspect_ratio > window_aspect_ratio)
+            {
+                // trim off top and bottom
+                S32 new_height = llround((F32)getRect().getWidth() / image_aspect_ratio); 
+                rect.mBottom += (getRect().getHeight() - new_height) / 2;
+                rect.mTop -= (getRect().getHeight() - new_height) / 2;
+            }
+            else if (image_aspect_ratio < window_aspect_ratio)
+            {
+                // trim off left and right
+                S32 new_width = llround((F32)getRect().getHeight() * image_aspect_ratio); 
+                rect.mLeft += (getRect().getWidth() - new_width) / 2;
+                rect.mRight -= (getRect().getWidth() - new_width) / 2;
+            }
+        }
+
+        // Stop shining animation.
+        mShineAnimTimer.stop();
 		mSnapshotDelayTimer.start();
 		mSnapshotDelayTimer.setTimerExpirySec(delay);
-		LLFloaterSnapshot::preUpdate();
-		LLFloaterSocial::preUpdate();
+        
+        // Tell the floater container that the snapshot is in the process of updating itself
+        if (mViewContainer)
+        {
+            mViewContainer->notify(LLSD().with("snapshot-updating", true));
+        }
 	}
 
 	// Update thumbnail if requested.
-	if(new_thumbnail)
+	if (new_thumbnail)
 	{
 		mThumbnailUpToDate = FALSE ;
+        mBigThumbnailUpToDate = FALSE;
 	}
 }
 
-void LLSnapshotLivePreview::setSnapshotQuality(S32 quality)
+// Return true if the quality has been changed, false otherwise
+bool LLSnapshotLivePreview::setSnapshotQuality(S32 quality, bool set_by_user)
 {
 	llclamp(quality, 0, 100);
 	if (quality != mSnapshotQuality)
 	{
 		mSnapshotQuality = quality;
-		gSavedSettings.setS32("SnapshotQuality", quality);
-		mSnapshotUpToDate = FALSE;
+        if (set_by_user)
+        {
+            gSavedSettings.setS32("SnapshotQuality", quality);
+        }
+        mFormattedImage = NULL;     // Invalidate the already formatted image if any
+        return true;
 	}
+    return false;
 }
 
 void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y)
@@ -459,68 +458,57 @@ void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_pare
 	if (old_rect.getWidth() != width || old_rect.getHeight() != height)
 	{
 		LL_DEBUGS() << "window reshaped, updating thumbnail" << LL_ENDL;
-		updateSnapshot(FALSE, TRUE);
+		updateSnapshot(TRUE);
 	}
 }
 
 BOOL LLSnapshotLivePreview::setThumbnailImageSize()
 {
-	if(getWidth() < 10 || getHeight() < 10)
+	if (getWidth() < 10 || getHeight() < 10)
 	{
 		return FALSE ;
 	}
-	S32 window_width = gViewerWindow->getWindowWidthRaw() ;
-	S32 window_height = gViewerWindow->getWindowHeightRaw() ;
+	S32 width  = (mThumbnailSubsampled ? mPreviewImage->getWidth()  : gViewerWindow->getWindowWidthRaw());
+	S32 height = (mThumbnailSubsampled ? mPreviewImage->getHeight() : gViewerWindow->getWindowHeightRaw()) ;
 
-	F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height);
+	F32 aspect_ratio = ((F32)width) / ((F32)height);
 
 	// UI size for thumbnail
-	// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h.
-	const LLRect& thumbnail_rect = mThumbnailPlaceholderRect;
-	S32 max_width = thumbnail_rect.getWidth();
-	S32 max_height = thumbnail_rect.getHeight();
+	S32 max_width  = mThumbnailPlaceholderRect.getWidth();
+	S32 max_height = mThumbnailPlaceholderRect.getHeight();
 
-	if (window_aspect_ratio > (F32)max_width / max_height)
+	if (aspect_ratio > (F32)max_width / (F32)max_height)
 	{
 		// image too wide, shrink to width
 		mThumbnailWidth = max_width;
-		mThumbnailHeight = llround((F32)max_width / window_aspect_ratio);
+		mThumbnailHeight = llround((F32)max_width / aspect_ratio);
 	}
 	else
 	{
 		// image too tall, shrink to height
 		mThumbnailHeight = max_height;
-		mThumbnailWidth = llround((F32)max_height * window_aspect_ratio);
+		mThumbnailWidth = llround((F32)max_height * aspect_ratio);
 	}
-
-	if(mThumbnailWidth > window_width || mThumbnailHeight > window_height)
+    
+	if (mThumbnailWidth > width || mThumbnailHeight > height)
 	{
 		return FALSE ;//if the window is too small, ignore thumbnail updating.
 	}
 
 	S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ;
-	if(!mKeepAspectRatio)
+	if (!mKeepAspectRatio)
 	{
-		F32 ratio_x = (F32)getWidth() / window_width ;
-		F32 ratio_y = (F32)getHeight() / window_height ;
-
-		//if(getWidth() > window_width ||
-		//	getHeight() > window_height )
-		{
-			if(ratio_x > ratio_y)
-			{
-				top = (S32)(top * ratio_y / ratio_x) ;
-			}
-			else
-			{
-				right = (S32)(right * ratio_x / ratio_y) ;
-			}			
-		}
-		//else
-		//{
-		//	right = (S32)(right * ratio_x) ;
-		//	top = (S32)(top * ratio_y) ;
-		//}
+		F32 ratio_x = (F32)getWidth()  / width ;
+		F32 ratio_y = (F32)getHeight() / height ;
+
+        if (ratio_x > ratio_y)
+        {
+            top = (S32)(top * ratio_y / ratio_x) ;
+        }
+        else
+        {
+            right = (S32)(right * ratio_x / ratio_y) ;
+        }
 		left = (S32)((mThumbnailWidth - right) * 0.5f) ;
 		bottom = (S32)((mThumbnailHeight - top) * 0.5f) ;
 		top += bottom ;
@@ -556,25 +544,62 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
 		return ;
 	}
 
+    // Invalidate the big thumbnail when we regenerate the small one
+    mBigThumbnailUpToDate = FALSE;
+
 	if(mThumbnailImage)
 	{
 		resetThumbnailImage() ;
 	}		
 
 	LLPointer<LLImageRaw> raw = new LLImageRaw;
-	if(!gViewerWindow->thumbnailSnapshot(raw,
-		mThumbnailWidth, mThumbnailHeight,
-		gSavedSettings.getBOOL("RenderUIInSnapshot"),
-		FALSE,
-		mSnapshotBufferType) )								
+    
+    if (mThumbnailSubsampled)
+    {
+        // The thumbnail is be a subsampled version of the preview (used in SL Share previews, i.e. Flickr, Twitter, Facebook)
+		raw->resize( mPreviewImage->getWidth(),
+                     mPreviewImage->getHeight(),
+                     mPreviewImage->getComponents());
+        raw->copy(mPreviewImage);
+        // Scale to the thumbnail size
+        if (!raw->scale(mThumbnailWidth, mThumbnailHeight))
+        {
+            raw = NULL ;
+        }
+    }
+    else
+    {
+        // The thumbnail is a screen view with screen grab positioning preview
+        if(!gViewerWindow->thumbnailSnapshot(raw,
+                                         mThumbnailWidth, mThumbnailHeight,
+                                         mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"),
+                                         FALSE,
+                                         mSnapshotBufferType) )
+        {
+            raw = NULL ;
+        }
+    }
+    
+	if (raw)
 	{
-		raw = NULL ;
-	}
-
-	if(raw)
-	{
-		raw->expandToPowerOfTwo();
-		mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); 		
+        // Filter the thumbnail
+        // Note: filtering needs to be done *before* the scaling to power of 2 or the effect is distorted
+        if (getFilter() != "")
+        {
+            std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(getFilter());
+            if (filter_path != "")
+            {
+                LLImageFilter filter(filter_path);
+                filter.executeFilter(raw);
+            }
+            else
+            {
+                llwarns << "Couldn't find a path to the following filter : " << getFilter() << llendl;
+            }
+        }
+        // Scale to a power of 2 so it can be mapped to a texture
+        raw->expandToPowerOfTwo();
+		mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
 		mThumbnailUpToDate = TRUE ;
 	}
 
@@ -582,6 +607,52 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
 	mThumbnailUpdateLock = FALSE ;		
 }
 
+LLViewerTexture* LLSnapshotLivePreview::getBigThumbnailImage()
+{
+	if (mThumbnailUpdateLock) //in the process of updating
+	{
+		return NULL;
+	}
+	if (mBigThumbnailUpToDate && mBigThumbnailImage)//already updated
+	{
+		return mBigThumbnailImage;
+	}
+    
+	LLPointer<LLImageRaw> raw = new LLImageRaw;
+    
+	if (raw)
+	{
+        // The big thumbnail is a new filtered version of the preview (used in SL Share previews, i.e. Flickr, Twitter, Facebook)
+        mBigThumbnailWidth = mPreviewImage->getWidth();
+        mBigThumbnailHeight = mPreviewImage->getHeight();
+        raw->resize( mBigThumbnailWidth,
+                     mBigThumbnailHeight,
+                     mPreviewImage->getComponents());
+        raw->copy(mPreviewImage);
+    
+        // Filter
+        // Note: filtering needs to be done *before* the scaling to power of 2 or the effect is distorted
+        if (getFilter() != "")
+        {
+            std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(getFilter());
+            if (filter_path != "")
+            {
+                LLImageFilter filter(filter_path);
+                filter.executeFilter(raw);
+            }
+            else
+            {
+                llwarns << "Couldn't find a path to the following filter : " << getFilter() << llendl;
+            }
+        }
+        // Scale to a power of 2 so it can be mapped to a texture
+        raw->expandToPowerOfTwo();
+		mBigThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
+		mBigThumbnailUpToDate = TRUE ;
+	}
+    
+    return mBigThumbnailImage ;
+}
 
 // Called often. Checks whether it's time to grab a new snapshot and if so, does it.
 // Returns TRUE if new snapshot generated, FALSE otherwise.
@@ -598,7 +669,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 	// If we're in freeze-frame mode and camera has moved, update snapshot.
 	LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();
 	LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion();
-	if (gSavedSettings.getBOOL("FreezeTime") && 
+	if (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview &&
 		(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f))
 	{
 		previewp->mCameraPos = new_camera_pos;
@@ -616,157 +687,256 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 	previewp->mSnapshotActive = 
 		(previewp->mSnapshotDelayTimer.getStarted() &&	previewp->mSnapshotDelayTimer.hasExpired())
 		&& !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active
-	if ( ! previewp->mSnapshotActive)
+	if (!previewp->mSnapshotActive && previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
 	{
 		return FALSE;
 	}
 
 	// time to produce a snapshot
-	previewp->setThumbnailImageSize();
-
-	LL_DEBUGS() << "producing snapshot" << LL_ENDL;
-	if (!previewp->mPreviewImage)
+	if(!previewp->getSnapshotUpToDate())
+    {
+        lldebugs << "producing snapshot" << llendl;
+        if (!previewp->mPreviewImage)
+        {
+            previewp->mPreviewImage = new LLImageRaw;
+        }
+
+        previewp->setVisible(FALSE);
+        previewp->setEnabled(FALSE);
+
+        previewp->getWindow()->incBusyCount();
+        previewp->setImageScaled(FALSE);
+
+        // grab the raw image
+        if (gViewerWindow->rawSnapshot(
+                previewp->mPreviewImage,
+                previewp->getWidth(),
+                previewp->getHeight(),
+                previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"),
+                previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE,
+                previewp->mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"),
+                FALSE,
+                previewp->mSnapshotBufferType,
+                previewp->getMaxImageSize()))
+        {
+            // Invalidate/delete any existing encoded image
+            previewp->mPreviewImageEncoded = NULL;
+            // Invalidate/delete any existing formatted image
+            previewp->mFormattedImage = NULL;
+            // Update the data size
+            previewp->estimateDataSize();
+
+            // Full size preview is set: get the decoded image result and save it for animation
+            if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview)
+            {
+                // Get the decoded version of the formatted image
+                previewp->getEncodedImage();
+            
+                // We need to scale that a bit for display...
+                LLPointer<LLImageRaw> scaled = new LLImageRaw(
+                    previewp->mPreviewImageEncoded->getData(),
+                    previewp->mPreviewImageEncoded->getWidth(),
+                    previewp->mPreviewImageEncoded->getHeight(),
+                    previewp->mPreviewImageEncoded->getComponents());
+
+                if (!scaled->isBufferInvalid())
+                {
+                    // leave original image dimensions, just scale up texture buffer
+                    if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
+                    {
+                        // go ahead and shrink image to appropriate power of 2 for display
+                        scaled->biasedScaleToPowerOfTwo(1024);
+                        previewp->setImageScaled(TRUE);
+                    }
+                    else
+                    {
+                        // expand image but keep original image data intact
+                        scaled->expandToPowerOfTwo(1024, FALSE);
+                    }
+
+                    previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
+                    LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
+                    gGL.getTexUnit(0)->bind(curr_preview_image);
+                    curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+                    curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+                    previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
+                    previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+                }
+            }
+            // The snapshot is updated now...
+            previewp->mSnapshotUpToDate = TRUE;
+        
+            // We need to update the thumbnail though
+            previewp->setThumbnailImageSize();
+            previewp->generateThumbnailImage(TRUE) ;
+        }
+        previewp->getWindow()->decBusyCount();
+        previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode
+        previewp->mSnapshotDelayTimer.stop();
+        previewp->mSnapshotActive = FALSE;
+        lldebugs << "done creating snapshot" << llendl;
+    }
+    
+    if (!previewp->getThumbnailUpToDate())
 	{
-		previewp->mPreviewImage = new LLImageRaw;
+		previewp->generateThumbnailImage() ;
 	}
+    
+    // Tell the floater container that the snapshot is updated now
+    if (previewp->mViewContainer)
+    {
+        previewp->mViewContainer->notify(LLSD().with("snapshot-updated", true));
+    }
 
-	if (!previewp->mPreviewImageEncoded)
-	{
-		previewp->mPreviewImageEncoded = new LLImageRaw;
-	}
+	return TRUE;
+}
 
-	previewp->setVisible(FALSE);
-	previewp->setEnabled(FALSE);
-
-	previewp->getWindow()->incBusyCount();
-	previewp->setImageScaled(FALSE);
-
-	// grab the raw image and encode it into desired format
-	if(gViewerWindow->rawSnapshot(
-		previewp->mPreviewImage,
-		previewp->getWidth(),
-		previewp->getHeight(),
-		previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"),
-		previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE,
-		gSavedSettings.getBOOL("RenderUIInSnapshot"),
-		FALSE,
-		previewp->mSnapshotBufferType,
-		previewp->getMaxImageSize()))
-	{
-		previewp->mPreviewImageEncoded->resize(
-			previewp->mPreviewImage->getWidth(), 
-			previewp->mPreviewImage->getHeight(), 
-			previewp->mPreviewImage->getComponents());
+S32 LLSnapshotLivePreview::getEncodedImageWidth() const
+{
+    S32 width = getWidth();
+    if (getSnapshotType() == SNAPSHOT_TEXTURE)
+    {
+        width = LLImageRaw::biasedDimToPowerOfTwo(width,MAX_TEXTURE_SIZE);
+    }
+    return width;
+}
+S32 LLSnapshotLivePreview::getEncodedImageHeight() const
+{
+    S32 height = getHeight();
+    if (getSnapshotType() == SNAPSHOT_TEXTURE)
+    {
+        height = LLImageRaw::biasedDimToPowerOfTwo(height,MAX_TEXTURE_SIZE);
+    }
+    return height;
+}
 
-		if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE)
+LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage()
+{
+	if (!mPreviewImageEncoded)
+	{
+		mPreviewImageEncoded = new LLImageRaw;
+    
+		mPreviewImageEncoded->resize(
+            mPreviewImage->getWidth(),
+            mPreviewImage->getHeight(),
+            mPreviewImage->getComponents());
+        
+		if (getSnapshotType() == SNAPSHOT_TEXTURE)
 		{
+            // We don't store the intermediate formatted image in mFormattedImage in the J2C case 
 			LL_DEBUGS() << "Encoding new image of format J2C" << LL_ENDL;
 			LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
+            // Copy the preview
 			LLPointer<LLImageRaw> scaled = new LLImageRaw(
-				previewp->mPreviewImage->getData(),
-				previewp->mPreviewImage->getWidth(),
-				previewp->mPreviewImage->getHeight(),
-				previewp->mPreviewImage->getComponents());
-
+                                                          mPreviewImage->getData(),
+                                                          mPreviewImage->getWidth(),
+                                                          mPreviewImage->getHeight(),
+                                                          mPreviewImage->getComponents());
+            // Scale it as required by J2C
 			scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
-			previewp->setImageScaled(TRUE);
+			setImageScaled(TRUE);
+            // Compress to J2C
 			if (formatted->encode(scaled, 0.f))
 			{
-				previewp->mDataSize = formatted->getDataSize();
-				formatted->decode(previewp->mPreviewImageEncoded, 0);
+                // We can update the data size precisely at that point
+				mDataSize = formatted->getDataSize();
+                // Decompress back
+				formatted->decode(mPreviewImageEncoded, 0);
 			}
 		}
 		else
 		{
-			// delete any existing image
-			previewp->mFormattedImage = NULL;
-			// now create the new one of the appropriate format.
-			LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat();
-			LL_DEBUGS() << "Encoding new image of format " << format << LL_ENDL;
-
-			switch(format)
-			{
-			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
-				previewp->mFormattedImage = new LLImagePNG(); 
-				break;
-			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
-				previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality); 
-				break;
-			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
-				previewp->mFormattedImage = new LLImageBMP(); 
-				break;
-			}
-			if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0))
-			{
-				previewp->mDataSize = previewp->mFormattedImage->getDataSize();
-				// special case BMP to copy instead of decode otherwise decode will crash.
-				if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
-				{
-					previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage);
-				}
-				else
-				{
-					previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0);
-				}
-			}
-		}
-
-		LLPointer<LLImageRaw> scaled = new LLImageRaw(
-			previewp->mPreviewImageEncoded->getData(),
-			previewp->mPreviewImageEncoded->getWidth(),
-			previewp->mPreviewImageEncoded->getHeight(),
-			previewp->mPreviewImageEncoded->getComponents());
-
-		if(!scaled->isBufferInvalid())
-		{
-			// leave original image dimensions, just scale up texture buffer
-			if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
-			{
-				// go ahead and shrink image to appropriate power of 2 for display
-				scaled->biasedScaleToPowerOfTwo(1024);
-				previewp->setImageScaled(TRUE);
-			}
-			else
-			{
-				// expand image but keep original image data intact
-				scaled->expandToPowerOfTwo(1024, FALSE);
-			}
-
-			previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
-			LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
-			gGL.getTexUnit(0)->bind(curr_preview_image);
-			if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE)
-			{
-				curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT);
-			}
-			else
-			{
-				curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-			}
-			curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
-
-			previewp->mSnapshotUpToDate = TRUE;
-			previewp->generateThumbnailImage(TRUE) ;
-
-			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
-			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+            // Update mFormattedImage if necessary
+            getFormattedImage();
+            if (getSnapshotFormat() == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
+            {
+                // BMP hack : copy instead of decode otherwise decode will crash.
+                mPreviewImageEncoded->copy(mPreviewImage);
+            }
+            else
+            {
+                // Decode back
+                mFormattedImage->decode(mPreviewImageEncoded, 0);
+            }
 		}
 	}
-	previewp->getWindow()->decBusyCount();
-	// only show fullscreen preview when in freeze frame mode
-	previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame"));
-	previewp->mSnapshotDelayTimer.stop();
-	previewp->mSnapshotActive = FALSE;
+    return mPreviewImageEncoded;
+}
 
-	if(!previewp->getThumbnailUpToDate())
-	{
-		previewp->generateThumbnailImage() ;
-	}
-	LL_DEBUGS() << "done creating snapshot" << LL_ENDL;
-	LLFloaterSnapshot::postUpdate();
-	LLFloaterSocial::postUpdate();
+// We actually estimate the data size so that we do not require actual compression when showing the preview
+// Note : whenever formatted image is computed, mDataSize will be updated to reflect the true size
+void LLSnapshotLivePreview::estimateDataSize()
+{
+    // Compression ratio
+    F32 ratio = 1.0;
+    
+    if (getSnapshotType() == SNAPSHOT_TEXTURE)
+    {
+        ratio = 8.0;    // This is what we shoot for when compressing to J2C
+    }
+    else
+    {
+        LLFloaterSnapshot::ESnapshotFormat format = getSnapshotFormat();
+        switch (format)
+        {
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+                ratio = 3.0;    // Average observed PNG compression ratio
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+                // Observed from JPG compression tests
+                ratio = (110 - mSnapshotQuality) / 2;
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+                ratio = 1.0;    // No compression with BMP
+                break;
+        }
+    }
+    mDataSize = (S32)((F32)mPreviewImage->getDataSize() / ratio);
+}
 
-	return TRUE;
+LLPointer<LLImageFormatted>	LLSnapshotLivePreview::getFormattedImage()
+{
+    if (!mFormattedImage)
+    {
+        // Apply the filter to mPreviewImage
+        if (getFilter() != "")
+        {
+            std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(getFilter());
+            if (filter_path != "")
+            {
+                LLImageFilter filter(filter_path);
+                filter.executeFilter(mPreviewImage);
+            }
+            else
+            {
+                llwarns << "Couldn't find a path to the following filter : " << getFilter() << llendl;
+            }
+        }
+        
+        // Create the new formatted image of the appropriate format.
+        LLFloaterSnapshot::ESnapshotFormat format = getSnapshotFormat();
+        lldebugs << "Encoding new image of format " << format << llendl;
+            
+        switch (format)
+        {
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+                mFormattedImage = new LLImagePNG();
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+                mFormattedImage = new LLImageJPEG(mSnapshotQuality);
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+                mFormattedImage = new LLImageBMP();
+                break;
+        }
+        if (mFormattedImage->encode(mPreviewImage, 0))
+        {
+            // We can update the data size precisely at that point
+            mDataSize = mFormattedImage->getDataSize();
+        }
+    }
+    return mFormattedImage;
 }
 
 void LLSnapshotLivePreview::setSize(S32 w, S32 h)
@@ -776,6 +946,15 @@ void LLSnapshotLivePreview::setSize(S32 w, S32 h)
 	setHeight(h);
 }
 
+void LLSnapshotLivePreview::setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat format)
+{
+    if (mSnapshotFormat != format)
+    {
+        mFormattedImage = NULL;     // Invalidate the already formatted image if any
+        mSnapshotFormat = format;
+    }
+}
+
 void LLSnapshotLivePreview::getSize(S32& w, S32& h) const
 {
 	w = getWidth();
@@ -836,6 +1015,10 @@ void LLSnapshotLivePreview::saveTexture()
 
 BOOL LLSnapshotLivePreview::saveLocal()
 {
+    // Update mFormattedImage if necessary
+    getFormattedImage();
+    
+    // Save the formatted image
 	BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage);
 
 	if(success)
@@ -844,3 +1027,4 @@ BOOL LLSnapshotLivePreview::saveLocal()
 	}
 	return success;
 }
+
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index 0f09ef214ab11d4b7f97979d05ec9584e16c914d..e1937187a3d90f004ac1103079048e57e4798b22 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -28,6 +28,7 @@
 #define LL_LLSNAPSHOTLIVEPREVIEW_H
 
 #include "llpanelsnapshot.h"
+#include "llviewertexture.h"
 #include "llviewerwindow.h"
 
 class LLImageJPEG;
@@ -61,6 +62,8 @@ class LLSnapshotLivePreview : public LLView
 	LLSnapshotLivePreview(const LLSnapshotLivePreview::Params& p);
 	~LLSnapshotLivePreview();
 
+    void setContainer(LLView* container) { mViewContainer = container; }
+
 	/*virtual*/ void draw();
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
 
@@ -70,6 +73,9 @@ class LLSnapshotLivePreview : public LLView
 	void getSize(S32& w, S32& h) const;
 	S32 getWidth() const { return mWidth[mCurImageIndex]; }
 	S32 getHeight() const { return mHeight[mCurImageIndex]; }
+    S32 getEncodedImageWidth() const;
+    S32 getEncodedImageHeight() const;
+    void estimateDataSize();
 	S32 getDataSize() const { return mDataSize; }
 	void setMaxImageSize(S32 size) ;
 	S32  getMaxImageSize() {return mMaxImageSize ;}
@@ -83,36 +89,48 @@ class LLSnapshotLivePreview : public LLView
 	S32  getThumbnailHeight() const { return mThumbnailHeight ; }
 	BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; }
 	BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;}
+    void setThumbnailSubsampled(BOOL subsampled) { mThumbnailSubsampled = subsampled; }
+
 	LLViewerTexture* getCurrentImage();
 	F32 getImageAspect();
-	F32 getAspect() ;
 	const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; }
 	BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; }
 	void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; }
 	const LLVector3d& getPosTakenGlobal() const { return mPosTakenGlobal; }
 
 	void setSnapshotType(ESnapshotType type) { mSnapshotType = type; }
-	void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; }
-	void setSnapshotQuality(S32 quality);
+	void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat format);
+	bool setSnapshotQuality(S32 quality, bool set_by_user = true);
 	void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
+    void setAllowRenderUI(BOOL allow) { mAllowRenderUI = allow; }
+    void setAllowFullScreenPreview(BOOL allow) { mAllowFullScreenPreview = allow; }
+    void setFilter(std::string filter_name) { mFilterName = filter_name; }
+    std::string  getFilter() const { return mFilterName; }
 	void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
 	void saveTexture();
 	BOOL saveLocal();
 
-	LLPointer<LLImageFormatted>	getFormattedImage() const { return mFormattedImage; }
-	LLPointer<LLImageRaw>		getEncodedImage() const { return mPreviewImageEncoded; }
+	LLPointer<LLImageFormatted>	getFormattedImage();
+	LLPointer<LLImageRaw>		getEncodedImage();
 
-	/// Sets size of preview thumbnail image and thhe surrounding rect.
+	/// Sets size of preview thumbnail image and the surrounding rect.
 	void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; }
 	BOOL setThumbnailImageSize() ;
 	void generateThumbnailImage(BOOL force_update = FALSE) ;
 	void resetThumbnailImage() { mThumbnailImage = NULL ; }
 	void drawPreviewRect(S32 offset_x, S32 offset_y) ;
 
+    
+	LLViewerTexture* getBigThumbnailImage();
+	S32  getBigThumbnailWidth() const { return mBigThumbnailWidth ; }
+	S32  getBigThumbnailHeight() const { return mBigThumbnailHeight ; }
+
 	// Returns TRUE when snapshot generated, FALSE otherwise.
 	static BOOL onIdle( void* snapshot_preview );
 
 private:
+    LLView*                     mViewContainer;
+    
 	LLColor4					mColor;
 	LLPointer<LLViewerTexture>	mViewerImage[2]; //used to represent the scene when the frame is frozen.
 	LLRect						mImageRect[2];
@@ -129,11 +147,20 @@ class LLSnapshotLivePreview : public LLView
 	BOOL                        mThumbnailUpdateLock ;
 	BOOL                        mThumbnailUpToDate ;
 	LLRect                      mThumbnailPlaceholderRect;
+    BOOL                        mThumbnailSubsampled; // TRUE if the thumbnail is a subsampled version of the mPreviewImage
+    
+	LLPointer<LLViewerTexture>	mBigThumbnailImage ;
+    S32                         mBigThumbnailWidth;
+    S32                         mBigThumbnailHeight;
+    BOOL                        mBigThumbnailUpToDate;
 
 	S32							mCurImageIndex;
+    // The logic is mPreviewImage (raw frame) -> mFormattedImage (formatted / filtered) -> mPreviewImageEncoded (decoded back, to show artifacts)
 	LLPointer<LLImageRaw>		mPreviewImage;
 	LLPointer<LLImageRaw>		mPreviewImageEncoded;
 	LLPointer<LLImageFormatted>	mFormattedImage;
+    BOOL                        mAllowRenderUI;
+    BOOL                        mAllowFullScreenPreview;
 	LLFrameTimer				mSnapshotDelayTimer;
 	S32							mShineCountdown;
 	LLFrameTimer				mShineAnimTimer;
@@ -150,6 +177,7 @@ class LLSnapshotLivePreview : public LLView
 	LLQuaternion				mCameraRot;
 	BOOL						mSnapshotActive;
 	LLViewerWindow::ESnapshotType mSnapshotBufferType;
+    std::string                 mFilterName;
 
 public:
 	static std::set<LLSnapshotLivePreview*> sList;
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 14a42dd8dc260dda6978f8e91d4eae61242ef134..9ea46cab68ebae968eab73d361cc00db35c9d2f4 100755
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2593,7 +2593,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
 
 	S32 desired_size;
 	std::string exten = gDirUtilp->getExtension(url);
-	if (f_type == FTT_SERVER_BAKE)
+	//if (f_type == FTT_SERVER_BAKE)
+    if ((f_type == FTT_SERVER_BAKE) && !url.empty() && !exten.empty() && (LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
 	{
 		// SH-4030: This case should be redundant with the following one, just
 		// breaking it out here to clarify that it's intended behavior.
diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7088558b83a1ada7f0a21bdb753209e07b181933
--- /dev/null
+++ b/indra/newview/lltwitterconnect.cpp
@@ -0,0 +1,503 @@
+/** 
+ * @file lltwitterconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Twitter Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltwitterconnect.h"
+
+#include "llagent.h"
+#include "llcallingcard.h"			// for LLAvatarTracker
+#include "llcommandhandler.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
+#include "llurlaction.h"
+#include "llimagepng.h"
+#include "llimagejpeg.h"
+#include "lltrans.h"
+#include "llevents.h"
+#include "llviewerregion.h"
+
+#include "llfloaterwebcontent.h"
+#include "llfloaterreg.h"
+
+boost::scoped_ptr<LLEventPump> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState"));
+boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo"));
+boost::scoped_ptr<LLEventPump> LLTwitterConnect::sContentWatcher(new LLEventStream("TwitterConnectContent"));
+
+// Local functions
+void log_twitter_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
+{
+    // Note: 302 (redirect) is *not* an error that warrants logging
+    if (status != 302)
+    {
+		LL_WARNS("TwitterConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL;
+    }
+}
+
+void toast_user_for_twitter_success()
+{
+	LLSD args;
+    args["MESSAGE"] = LLTrans::getString("twitter_post_success");
+    LLNotificationsUtil::add("TwitterConnect", args);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterConnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterConnectResponder);
+public:
+	
+    LLTwitterConnectResponder()
+    {
+        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+    }
+    
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
+        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		if ( HTTP_FOUND == getStatus() )
+		{
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+                LLTwitterConnect::instance().openTwitterWeb(location);
+			}
+		}
+		else
+		{
+			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
+			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+			const LLSD& content = getContent();
+			log_twitter_connect_error("Connect", getStatus(), getReason(),
+									   content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterShareResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterShareResponder);
+public:
+    
+	LLTwitterShareResponder()
+	{
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+	}
+	
+	/* virtual */ void httpSuccess()
+	{
+        toast_user_for_twitter_success();
+		LL_DEBUGS("TwitterConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
+        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTED);
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		if ( HTTP_FOUND == getStatus() )
+		{
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+                LLTwitterConnect::instance().openTwitterWeb(location);
+			}
+		}
+		else if ( HTTP_NOT_FOUND == getStatus() )
+		{
+			LLTwitterConnect::instance().connectToTwitter();
+		}
+		else
+		{
+			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED);
+			const LLSD& content = getContent();
+			log_twitter_connect_error("Share", getStatus(), getReason(),
+									   content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterDisconnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterDisconnectResponder);
+public:
+ 
+	LLTwitterDisconnectResponder()
+	{
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING);
+	}
+
+	void setUserDisconnected()
+	{
+		// Clear data
+		LLTwitterConnect::instance().clearInfo();
+
+		//Notify state change
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
+	}
+
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL;
+		setUserDisconnected();
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		//User not found so already disconnected
+		if ( HTTP_NOT_FOUND == getStatus() )
+		{
+			LL_DEBUGS("TwitterConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;
+			setUserDisconnected();
+		}
+		else
+		{
+			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
+			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED);
+			const LLSD& content = getContent();
+			log_twitter_connect_error("Disconnect", getStatus(), getReason(),
+									   content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterConnectedResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterConnectedResponder);
+public:
+    
+	LLTwitterConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+    {
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+    }
+    
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
+        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		// show the facebook login page if not connected yet
+		if ( HTTP_NOT_FOUND == getStatus() )
+		{
+			LL_DEBUGS("TwitterConnect") << "Not connected. " << dumpResponse() << LL_ENDL;
+			if (mAutoConnect)
+			{
+                LLTwitterConnect::instance().connectToTwitter();
+			}
+			else
+			{
+                LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
+			}
+		}
+		else
+		{
+			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+			const LLSD& content = getContent();
+			log_twitter_connect_error("Connected", getStatus(), getReason(),
+									   content.get("error_code"), content.get("error_description"));
+		}
+	}
+    
+private:
+	bool mAutoConnect;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterInfoResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterInfoResponder);
+public:
+
+	/* virtual */ void httpSuccess()
+	{
+		LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL;
+		LL_DEBUGS("TwitterConnect") << "Getting Twitter info successful. " << dumpResponse() << LL_ENDL;
+        LLTwitterConnect::instance().storeInfo(getContent());
+	}
+    
+	/* virtual */ void httpFailure()
+	{
+		if ( HTTP_FOUND == getStatus() )
+		{
+			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (location.empty())
+			{
+				LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse()
+                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			}
+			else
+			{
+                LLTwitterConnect::instance().openTwitterWeb(location);
+			}
+		}
+		else
+		{
+			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
+			const LLSD& content = getContent();
+			log_twitter_connect_error("Info", getStatus(), getReason(),
+									   content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+LLTwitterConnect::LLTwitterConnect()
+:	mConnectionState(TWITTER_NOT_CONNECTED),
+	mConnected(false),
+	mInfo(),
+	mRefreshInfo(false),
+	mReadFromMaster(false)
+{
+}
+
+void LLTwitterConnect::openTwitterWeb(std::string url)
+{
+	// Open the URL in an internal browser window without navigation UI
+	LLFloaterWebContent::Params p;
+    p.url(url);
+    p.show_chrome(true);
+    p.allow_address_entry(false);
+    p.allow_back_forward_navigation(false);
+    p.trusted_content(true);
+    p.clean_browser(true);
+	LLFloater *floater = LLFloaterReg::showInstance("twitter_web", p);
+	//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
+	//So when showing the internal web browser, set focus to it's containing floater "twitter_web". When a mouse event 
+	//occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus.
+	//twitter_web floater contains the "webbrowser" panel.    JIRA: ACME-744
+	gFocusMgr.setKeyboardFocus( floater );
+
+	//LLUrlAction::openURLExternal(url);
+}
+
+std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, bool include_read_from_master)
+{
+    std::string url("");
+    LLViewerRegion *regionp = gAgent.getRegion();
+    if (regionp)
+    {
+		//url = "http://pdp15.lindenlab.com/twitter/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO
+        url = regionp->getCapability("TwitterConnect");
+        url += route;
+    
+        if (include_read_from_master && mReadFromMaster)
+        {
+            url += "?read_from_master=true";
+        }
+    }
+	return url;
+}
+
+void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier)
+{
+	LLSD body;
+	if (!request_token.empty())
+		body["request_token"] = request_token;
+	if (!oauth_verifier.empty())
+		body["oauth_verifier"] = oauth_verifier;
+    
+	LLHTTPClient::put(getTwitterConnectURL("/connection"), body, new LLTwitterConnectResponder());
+}
+
+void LLTwitterConnect::disconnectFromTwitter()
+{
+	LLHTTPClient::del(getTwitterConnectURL("/connection"), new LLTwitterDisconnectResponder());
+}
+
+void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect)
+{
+	const bool follow_redirects = false;
+	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	LLHTTPClient::get(getTwitterConnectURL("/connection", true), new LLTwitterConnectedResponder(auto_connect),
+						LLSD(), timeout, follow_redirects);
+}
+
+void LLTwitterConnect::loadTwitterInfo()
+{
+	if(mRefreshInfo)
+	{
+		const bool follow_redirects = false;
+		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+		LLHTTPClient::get(getTwitterConnectURL("/info", true), new LLTwitterInfoResponder(),
+			LLSD(), timeout, follow_redirects);
+	}
+}
+
+void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::string& status)
+{
+	LLSD body;
+	body["image"] = image_url;
+	body["status"] = status;
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::post(getTwitterConnectURL("/share/photo", true), body, new LLTwitterShareResponder());
+}
+
+void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status)
+{
+	std::string imageFormat;
+	if (dynamic_cast<LLImagePNG*>(image.get()))
+	{
+		imageFormat = "png";
+	}
+	else if (dynamic_cast<LLImageJPEG*>(image.get()))
+	{
+		imageFormat = "jpg";
+	}
+	else
+	{
+		llwarns << "Image to upload is not a PNG or JPEG" << llendl;
+		return;
+	}
+	
+	// All this code is mostly copied from LLWebProfile::post()
+	const std::string boundary = "----------------------------0123abcdefab";
+
+	LLSD headers;
+	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+
+	std::ostringstream body;
+
+	// *NOTE: The order seems to matter.
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"status\"\r\n\r\n"
+			<< status << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
+			<< "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+	// Insert the image data.
+	// *FIX: Treating this as a string will probably screw it up ...
+	U8* image_data = image->getData();
+	for (S32 i = 0; i < image->getDataSize(); ++i)
+	{
+		body << image_data[i];
+	}
+
+	body <<	"\r\n--" << boundary << "--\r\n";
+
+	// postRaw() takes ownership of the buffer and releases it later.
+	size_t size = body.str().size();
+	U8 *data = new U8[size];
+	memcpy(data, body.str().data(), size);
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::postRaw(getTwitterConnectURL("/share/photo", true), data, size, new LLTwitterShareResponder(), headers);
+}
+
+void LLTwitterConnect::updateStatus(const std::string& status)
+{
+	LLSD body;
+	body["status"] = status;
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::post(getTwitterConnectURL("/share/status", true), body, new LLTwitterShareResponder());
+}
+
+void LLTwitterConnect::storeInfo(const LLSD& info)
+{
+	mInfo = info;
+	mRefreshInfo = false;
+
+	sInfoWatcher->post(info);
+}
+
+const LLSD& LLTwitterConnect::getInfo() const
+{
+	return mInfo;
+}
+
+void LLTwitterConnect::clearInfo()
+{
+	mInfo = LLSD();
+}
+
+void LLTwitterConnect::setDataDirty()
+{
+	mRefreshInfo = true;
+}
+
+void LLTwitterConnect::setConnectionState(LLTwitterConnect::EConnectionState connection_state)
+{
+	if(connection_state == TWITTER_CONNECTED)
+	{
+		mReadFromMaster = true;
+		setConnected(true);
+		setDataDirty();
+	}
+	else if(connection_state == TWITTER_NOT_CONNECTED)
+	{
+		setConnected(false);
+	}
+	else if(connection_state == TWITTER_POSTED)
+	{
+		mReadFromMaster = false;
+	}
+
+	if (mConnectionState != connection_state)
+	{
+		// set the connection state before notifying watchers
+		mConnectionState = connection_state;
+
+		LLSD state_info;
+		state_info["enum"] = connection_state;
+		sStateWatcher->post(state_info);
+	}
+}
+
+void LLTwitterConnect::setConnected(bool connected)
+{
+	mConnected = connected;
+}
diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1df13f18cf558ea934ebe35983c770a6f84bc2e
--- /dev/null
+++ b/indra/newview/lltwitterconnect.h
@@ -0,0 +1,99 @@
+/** 
+ * @file lltwitterconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Twitter Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTWITTERCONNECT_H
+#define LL_LLTWITTERCONNECT_H
+
+#include "llsingleton.h"
+#include "llimage.h"
+
+class LLEventPump;
+
+/**
+ * @class LLTwitterConnect
+ *
+ * Manages authentication to, and interaction with, a web service allowing the
+ * the viewer to post status updates and upload photos to Twitter.
+ */
+class LLTwitterConnect : public LLSingleton<LLTwitterConnect>
+{
+	LOG_CLASS(LLTwitterConnect);
+public:
+    enum EConnectionState
+	{
+		TWITTER_NOT_CONNECTED = 0,
+		TWITTER_CONNECTION_IN_PROGRESS = 1,
+		TWITTER_CONNECTED = 2,
+		TWITTER_CONNECTION_FAILED = 3,
+		TWITTER_POSTING = 4,
+		TWITTER_POSTED = 5,
+		TWITTER_POST_FAILED = 6,
+		TWITTER_DISCONNECTING = 7,
+		TWITTER_DISCONNECT_FAILED = 8
+	};
+	
+	void connectToTwitter(const std::string& request_token = "", const std::string& oauth_verifier = "");	// Initiate the complete Twitter connection. Please use checkConnectionToTwitter() in normal use.
+	void disconnectFromTwitter();																			// Disconnect from the Twitter service.
+    void checkConnectionToTwitter(bool auto_connect = false);												// Check if an access token is available on the Twitter service. If not, call connectToTwitter().
+    
+	void loadTwitterInfo();
+	void uploadPhoto(const std::string& image_url, const std::string& status);
+	void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status);
+	void updateStatus(const std::string& status);
+	
+	void storeInfo(const LLSD& info);
+	const LLSD& getInfo() const;
+	void clearInfo();
+	void setDataDirty();
+    
+    void setConnectionState(EConnectionState connection_state);
+	void setConnected(bool connected);
+	bool isConnected() { return mConnected; }
+	bool isTransactionOngoing() { return ((mConnectionState == TWITTER_CONNECTION_IN_PROGRESS) || (mConnectionState == TWITTER_POSTING) || (mConnectionState == TWITTER_DISCONNECTING)); }
+    EConnectionState getConnectionState() { return mConnectionState; }
+    
+    void openTwitterWeb(std::string url);
+
+private:
+	friend class LLSingleton<LLTwitterConnect>;
+
+	LLTwitterConnect();
+	~LLTwitterConnect() {};
+ 	std::string getTwitterConnectURL(const std::string& route = "", bool include_read_from_master = false);
+
+    EConnectionState mConnectionState;
+	BOOL mConnected;
+	LLSD mInfo;
+	bool mRefreshInfo;
+	bool mReadFromMaster;
+	
+	static boost::scoped_ptr<LLEventPump> sStateWatcher;
+	static boost::scoped_ptr<LLEventPump> sInfoWatcher;
+	static boost::scoped_ptr<LLEventPump> sContentWatcher;
+};
+
+#endif // LL_LLTWITTERCONNECT_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index e427bb173585a434cdf0cbf6d158fc31a914b629..9b3f9195e37c2affd95af9a8c0582fbe00925a09 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -39,6 +39,7 @@
 #include "llfloateravatar.h"
 #include "llfloateravatarpicker.h"
 #include "llfloateravatartextures.h"
+#include "llfloaterbigpreview.h"
 #include "llfloaterbeacons.h"
 #include "llfloaterbuildoptions.h"
 #include "llfloaterbulkpermission.h"
@@ -61,6 +62,8 @@
 #include "llfloatereditwater.h"
 #include "llfloaterenvironmentsettings.h"
 #include "llfloaterevent.h"
+#include "llfloaterfacebook.h"
+#include "llfloaterflickr.h"
 #include "llfloaterfonttest.h"
 #include "llfloatergesture.h"
 #include "llfloatergodtools.h"
@@ -104,7 +107,6 @@
 #include "llfloatersettingsdebug.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llfloatersnapshot.h"
-#include "llfloatersocial.h"
 #include "llfloatersounddevices.h"
 #include "llfloaterspellchecksettings.h"
 #include "llfloatertelehub.h"
@@ -116,6 +118,7 @@
 #include "llfloatertos.h"
 #include "llfloatertoybox.h"
 #include "llfloatertranslationsettings.h"
+#include "llfloatertwitter.h"
 #include "llfloateruipreview.h"
 #include "llfloatervoiceeffect.h"
 #include "llfloaterwebcontent.h"
@@ -305,7 +308,6 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
 	LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
 	LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
-	LLFloaterReg::add("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>);
 	LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
 	LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
 	LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>);
@@ -314,8 +316,16 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);
 	LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
 	LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
-	LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);	
+	LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
+
 	LLFloaterReg::add("fbc_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
+	LLFloaterReg::add("flickr_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
+	LLFloaterReg::add("twitter_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
+	
+	LLFloaterReg::add("facebook", "floater_facebook.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFacebook>);
+	LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFlickr>);
+	LLFloaterReg::add("twitter", "floater_twitter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTwitter>);
+	LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>);
 	
 	LLFloaterUIPreviewUtil::registerFloater();
 	LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload");
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index ed268420357685f91d29d99f20478b803666362b..bdda37cc5ff2c054677ca781e5dcfbc2922c2180 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1524,7 +1524,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
 	// popping up at the moment we start a media plugin.
 	if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
 	{
-		// The null owner will keep the browser plugin from fully initializing 
+		// The null owner will keep the browser plugin from fully initializing
 		// (specifically, it keeps LLPluginClassMedia from negotiating a size change, 
 		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
 		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0);
@@ -1533,7 +1533,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
 
 /////////////////////////////////////////////////////////////////////////////////////////
 // static
-LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() 
+LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()
 {
 	LLPluginClassMedia* result = sSpareBrowserMediaSource;
 	sSpareBrowserMediaSource = NULL;
@@ -1582,7 +1582,7 @@ std::string LLViewerMedia::getParcelAudioURL()
 // static
 void LLViewerMedia::initClass()
 {
-	gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL);	
+	gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL);
 	sTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
 		setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished));
 }
@@ -1670,7 +1670,8 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 	mNavigateSuspendedDeferred(false),
 	mIsUpdated(false),
 	mTrustedBrowser(false),
-	mZoomFactor(1.0)
+	mZoomFactor(1.0),
+    mCleanBrowser(false)
 { 
 
 	// Set up the mute list observer if it hasn't been set up already.
@@ -1794,14 +1795,16 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 
 //////////////////////////////////////////////////////////////////////////////////////////
 /*static*/
-LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)
+LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target, bool clean_browser)
 {
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
 	LLPluginClassMedia* media_source = NULL;
 	
 	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
 	// If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it.
-	if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
+    // Do not use a spare if launching with full viewer control (e.g. Facebook, Twitter and few others)
+	if ((plugin_basename == "media_plugin_webkit") &&
+        !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins") && !clean_browser)
 	{
 		media_source = LLViewerMedia::getSpareBrowserMediaSource();
 		if(media_source)
@@ -1813,7 +1816,6 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 			return media_source;
 		}
 	}
-	
 	if(plugin_basename.empty())
 	{
 		LL_WARNS_ONCE("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL;
@@ -1857,18 +1859,18 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 
 			// collect 'cookies enabled' setting from prefs and send to embedded browser
 			bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" );
-			media_source->enable_cookies( cookies_enabled );
+			media_source->enable_cookies( cookies_enabled || clean_browser);
 
 			// collect 'plugins enabled' setting from prefs and send to embedded browser
 			bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
-			media_source->setPluginsEnabled( plugins_enabled );
+			media_source->setPluginsEnabled( plugins_enabled  || clean_browser);
 
 			// collect 'javascript enabled' setting from prefs and send to embedded browser
 			bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
-			media_source->setJavascriptEnabled( javascript_enabled );
+			media_source->setJavascriptEnabled( javascript_enabled || clean_browser);
 		
 			bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
-			media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled );
+			media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled  || clean_browser);
 
 			media_source->setTarget(target);
 			
@@ -1923,7 +1925,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 	// Save the MIME type that really caused the plugin to load
 	mCurrentMimeType = mMimeType;
 
-	LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget);
+	LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget, mCleanBrowser);
 	
 	if (media_source)
 	{
@@ -2544,7 +2546,7 @@ void LLViewerMediaImpl::unload()
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type,  bool rediscover_type, bool server_request)
+void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type,  bool rediscover_type, bool server_request, bool clean_browser)
 {
 	cancelMimeTypeProbe();
 
@@ -2557,6 +2559,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
 	// Always set the current URL and MIME type.
 	mMediaURL = url;
 	mMimeType = mime_type;
+    mCleanBrowser = clean_browser;
 	
 	// Clear the current media URL, since it will no longer be correct.
 	mCurrentMediaURL.clear();
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index fff5b3fc089211ac9693295cf90e1ac2a78326e2..6803adfaa251bc986ff6a76aacebc9009f1f5e70 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -234,7 +234,7 @@ class LLViewerMediaImpl
 	void navigateReload();
 	void navigateHome();
 	void unload();
-	void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false);
+	void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false, bool clean_browser = false);
 	void navigateInternal();
 	void navigateStop();
 	bool handleKeyHere(KEY key, MASK mask);
@@ -289,7 +289,7 @@ class LLViewerMediaImpl
 	void setTarget(const std::string& target) { mTarget = target; }
 	
 	// utility function to create a ready-to-use media instance from a desired media type.
-	static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null);
+	static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null, bool clean_browser = false);
 
 	// Internally set our desired browser user agent string, including
 	// the Second Life version and skin name.  Used because we can
@@ -464,6 +464,7 @@ class LLViewerMediaImpl
 	bool mTrustedBrowser;
 	std::string mTarget;
 	LLNotificationPtr mNotification;
+    bool mCleanBrowser;     // force the creation of a clean browsing target with full options enabled
 
 private:
 	BOOL mIsUpdated ;
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 04697f34727fcf3bec6e4a17182f214bbe46c869..9199e7fd97c1b3627767111cdce91375796df7b8 100755
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -215,7 +215,8 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
 #endif
 	case LLFilePicker::FFLOAD_XML:
 	    return XML_EXTENSIONS;
-	case LLFilePicker::FFLOAD_ALL:
+    case LLFilePicker::FFLOAD_ALL:
+    case LLFilePicker::FFLOAD_EXE:
 		return ALL_FILE_EXTENSIONS;
 #endif
     default:
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index f15ebda452b4e35a23d3b90618913bb066cd8f11..d1e8ac9d7ed2dd77617acadca3ac54ebac974c85 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2658,7 +2658,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("EstateChangeInfo");
 	capabilityNames.append("EventQueueGet");
 	capabilityNames.append("FacebookConnect");
-	//capabilityNames.append("FacebookRedirect");
+	capabilityNames.append("FlickrConnect");
+	capabilityNames.append("TwitterConnect");
 
 	if (gSavedSettings.getBOOL("UseHTTPInventory"))
 	{	
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index d4df1ee71c56ebae2c22edc5963e1b619c894648..ec733c1e8bc13df1f1de61b07b2ef8967b7a6de6 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -133,6 +133,8 @@ with the same filename but different name
   <texture name="Command_Chat_Icon"         file_name="toolbar_icons/chat.png"         preload="true" />
   <texture name="Command_Compass_Icon"      file_name="toolbar_icons/land.png"         preload="true" />
   <texture name="Command_Destinations_Icon" file_name="toolbar_icons/destinations.png" preload="true" />
+  <texture name="Command_Facebook_Icon"     file_name="toolbar_icons/facebook.png"     preload="true" />
+  <texture name="Command_Flickr_Icon"       file_name="toolbar_icons/flickr.png"       preload="true" />
   <texture name="Command_Gestures_Icon"     file_name="toolbar_icons/gestures.png"     preload="true" />
   <texture name="Command_HowTo_Icon"        file_name="toolbar_icons/howto.png"        preload="true" />
   <texture name="Command_Inventory_Icon"    file_name="toolbar_icons/inventory.png"    preload="true" />
@@ -148,9 +150,9 @@ with the same filename but different name
   <texture name="Command_Preferences_Icon"  file_name="toolbar_icons/preferences.png"  preload="true" />
   <texture name="Command_Profile_Icon"      file_name="toolbar_icons/profile.png"      preload="true" />
   <texture name="Command_Search_Icon"       file_name="toolbar_icons/search.png"       preload="true" />
-  <texture name="Command_Social_Icon"       file_name="toolbar_icons/facebook.png"     preload="true" />
   <texture name="Command_Snapshot_Icon"     file_name="toolbar_icons/snapshot.png"     preload="true" />
   <texture name="Command_Speak_Icon"        file_name="toolbar_icons/speak.png"        preload="true" />
+  <texture name="Command_Twitter_Icon"      file_name="toolbar_icons/twitter.png"      preload="true" />
   <texture name="Command_View_Icon"         file_name="toolbar_icons/view.png"         preload="true" />
   <texture name="Command_Voice_Icon"        file_name="toolbar_icons/nearbyvoice.png"  preload="true" />
   <texture name="Caret_Bottom_Icon"         file_name="toolbar_icons/caret_bottom.png" preload="true" scale.left="1" scale.top="23" scale.right="15" scale.bottom="1" />
diff --git a/indra/newview/skins/default/textures/toolbar_icons/flickr.png b/indra/newview/skins/default/textures/toolbar_icons/flickr.png
new file mode 100644
index 0000000000000000000000000000000000000000..7fce9f0df24675f2af445689467a21ec14796a54
Binary files /dev/null and b/indra/newview/skins/default/textures/toolbar_icons/flickr.png differ
diff --git a/indra/newview/skins/default/textures/toolbar_icons/twitter.png b/indra/newview/skins/default/textures/toolbar_icons/twitter.png
new file mode 100644
index 0000000000000000000000000000000000000000..a99c490887eafde50d0b4295d3bd93efafab3dda
Binary files /dev/null and b/indra/newview/skins/default/textures/toolbar_icons/twitter.png differ
diff --git a/indra/newview/skins/default/xui/en/floater_big_preview.xml b/indra/newview/skins/default/xui/en/floater_big_preview.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c0bdd3d9bd4d7f7b87972c7d1b09a78567b557f9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_big_preview.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="true"
+  can_minimize="false"
+  help_topic="floater_big_preview"
+  layout="topleft"
+  name="floater_big_preview"
+  save_rect="true"
+  single_instance="true"
+  reuse_instance="true"
+  title="PREVIEW"
+  height="465"
+  width="770">
+  <panel
+   height="450"
+   width="750"
+   visible="true"
+   name="big_preview_placeholder"
+   top="5"
+   follows="all"
+   left="10">
+  </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_facebook.xml b/indra/newview/skins/default/xui/en/floater_facebook.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4535b9084e6f9aea909450c73c5eb483eed2b868
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_facebook.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="true"
+  help_topic="floater_facebook"
+  layout="topleft"
+  name="floater_facebook"
+  save_rect="true"
+  single_instance="true"
+  reuse_instance="true"
+  title="POST TO FACEBOOK"
+  min_height="501"
+  min_width="304"
+  height="482"
+  width="304">
+  <panel
+   height="482"
+   width="304"
+   visible="true"
+   name="background"
+   follows="all"
+   top="0"
+   left="0">
+   <tab_container
+     name="tabs"
+     tab_group="1"
+     tab_min_width="70"
+     tab_height="30"
+     tab_position="top"
+     top="7"
+     height="437"
+     follows="all"
+     halign="center"
+     use_highlighting_on_hover="true">
+     <panel
+       filename="panel_facebook_status.xml"
+       class="llfacebookstatuspanel"
+       follows="all"
+       label="STATUS"
+       name="panel_facebook_status"/>
+     <panel
+       filename="panel_facebook_photo.xml"
+       class="llfacebookphotopanel"
+       follows="all"
+       label="PHOTO"
+       name="panel_facebook_photo"/>
+     <panel
+       filename="panel_facebook_place.xml"
+       class="llfacebookcheckinpanel"
+       follows="all"
+       label="CHECK IN"
+       name="panel_facebook_place"/>
+     <panel
+       filename="panel_facebook_friends.xml"
+       class="llfacebookfriendspanel"
+       follows="all"
+       label="FRIENDS"
+       name="panel_facebook_friends"/>
+     <panel
+       filename="panel_facebook_account.xml"
+       class="llfacebookaccountpanel"
+       follows="all"
+       label="ACCOUNT"
+       name="panel_facebook_account"/>
+   </tab_container>
+    <panel
+     name="connection_status_panel"
+     follows="left|bottom|right"
+     height="24">
+     <text
+      name="connection_error_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left="9"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="DrYellow"
+      font="SansSerif">
+      Error
+     </text>
+     <loading_indicator
+      follows="left|bottom"
+      height="24"
+      width="24"
+      name="connection_loading_indicator"
+      top="2"
+      left="9"
+      visible="true"/>
+     <text
+      name="connection_loading_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left_pad="5"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="EmphasisColor"
+      font="SansSerif">
+      Loading...
+    </text>
+  </panel>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_social.xml b/indra/newview/skins/default/xui/en/floater_flickr.xml
similarity index 68%
rename from indra/newview/skins/default/xui/en/floater_social.xml
rename to indra/newview/skins/default/xui/en/floater_flickr.xml
index b7ff374d5f6c6f6284350d3a03f778ea9e3c4f66..1a9ffd0489b161f13145edb394b4dd4fbd50164d 100644
--- a/indra/newview/skins/default/xui/en/floater_social.xml
+++ b/indra/newview/skins/default/xui/en/floater_flickr.xml
@@ -3,17 +3,17 @@
   positioning="cascading"
   can_close="true"
   can_resize="false"
-  help_topic="floater_social"
+  help_topic="floater_flickr"
   layout="topleft"
-  name="floater_social"
+  name="floater_flickr"
   save_rect="true"
   single_instance="true"
   reuse_instance="true"
-  title="POST TO FACEBOOK"
-  height="482"
+  title="UPLOAD TO FLICKR"
+  height="622"
   width="304">
   <panel
-   height="482"
+   height="622"
    width="304"
    visible="true"
    name="background"
@@ -27,32 +27,21 @@
      tab_height="30"
      tab_position="top"
      top="7"
-     height="437"
-     halign="center">
+     height="577"
+     halign="center"
+     use_highlighting_on_hover="true">
      <panel
-       filename="panel_social_status.xml"
-       class="llsocialstatuspanel"
-       follows="all"
-       label="STATUS"
-       name="panel_social_status"/>
-     <panel
-       filename="panel_social_photo.xml"
-       class="llsocialphotopanel"
+       filename="panel_flickr_photo.xml"
+       class="llflickrphotopanel"
        follows="all"
        label="PHOTO"
-       name="panel_social_photo"/>
-     <panel
-       filename="panel_social_place.xml"
-       class="llsocialcheckinpanel"
-       follows="all"
-       label="CHECK IN"
-       name="panel_social_place"/>
+       name="panel_flickr_photo"/>
      <panel
-       filename="panel_social_account.xml"
-       class="llsocialaccountpanel"
+       filename="panel_flickr_account.xml"
+       class="llflickraccountpanel"
        follows="all"
        label="ACCOUNT"
-       name="panel_social_account"/>     
+       name="panel_flickr_account"/>     
     </tab_container>
     <panel
      name="connection_status_panel"
diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml
index 853c209bcac0e4395a287dcef2142e6a187ec5fa..771035b40da33c7314dc8d54676c03a2499685f4 100755
--- a/indra/newview/skins/default/xui/en/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml
@@ -10,7 +10,7 @@
  help_topic="snapshot"
  save_rect="true"
  save_visibility="false"
- title="SNAPSHOT PREVIEW"
+ title="SNAPSHOT"
  width="470">
     <floater.string
      name="unknown">
@@ -381,5 +381,31 @@
          top_pad="8"
          width="180"
          name="auto_snapshot_check" />
+        <text
+         type="string"
+         length="1"
+         follows="left|top"
+         height="13"
+         layout="topleft"
+         left="10"
+         name="filter_list_label"
+         top_pad="10"
+         width="50">
+            Filter:
+        </text>
+        <combo_box
+            control_name="PhotoFilters"
+            follows="left|right|top"
+            name="filters_combobox"
+            tool_tip="Image filters"
+            top_pad="8"
+            left="30"
+            height="21"
+            width="135">
+            <combo_box.item
+            label="No Filter"
+            name="NoFilter"
+            value="NoFilter" />
+        </combo_box>
     </panel>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_twitter.xml b/indra/newview/skins/default/xui/en/floater_twitter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aa5bfce2e9775d81b22afc598c49319669b8f4bd
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_twitter.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="false"
+  help_topic="floater_twitter"
+  layout="topleft"
+  name="floater_twitter"
+  save_rect="true"
+  single_instance="true"
+  reuse_instance="true"
+  title="TWITTER"
+  height="502"
+  width="304">
+  <panel
+   height="502"
+   width="304"
+   visible="true"
+   name="background"
+   follows="all"
+   top="0"
+   left="0">
+   <tab_container
+     name="tabs"
+     tab_group="1"
+     tab_min_width="70"
+     tab_height="30"
+     tab_position="top"
+     top="7"
+     height="457"
+     halign="center"
+     use_highlighting_on_hover="true">
+     <panel
+       filename="panel_twitter_photo.xml"
+       class="lltwitterphotopanel"
+       follows="all"
+       label="COMPOSE"
+       name="panel_twitter_photo"/>
+     <panel
+       filename="panel_twitter_account.xml"
+       class="lltwitteraccountpanel"
+       follows="all"
+       label="ACCOUNT"
+       name="panel_twitter_account"/>     
+    </tab_container>
+    <panel
+     name="connection_status_panel"
+     follows="left|bottom|right"
+     height="24">
+     <text
+      name="connection_error_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left="9"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="DrYellow"
+      font="SansSerif">
+      Error
+     </text>
+     <loading_indicator
+      follows="left|bottom|right"
+      height="24"
+      width="24"
+      name="connection_loading_indicator"
+      top="2"
+      left="9"
+      visible="true"/>
+     <text
+      name="connection_loading_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left_pad="5"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="EmphasisColor"
+      font="SansSerif">
+      Loading...
+    </text>
+  </panel>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index ec20c25f14ea1e9187c215f6d0d93788d7a80711..65b80ff6225acc6db0ca98da247e4a9299abc8b2 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -15,14 +15,6 @@
          function="ShowAgentProfile"
          parameter="agent" />
       </menu_item_call>
-      <menu_item_call
-        label="Post to Facebook..."
-        name="PostToFacebook">
-        <menu_item_call.on_click
-          function="Floater.Toggle"
-          parameter="social"/>
-      </menu_item_call>      
-      <menu_item_separator/>
       <menu_item_call
        label="Appearance..."
        name="ChangeOutfit">
@@ -288,6 +280,28 @@
              parameter="conversation" />
         </menu_item_check>
         <menu_item_separator/>
+      <menu_item_call
+        label="Facebook..."
+        name="Facebook">
+        <menu_item_call.on_click
+          function="Floater.Toggle"
+          parameter="facebook"/>
+      </menu_item_call>
+      <menu_item_call
+        label="Twitter..."
+        name="Twitter">
+        <menu_item_call.on_click
+          function="Floater.Toggle"
+          parameter="twitter"/>
+      </menu_item_call>
+      <menu_item_call
+        label="Flickr..."
+        name="Flickr">
+        <menu_item_call.on_click
+          function="Floater.Toggle"
+          parameter="flickr"/>
+      </menu_item_call>
+        <menu_item_separator/>
         <menu
          label="Voice morphing"
          name="VoiceMorphing"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index ff042e55cea4112369b2bbbda57ca7a5edbf20d9..1857563be423ff6d17ba7ad6cd2f347ee0244b4e 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6115,7 +6115,21 @@ Please select at least one type of content to search (General, Moderate, or Adul
   type="notifytip">
 [MESSAGE]
  </notification>
-    
+
+  <notification
+   icon="notify.tga"
+   name="FlickrConnect"
+   type="notifytip">
+    [MESSAGE]
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="TwitterConnect"
+   type="notifytip">
+    [MESSAGE]
+  </notification>
+
   <notification
    icon="notify.tga"
    name="PaymentReceived"
diff --git a/indra/newview/skins/default/xui/en/panel_social_account.xml b/indra/newview/skins/default/xui/en/panel_facebook_account.xml
similarity index 91%
rename from indra/newview/skins/default/xui/en/panel_social_account.xml
rename to indra/newview/skins/default/xui/en/panel_facebook_account.xml
index d7235396fe64e8c712f5ce14c38e3d8393148804..122cbfb7170a75e9e0534090da9b1a4f0083f611 100644
--- a/indra/newview/skins/default/xui/en/panel_social_account.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_account.xml
@@ -2,7 +2,8 @@
 	 height="400"
 	 width="304"
 	 layout="topleft"
-   name="panel_social_account">
+    follows="all"
+   name="panel_facebook_account">
   <string
       name="facebook_connected"
       value="You are connected to Facebook as:" />
@@ -34,6 +35,7 @@
    type="string"/>
   <panel
     layout="topleft"
+    follows="left|top"
     name="panel_buttons"
     height="345"
     left="9">
@@ -69,7 +71,7 @@
       name="account_learn_more_label"
       top_pad="20"
       type="string">
-      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share/ta-p/2149711 Learn about posting to Facebook]
+      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Facebook/ta-p/2149711 Learn about posting to Facebook]
     </text>
   </panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_facebook_friends.xml b/indra/newview/skins/default/xui/en/panel_facebook_friends.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9d21a3a29345ce6eb9a7cccc7058a94ee7556a8d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_facebook_friends.xml
@@ -0,0 +1,72 @@
+<panel
+	 height="400"
+	 width="304"
+	 layout="topleft"
+    follows="all"
+   name="panel_facebook_friends">
+  <string
+   name="facebook_friends_empty"
+   value="You currently do not have any Facebook friends who are also Second Life residents. Ask your Facebook friends to join Second Life today!" />
+  <string
+   name="facebook_friends_no_connected"
+   value="You're currently not connected to Facebook. Please go to the Account tab to connect and enable this feature." />
+  <accordion
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+   follows="all"
+   height="408"
+   layout="topleft"
+   left="3"
+   name="friends_accordion"
+   right="-2"
+   top_pad="2">
+    <accordion_tab
+     layout="topleft"
+     height="173"
+     name="tab_second_life_friends"
+     title="SL friends">
+      <avatar_list
+       ignore_online_status="true"
+       allow_select="true"
+       follows="all"
+       height="173"
+       layout="topleft"
+       left="0"
+       name="second_life_friends"
+       show_permissions_granted="true"
+       top="0"
+       width="307" />
+    </accordion_tab>
+    <accordion_tab
+     layout="topleft"
+     height="173"
+     name="tab_suggested_friends"
+     title="Add these people as SL friends">
+      <avatar_list
+       ignore_online_status="true"
+       allow_select="true"
+       follows="all"
+       height="173"
+       layout="topleft"
+       left="0"
+       name="suggested_friends"
+       show_permissions_granted="true"
+       top="0"
+       width="307" />
+    </accordion_tab>
+  </accordion>
+    <text
+        layout="topleft"
+        word_wrap="true"
+        height="64"
+        width="290"
+        follows="top|left|right"
+        font="SansSerif"
+        left="9"
+        name="facebook_friends_status"
+        top="21"
+        type="string">
+        Not connected to Facebook.
+    </text>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_social_photo.xml b/indra/newview/skins/default/xui/en/panel_facebook_photo.xml
similarity index 72%
rename from indra/newview/skins/default/xui/en/panel_social_photo.xml
rename to indra/newview/skins/default/xui/en/panel_facebook_photo.xml
index c79a246d9d137a752e0e5a83bd4e389da6582828..b5b6dee004a97ffcb10e6a0fad29fc03132b617c 100644
--- a/indra/newview/skins/default/xui/en/panel_social_photo.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_photo.xml
@@ -2,7 +2,8 @@
       height="400"
       width="304"
       layout="topleft"
-      name="panel_social_photo">
+      follows="all"
+      name="panel_facebook_photo">
       <layout_stack
 	   layout="topleft"
        border_size="0"
@@ -15,7 +16,7 @@
          name="snapshot_panel"
          height="367">
             <combo_box
-             control_name="SocialPhotoResolution"
+             control_name="FacebookPhotoResolution"
              follows="left|top"
              top="6"
              left="9"
@@ -39,27 +40,32 @@
                label="1024x768"
                name="1024x768"
                value="[i1024,i768]" />
+              <combo_box.item
+               label="1200x630"
+               name="1200x630"
+               value="[i1200,i630]" />
+            </combo_box>
+            <combo_box
+                control_name="FacebookPhotoFilters"
+                follows="right|top"
+                name="filters_combobox"
+                tool_tip="Image filters"
+                top="6"
+                left="165"
+                height="21"
+                width="135">
+                <combo_box.item
+                label="No Filter"
+                name="NoFilter"
+                value="NoFilter" />
             </combo_box>
-            <text
-             follows="left|top"
-             font="SansSerifSmall"
-             height="14"
-             left="208"
-             length="1"
-             halign="right"
-             name="file_size_label"
-             top="9"
-             type="string"
-             width="50">
-              [SIZE] KB
-            </text>
             <panel
                 height="150"
                 width="250"
                 visible="true"
                 name="thumbnail_placeholder"
                 top="33"
-                follows="left|top"
+                follows="left|top|right"
                 left="9">
             </panel>
             <button
@@ -81,7 +87,7 @@
                 text_color="EmphasisColor"
                 height="14"
                 top_pad="-19"
-                left_pad="-20"
+                left_pad="-30"
                 length="1"
                 halign="center"
                 name="working_lbl"
@@ -91,6 +97,20 @@
                 width="150">
                 Refreshing...
             </text>
+            <button
+                follows="right|top"
+                height="23"
+                label="Preview"
+                left="200"
+                top_pad="-19"
+                name="big_preview_btn"
+                tool_tip="Click to toggle preview"
+                is_toggle="true"
+                visible="true"
+                width="100" >
+                <button.commit_callback
+                function="SocialSharing.BigPreview" />
+            </button>
             <text
              length="1"
              follows="top|left|right"
@@ -103,7 +123,7 @@
               Comment (optional):
             </text>
             <text_editor
-             follows="left|top"
+             follows="left|top|right|bottom"
              height="87"
              width="250"
              left="9"
@@ -118,7 +138,7 @@
           name="photo_button_panel"
           height="25">
           <button
-           follows="left|top"
+           follows="left|bottom"
            top="0"
            left="9"
            height="23"
@@ -129,7 +149,7 @@
              function="SocialSharing.SendPhoto" />
           </button>
           <button
-               follows="left|top"
+               follows="left|bottom"
                height="23"
                label="Cancel"
                name="cancel_photo_btn"
diff --git a/indra/newview/skins/default/xui/en/panel_social_place.xml b/indra/newview/skins/default/xui/en/panel_facebook_place.xml
similarity index 95%
rename from indra/newview/skins/default/xui/en/panel_social_place.xml
rename to indra/newview/skins/default/xui/en/panel_facebook_place.xml
index 13e94f6998ce42168c2d3e3fb05c5f5382b45a5b..84c87df5239b7416880b312c57b27523f537f546 100644
--- a/indra/newview/skins/default/xui/en/panel_social_place.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_place.xml
@@ -2,7 +2,8 @@
       height="400"
       width="304"
 	  layout="topleft"
-      name="panel_social_place">
+      follows="all"
+      name="panel_facebook_place">
       <layout_stack
 	    layout="topleft"
         border_size="0"
@@ -26,7 +27,7 @@
             Say something about where you are:
           </text>
           <text_editor
-            follows="top|left"
+            follows="top|left|right"
             height="150"
             width="250"
             left="9"
@@ -106,7 +107,7 @@
             name="place_button_panel"
             height="25">
             <button
-              follows="left|top"
+              follows="left|bottom"
               top="0"
               left="9"
               height="23"
@@ -117,7 +118,7 @@
                  function="SocialSharing.SendCheckin" />
             </button>
             <button
-              follows="left|top"
+              follows="left|bottom"
               height="23"
               label="Cancel"
               name="cancel_place_btn"
diff --git a/indra/newview/skins/default/xui/en/panel_social_status.xml b/indra/newview/skins/default/xui/en/panel_facebook_status.xml
similarity index 90%
rename from indra/newview/skins/default/xui/en/panel_social_status.xml
rename to indra/newview/skins/default/xui/en/panel_facebook_status.xml
index 54cfa3f52486bad7e8e0a05e84a9c4edd10a0f07..480abec55873ac2353ad1abbf2d10bb52356879a 100644
--- a/indra/newview/skins/default/xui/en/panel_social_status.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_status.xml
@@ -1,8 +1,9 @@
     <panel
 	 height="400"
 	 width="304"
+     follows="all"
 	 layout="topleft"
-     name="panel_social_status">
+     name="panel_facebook_status">
      <layout_stack
       layout="topleft"
       border_size="0"
@@ -26,7 +27,7 @@
         What's on your mind?
        </text>
        <text_editor
-        follows="left|top"
+        follows="left|top|right"
         height="150"
         width="250"
         left="9"
@@ -41,7 +42,7 @@
        name="status_button_panel"
        height="25">
        <button
-        follows="left|top"
+        follows="left|bottom"
         top="0"
         left="9"
         height="23"
@@ -52,7 +53,7 @@
           function="SocialSharing.SendStatus" />
        </button>
        <button
-        follows="left|top"
+        follows="left|bottom"
         height="23"
         label="Cancel"
         name="cancel_status_btn"
diff --git a/indra/newview/skins/default/xui/en/panel_flickr_account.xml b/indra/newview/skins/default/xui/en/panel_flickr_account.xml
new file mode 100644
index 0000000000000000000000000000000000000000..506d2e2f749701af6f5c578f4f687cc987a95347
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_flickr_account.xml
@@ -0,0 +1,75 @@
+<panel
+	 height="540"
+	 width="304"
+	 layout="topleft"
+   name="panel_flickr_account">
+  <string
+      name="flickr_connected"
+      value="You are connected to Flickr as:" />
+  <string
+      name="flickr_disconnected"
+      value="Not connected to Flickr" />
+  <text
+   layout="topleft"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_caption_label"
+   top="21"
+   type="string">
+    Not connected to Flickr.
+  </text>
+  <text
+   layout="topleft"
+   top_pad="2"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_name_label"
+   parse_urls="true"
+   type="string"/>
+  <panel
+    layout="topleft"
+    name="panel_buttons"
+    height="345"
+    left="9">
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_pad="9"
+     visible="true"
+     height="23"
+     label="Connect..."
+     name="connect_btn"
+     width="210">
+      <commit_callback function="SocialSharing.Connect"/>
+    </button>
+
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_delta="0"
+     height="23"
+     label="Disconnect"
+     name="disconnect_btn"
+     width="210"
+     visible="false">
+      <commit_callback function="SocialSharing.Disconnect"/>
+    </button>
+    <text
+      layout="topleft"
+      length="1"
+      follows="top|left"
+      height="16"
+      left="0"
+      name="account_learn_more_label"
+      top_pad="20"
+      type="string">
+      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Flickr/ta-p/2435609 Learn about posting to Flickr]
+    </text>
+  </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8d8ef45c0d48cb7554464b0b2263507f31a72396
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
@@ -0,0 +1,245 @@
+    <panel
+      height="540"
+      width="304"
+      layout="topleft"
+      name="panel_flickr_photo">
+      <layout_stack
+	   layout="topleft"
+       border_size="0"
+       height="532"
+       follows="all"
+       orientation="vertical"
+       name="stack_photo"
+       top="8">
+        <layout_panel	
+         name="snapshot_panel"
+         height="507">
+            <combo_box
+             control_name="FlickrPhotoResolution"
+             follows="left|top"
+             top="6"
+             left="9"
+             name="resolution_combobox"
+             tool_tip="Image resolution"
+             height="21"
+             width="135">
+              <combo_box.item
+               label="Current Window"
+               name="CurrentWindow"
+               value="[i0,i0]" />
+              <combo_box.item
+               label="640x480"
+               name="640x480"
+               value="[i640,i480]" />
+              <combo_box.item
+               label="800x600"
+               name="800x600"
+               value="[i800,i600]" />
+              <combo_box.item
+               label="1024x768"
+               name="1024x768"
+               value="[i1024,i768]" />
+            </combo_box>
+            <combo_box
+               control_name="FlickrPhotoFilters"
+               follows="right|top"
+               name="filters_combobox"
+               tool_tip="Image filters"
+               top="6"
+               left="165"
+               height="21"
+               width="135">
+                <combo_box.item
+                 label="No Filter"
+                 name="NoFilter"
+                 value="NoFilter" />
+            </combo_box>
+            <panel
+                height="150"
+                width="250"
+                visible="true"
+                name="thumbnail_placeholder"
+                top="33"
+                follows="left|top"
+                left="9">
+            </panel>
+            <button
+             follows="left|top"
+             height="23"
+             label="Refresh"
+             left="9"
+             top_pad="5"
+             name="new_snapshot_btn"
+             tool_tip="Click to refresh"
+             visible="true"
+             width="100" >
+             <button.commit_callback
+               function="SocialSharing.RefreshPhoto" />
+            </button>
+            <text
+                follows="left|top"
+                font="SansSerif"
+                text_color="EmphasisColor"
+                height="14"
+                top_pad="-19"
+                left_pad="-30"
+                length="1"
+                halign="center"
+                name="working_lbl"
+                translate="false"
+                type="string"
+                visible="true"
+                width="150">
+                Refreshing...
+            </text>
+            <button
+                follows="right|top"
+                height="23"
+                label="Preview"
+                left="200"
+                top_pad="-19"
+                name="big_preview_btn"
+                tool_tip="Click to toggle preview"
+                is_toggle="true"
+                visible="true"
+                width="100" >
+                <button.commit_callback
+                function="SocialSharing.BigPreview" />
+            </button>
+            <text
+             length="1"
+             follows="top|left|right"
+             font="SansSerif"
+             height="16"
+             left="9"
+             name="title_label"
+             top_pad="15"
+             type="string">
+              Title:
+            </text>
+            <line_editor
+             follows="left|top"
+             height="20"
+             width="250"
+             left="9"
+             length="1"
+             max_length="256"
+             name="photo_title"
+             type="string">
+            </line_editor>
+            <text
+             length="1"
+             follows="top|left|right"
+             font="SansSerif"
+             height="16"
+             left="9"
+             name="description_label"
+             top_pad="10"
+             type="string">
+              Description:
+            </text>
+            <text_editor
+             follows="left|top"
+             height="50"
+             width="250"
+             left="9"
+             length="1"
+             max_length="700"
+             name="photo_description"
+             type="string"
+             word_wrap="true">
+            </text_editor>
+            <check_box
+             follows="left|top"
+             initial_value="true"
+             label="Include SL location at end of description"
+             name="add_location_cb"
+              left="9"
+              height="16"
+             top_pad="8"/>
+            <text
+             length="1"
+             follows="top|left|right"
+             font="SansSerif"
+             height="16"
+             left="9"
+             name="tags_label"
+             top_pad="10"
+             type="string">
+              Tags:
+            </text>
+            <text
+              length="1"
+              follows="top|left"
+              font="SansSerifSmall"
+              text_color="White_50"
+              height="30"
+              name="tags_help_label"
+              left="50"
+              top_pad="-16"
+              type="string">
+Separate tags with spaces
+Use "" for multi-word tags
+            </text>
+            <text_editor
+             follows="left|top"
+             height="50"
+             width="250"
+             left="9"
+             length="1"
+             max_length="700"
+             name="photo_tags"
+             type="string"
+             word_wrap="true">
+            </text_editor>
+            <combo_box
+             control_name="FlickrPhotoRating"
+             follows="left|top"
+             top_pad="16"
+             left="9"
+             name="rating_combobox"
+             tool_tip="Flickr content rating"
+             height="21"
+             width="250">
+              <combo_box.item
+               label="Safe Flickr rating"
+               name="SafeRating"
+               value="1" />
+              <combo_box.item
+               label="Moderate Flickr rating"
+               name="ModerateRating"
+               value="2" />
+              <combo_box.item
+               label="Restricted Flickr rating"
+               name="RestrictedRating"
+               value="3" />
+            </combo_box>
+        </layout_panel>
+        <layout_panel
+          name="photo_button_panel"
+          height="25">
+          <button
+           follows="left|top"
+           top="0"
+           left="9"
+           height="23"
+           label="Upload"
+           name="post_photo_btn"
+           width="100">
+            <button.commit_callback
+             function="SocialSharing.SendPhoto" />
+          </button>
+          <button
+               follows="left|top"
+               height="23"
+               label="Cancel"
+               name="cancel_photo_btn"
+               left_pad="15"
+               top_delta="0"
+               width="100">
+            <button.commit_callback
+             function="SocialSharing.Cancel" />
+          </button>          
+        </layout_panel>        
+      </layout_stack>
+    </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
index 61c8c971c28766cb8968175ba418f039f904acef..eff60f8228bcaaaa7026ead068999cddb0b1a7cd 100755
--- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
@@ -81,4 +81,40 @@
     <button.commit_callback
      function="Snapshot.SaveToComputer" />
   </button>
+  <text
+    font="SansSerif"
+    layout="topleft"
+    length="1"
+    follows="top|left"
+    height="16"
+    left="10"
+    name="send_to_facebook_textbox"
+    top_pad="10"
+    type="string">
+    Send to:  [secondlife:/// Facebook]
+  </text>
+  <text
+    font="SansSerif"
+    layout="topleft"
+    length="1"
+    follows="top|left"
+    height="16"
+    left="140"
+    name="send_to_twitter_textbox"
+    top_pad="-16"
+    type="string">
+    [secondlife:/// Twitter]
+  </text>
+  <text
+    font="SansSerif"
+    layout="topleft"
+    length="1"
+    follows="top|left"
+    height="16"
+    left="190"
+    name="send_to_flickr_textbox"
+    top_pad="-16"
+    type="string">
+    [secondlife:/// Flickr]
+  </text>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_twitter_account.xml b/indra/newview/skins/default/xui/en/panel_twitter_account.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ee4f6396e1068cfdb24336385bda4439b165820f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_twitter_account.xml
@@ -0,0 +1,75 @@
+<panel
+	 height="400"
+	 width="304"
+	 layout="topleft"
+   name="panel_twitter_account">
+  <string
+      name="twitter_connected"
+      value="You are connected to Twitter as:" />
+  <string
+      name="twitter_disconnected"
+      value="Not connected to Twitter" />
+  <text
+   layout="topleft"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_caption_label"
+   top="21"
+   type="string">
+    Not connected to Twitter.
+  </text>
+  <text
+   layout="topleft"
+   top_pad="2"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_name_label"
+   parse_urls="true"
+   type="string"/>
+  <panel
+    layout="topleft"
+    name="panel_buttons"
+    height="345"
+    left="9">
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_pad="9"
+     visible="true"
+     height="23"
+     label="Connect..."
+     name="connect_btn"
+     width="210">
+      <commit_callback function="SocialSharing.Connect"/>
+    </button>
+
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_delta="0"
+     height="23"
+     label="Disconnect"
+     name="disconnect_btn"
+     width="210"
+     visible="false">
+      <commit_callback function="SocialSharing.Disconnect"/>
+    </button>
+    <text
+      layout="topleft"
+      length="1"
+      follows="top|left"
+      height="16"
+      left="0"
+      name="account_learn_more_label"
+      top_pad="20"
+      type="string">
+      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Twitter/ta-p/2435453 Learn about posting to Twitter]
+    </text>
+  </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_twitter_photo.xml b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c2be56da2174e3cd32de376d844b583c370db709
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml
@@ -0,0 +1,193 @@
+    <panel
+      height="420"
+      width="304"
+      layout="topleft"
+      name="panel_twitter_photo">
+      <layout_stack
+	   layout="topleft"
+       border_size="0"
+       height="412"
+       follows="all"
+       orientation="vertical"
+       name="stack_photo"
+       top="8">
+        <layout_panel
+         name="text_panel"
+         height="160">
+          <text
+           length="1"
+           follows="top|left|right"
+           font="SansSerif"
+           height="16"
+           left="9"
+           name="status_label"
+           top="3"
+           type="string">
+            What's happening?
+          </text>
+          <text
+           length="1"
+           follows="top|left"
+           font="SansSerif"
+           text_color="EmphasisColor"
+           halign="right"
+           height="16"
+           width="30"
+           left="227"
+           name="status_counter_label"
+           top="3"
+           type="string">
+            140
+          </text>
+          <text_editor
+           follows="left|top"
+           height="87"
+           width="250"
+           left="9"
+           length="1"
+           max_length="140"
+           name="photo_status"
+           type="string"
+           word_wrap="true">
+          </text_editor>
+          <check_box
+           follows="left|top"
+           initial_value="true"
+           label="Include SL location"
+           name="add_location_cb"
+            left="9"
+            height="16"
+           top_pad="10"/>
+          <check_box
+           follows="left|top"
+           initial_value="true"
+           label="Include a photo"
+           name="add_photo_cb"
+            left="9"
+            height="16"
+           top_pad="10"/>
+        </layout_panel>
+          <layout_panel
+           name="snapshot_panel"
+           height="227">
+            <combo_box
+             control_name="TwitterPhotoResolution"
+             follows="left|top"
+             top="6"
+             left="9"
+             name="resolution_combobox"
+             tool_tip="Image resolution"
+             height="21"
+             width="135">
+              <combo_box.item
+               label="Current Window"
+               name="CurrentWindow"
+               value="[i0,i0]" />
+              <combo_box.item
+               label="640x480"
+               name="640x480"
+               value="[i640,i480]" />
+              <combo_box.item
+               label="800x600"
+               name="800x600"
+               value="[i800,i600]" />
+              <combo_box.item
+               label="1024x768"
+               name="1024x768"
+               value="[i1024,i768]" />
+            </combo_box>
+              <combo_box
+                  control_name="TwitterPhotoFilters"
+                  follows="right|top"
+                  name="filters_combobox"
+                  tool_tip="Image filters"
+                  top="6"
+                  left="165"
+                  height="21"
+                  width="135">
+                  <combo_box.item
+                  label="No Filter"
+                  name="NoFilter"
+                  value="NoFilter" />
+              </combo_box>
+            <panel
+                height="150"
+                width="250"
+                visible="true"
+                name="thumbnail_placeholder"
+                top="33"
+                follows="left|top"
+                left="9">
+            </panel>
+            <button
+             follows="left|top"
+             height="23"
+             label="Refresh"
+             left="9"
+             top_pad="5"
+             name="new_snapshot_btn"
+             tool_tip="Click to refresh"
+             visible="true"
+             width="100" >
+             <button.commit_callback
+               function="SocialSharing.RefreshPhoto" />
+            </button>
+            <text
+                follows="left|top"
+                font="SansSerif"
+                text_color="EmphasisColor"
+                height="14"
+                top_pad="-19"
+                left_pad="-30"
+                length="1"
+                halign="center"
+                name="working_lbl"
+                translate="false"
+                type="string"
+                visible="true"
+                width="150">
+                Refreshing...
+            </text>
+              <button
+                  follows="right|top"
+                  height="23"
+                  label="Preview"
+                  left="200"
+                  top_pad="-19"
+                  name="big_preview_btn"
+                  tool_tip="Click to toggle preview"
+                  is_toggle="true"
+                  visible="true"
+                  width="100" >
+                  <button.commit_callback
+                  function="SocialSharing.BigPreview" />
+              </button>
+        </layout_panel>
+        <layout_panel
+          name="photo_button_panel"
+          height="25">
+          <button
+           follows="left|top"
+           top="0"
+           left="9"
+           height="23"
+           label="Tweet"
+           name="post_photo_btn"
+           width="100">
+            <button.commit_callback
+             function="SocialSharing.SendPhoto" />
+          </button>
+          <button
+               follows="left|top"
+               height="23"
+               label="Cancel"
+               name="cancel_photo_btn"
+               left_pad="15"
+               top_delta="0"
+               width="100">
+            <button.commit_callback
+             function="SocialSharing.Cancel" />
+          </button>          
+        </layout_panel>        
+      </layout_stack>
+    </panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 0848762e22aae090d583045d7c857d2369e80873..7bbe7cc798af2797af96ee8beeda1d46b1865ee8 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -184,15 +184,40 @@ Please try logging in again in a minute.</string>
 	<string name="SentToInvalidRegion">You were sent to an invalid region.</string>
 	<string name="TestingDisconnect">Testing viewer disconnect</string>
 
-	<!-- Facebook Connect and, eventually, other Social Network -->
-	<string name="SocialFacebookConnecting">Connecting to Facebook...</string>
-	<string name="SocialFacebookPosting">Posting...</string>
-	<string name="SocialFacebookDisconnecting">Disconnecting from Facebook...</string>
-	<string name="SocialFacebookErrorConnecting">Problem connecting to Facebook</string>
-	<string name="SocialFacebookErrorPosting">Problem posting to Facebook</string>
-	<string name="SocialFacebookErrorDisconnecting">Problem disconnecting from Facebook</string>
+	<!-- SLShare: Facebook, Flickr, and Twitter -->
+  <string name="SocialFacebookConnecting">Connecting to Facebook...</string>
+  <string name="SocialFacebookPosting">Posting...</string>
+  <string name="SocialFacebookDisconnecting">Disconnecting from Facebook...</string>
+  <string name="SocialFacebookErrorConnecting">Problem connecting to Facebook</string>
+  <string name="SocialFacebookErrorPosting">Problem posting to Facebook</string>
+  <string name="SocialFacebookErrorDisconnecting">Problem disconnecting from Facebook</string>
+  <string name="SocialFlickrConnecting">Connecting to Flickr...</string>
+  <string name="SocialFlickrPosting">Posting...</string>
+  <string name="SocialFlickrDisconnecting">Disconnecting from Flickr...</string>
+  <string name="SocialFlickrErrorConnecting">Problem connecting to Flickr</string>
+  <string name="SocialFlickrErrorPosting">Problem posting to Flickr</string>
+  <string name="SocialFlickrErrorDisconnecting">Problem disconnecting from Flickr</string>
+  <string name="SocialTwitterConnecting">Connecting to Twitter...</string>
+  <string name="SocialTwitterPosting">Posting...</string>
+  <string name="SocialTwitterDisconnecting">Disconnecting from Twitter...</string>
+  <string name="SocialTwitterErrorConnecting">Problem connecting to Twitter</string>
+  <string name="SocialTwitterErrorPosting">Problem posting to Twitter</string>
+  <string name="SocialTwitterErrorDisconnecting">Problem disconnecting from Twitter</string>
     
-	<!-- Tooltip -->
+	<!-- SLShare: User Friendly Filter Names Translation -->
+    <string name="BlackAndWhite">Black &amp; White</string>
+    <string name="Colors1970">1970&apos;s Colors</string>
+    <string name="Intense">Intense</string>
+    <string name="Newspaper">Newsprint</string>
+    <string name="Sepia">Sepia</string>
+    <string name="Spotlight">Spotlight</string>
+    <string name="Video">Video</string>
+    <string name="Autocontrast">Autocontrast</string>
+    <string name="LensFlare">Lens Flare</string>
+    <string name="Miniature">Miniature</string>
+    <string name="Toycamera">Toy Camera</string>
+	
+    <!-- Tooltip -->
 	<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar -->
 	<string name="TooltipNoName">(no name)</string> <!-- No name on an object -->
 	<string name="TooltipOwner">Owner:</string> <!-- Owner name follows -->
@@ -3491,6 +3516,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
   <string name="facebook_post_success">
     You posted to Facebook.
   </string>
+  <string name="flickr_post_success">
+    You posted to Flickr.
+  </string>
+  <string name="twitter_post_success">
+    You posted to Twitter.
+  </string>
 
   <string name="no_session_message">
     (IM Session Doesn't Exist)
@@ -3909,6 +3940,8 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_Conversations_Label">Conversations</string>
   <string name="Command_Compass_Label">Compass</string>
   <string name="Command_Destinations_Label">Destinations</string>
+  <string name="Command_Facebook_Label">Facebook</string>
+  <string name="Command_Flickr_Label">Flickr</string>
   <string name="Command_Gestures_Label">Gestures</string>
   <string name="Command_HowTo_Label">How to</string>
   <string name="Command_Inventory_Label">Inventory</string>
@@ -3924,8 +3957,8 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_Profile_Label">Profile</string>
   <string name="Command_Search_Label">Search</string>
   <string name="Command_Snapshot_Label">Snapshot</string>
-  <string name="Command_Social_Label">Facebook</string>
   <string name="Command_Speak_Label">Speak</string>
+  <string name="Command_Twitter_Label">Twitter</string>
   <string name="Command_View_Label">Camera controls</string>
   <string name="Command_Voice_Label">Voice settings</string>
 
@@ -3937,6 +3970,8 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_Conversations_Tooltip">Converse with everyone</string>
   <string name="Command_Compass_Tooltip">Compass</string>
   <string name="Command_Destinations_Tooltip">Destinations of interest</string>
+  <string name="Command_Facebook_Tooltip">Post to Facebook</string>
+  <string name="Command_Flickr_Tooltip">Upload to Flickr</string>
   <string name="Command_Gestures_Tooltip">Gestures for your avatar</string>
   <string name="Command_HowTo_Tooltip">How to do common tasks</string>
   <string name="Command_Inventory_Tooltip">View and use your belongings</string>
@@ -3952,8 +3987,8 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_Profile_Tooltip">Edit or view your profile</string>
   <string name="Command_Search_Tooltip">Find places, events, people</string>
   <string name="Command_Snapshot_Tooltip">Take a picture</string>
-  <string name="Command_Social_Tooltip">Post to Facebook</string>
   <string name="Command_Speak_Tooltip">Speak with people nearby using your microphone</string>
+  <string name="Command_Twitter_Tooltip">Twitter</string>
   <string name="Command_View_Tooltip">Changing camera angle</string>
   <string name="Command_Voice_Tooltip">Volume controls for calls and people near you in world</string>
 
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index f7b3a45e8da33d9ef137cec77bf616d5060ebc26..f079f31c81b0c20e674123faa6ec086848c96b95 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -98,6 +98,9 @@ def construct(self):
                 # ... and the entire windlight directory
                 self.path("windlight")
 
+                # ... and the entire image filters directory
+                self.path("filters")
+            
                 # ... and the included spell checking dictionaries
                 pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
                 if self.prefix(src=pkgdir,dst=""):