summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/android
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/android')
-rw-r--r--WebCore/platform/graphics/android/AffineTransformAndroid.cpp168
-rw-r--r--WebCore/platform/graphics/android/FontAndroid.cpp150
-rw-r--r--WebCore/platform/graphics/android/FontCacheAndroid.cpp156
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.cpp68
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.h47
-rw-r--r--WebCore/platform/graphics/android/FontDataAndroid.cpp121
-rw-r--r--WebCore/platform/graphics/android/FontPlatformData.h104
-rw-r--r--WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp151
-rw-r--r--WebCore/platform/graphics/android/GlyphMapAndroid.cpp69
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp1114
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp254
-rw-r--r--WebCore/platform/graphics/android/ImageBufferAndroid.cpp53
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp336
-rw-r--r--WebCore/platform/graphics/android/PathAndroid.cpp231
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphics.h25
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.cpp73
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.h108
-rw-r--r--WebCore/platform/graphics/android/SkBitmapRef.h54
-rw-r--r--WebCore/platform/graphics/android/android_graphics.cpp223
-rw-r--r--WebCore/platform/graphics/android/android_graphics.h80
20 files changed, 3585 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
new file mode 100644
index 0000000..d00aa40
--- /dev/null
+++ b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
@@ -0,0 +1,168 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "AffineTransform.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include "android_graphics.h"
+
+namespace WebCore {
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+AffineTransform::AffineTransform()
+{
+ m_transform.reset();
+}
+
+AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform.reset();
+
+ m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
+
+ m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
+}
+
+void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
+
+ m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
+}
+
+void AffineTransform::map(double x, double y, double *x2, double *y2) const
+{
+ SkPoint src, dst;
+ src.set(SkDoubleToScalar(x), SkDoubleToScalar(y));
+ m_transform.mapPoints(&dst, &src, 1);
+
+ *x2 = SkScalarToDouble(dst.fX);
+ *y2 = SkScalarToDouble(dst.fY);
+}
+
+IntRect AffineTransform::mapRect(const IntRect &rect) const
+{
+ SkRect src, dst;
+ SkIRect ir;
+
+ android_setrect(&src, rect);
+ m_transform.mapRect(&dst, src);
+ dst.round(&ir);
+
+ return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+{
+ SkRect src, dst;
+ SkIRect ir;
+
+ android_setrect(&src, rect);
+ m_transform.mapRect(&dst, src);
+ dst.round(&ir);
+
+ return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+}
+
+bool AffineTransform::isIdentity() const
+{
+ return m_transform.isIdentity();
+}
+
+void AffineTransform::reset()
+{
+ m_transform.reset();
+}
+
+AffineTransform &AffineTransform::scale(double sx, double sy)
+{
+ m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
+ return *this;
+}
+
+AffineTransform &AffineTransform::rotate(double d)
+{
+ m_transform.preRotate(SkDoubleToScalar(d));
+ return *this;
+}
+
+AffineTransform &AffineTransform::translate(double tx, double ty)
+{
+ m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty));
+ return *this;
+}
+
+AffineTransform &AffineTransform::shear(double sx, double sy)
+{
+ m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
+ return *this;
+}
+
+double AffineTransform::det() const
+{
+ return SkScalarToDouble(m_transform[SkMatrix::kMScaleX]) * SkScalarToDouble(m_transform[SkMatrix::kMScaleY]) -
+ SkScalarToDouble(m_transform[SkMatrix::kMSkewX]) * SkScalarToDouble(m_transform[SkMatrix::kMSkewY]);
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ AffineTransform inverse;
+
+ m_transform.invert(&inverse.m_transform);
+
+ return inverse;
+}
+
+AffineTransform::operator SkMatrix() const
+{
+ return m_transform;
+}
+
+bool AffineTransform::operator==(const AffineTransform &m2) const
+{
+ return m_transform == m2.m_transform;
+}
+
+AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+{
+ // is this the correct order???
+ m_transform.setConcat(m_transform, m2.m_transform);
+ return *this;
+}
+
+AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+{
+ AffineTransform cat;
+
+ // is this the correct order???
+ cat.m_transform.setConcat(m_transform, m2.m_transform);
+ return cat;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp
new file mode 100644
index 0000000..340d1c1
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FontData.h"
+#include "FontFallbackList.h"
+#include "GraphicsContext.h"
+#include "GlyphBuffer.h"
+#include "PlatformGraphicsContext.h"
+#include "IntRect.h"
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkTemplates.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
+ const FloatPoint& point) const {
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ SkPaint paint;
+
+ font->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->fillColor().rgb());
+
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+
+ const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
+ SkScalar x = SkFloatToScalar(point.x());
+ SkScalar y = SkFloatToScalar(point.y());
+
+ if (glyphBuffer.hasAdjustedWidths()) {
+ const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
+ SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
+ SkPoint* pos = storage.get();
+
+ for (int i = 0; i < numGlyphs; i++) {
+ pos[i].set(x, y);
+ x += SkFloatToScalar(adv[i].width());
+ y += SkFloatToScalar(adv[i].height());
+ }
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ } else {
+ canvas->drawText(glyphs, numGlyphs << 1, x, y, paint);
+ }
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int, int) const
+{
+ SkPaint paint;
+ SkScalar width, left;
+ SkPaint::FontMetrics metrics;
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+ width = paint.measureText(run.characters(), run.length() << 1);
+ SkScalar spacing = paint.getFontMetrics(&metrics);
+
+ return FloatRect(point.x(),
+ point.y() - floorf(SkScalarToFloat(-metrics.fAscent)),
+ roundf(SkScalarToFloat(width)),
+ roundf(SkScalarToFloat(spacing)));
+}
+
+void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, FloatPoint const& point, int, int) const
+{
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ SkPaint paint;
+
+ primaryFont()->platformData().setupPaint(&paint);
+ paint.setColor(gc->fillColor().rgb());
+
+#if 0
+ int n = run.to() - run.from();
+printf("------------- complex draw %d chars", n);
+ for (int i = 0; i < n; i++)
+ printf(" %04X", run.data(run.from())[i]);
+ printf("\n");
+#endif
+
+ canvas->drawText(run.characters(), run.length() << 1,
+ SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
+ paint);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ SkPaint paint;
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+//printf("--------- complext measure %d chars\n", run.to() - run.from());
+
+ SkScalar width = paint.measureText(run.characters(), run.length() << 1);
+ return SkScalarToFloat(width);
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ SkPaint paint;
+ int count = run.length();
+ SkAutoSTMalloc<64, SkScalar> storage(count);
+ SkScalar* widths = storage.get();
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+ count = paint.getTextWidths(run.characters(), count << 1, widths);
+
+ if (count > 0)
+ {
+ SkScalar pos = 0;
+ for (int i = 0; i < count; i++)
+ {
+ if (x < SkScalarRound(pos + SkScalarHalf(widths[i])))
+ return i;
+ pos += widths[i];
+ }
+ }
+ return count;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
new file mode 100644
index 0000000..903159e
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+#include "FontPlatformData.h"
+#include "Font.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ return font.primaryFont(); // do I need to make a copy (i.e. does the caller delete what I return?
+
+#if 0
+ // IMLangFontLink::MapFont Method does what we want.
+ IMLangFontLink2* langFontLink = getFontLinkInterface();
+ if (!langFontLink)
+ return 0;
+
+ FontData* fontData = 0;
+ HDC hdc = GetDC(0);
+ DWORD fontCodePages;
+ langFontLink->GetFontCodePages(hdc, font.primaryFont()->m_font.hfont(), &fontCodePages);
+
+ DWORD actualCodePages;
+ long cchActual;
+ langFontLink->GetStrCodePages(characters, length, fontCodePages, &actualCodePages, &cchActual);
+ if (cchActual) {
+ HFONT result;
+ if (langFontLink->MapFont(hdc, actualCodePages, characters[0], &result) == S_OK) {
+ fontData = new FontData(FontPlatformData(result, font.fontDescription().computedPixelSize()));
+ fontData->setIsMLangFont();
+ }
+ }
+
+ ReleaseDC(0, hdc);
+ return fontData;
+#endif
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& font)
+{
+ static AtomicString str("sans-serif");
+ return getCachedFontPlatformData(font, str);
+}
+
+static char* AtomicStringToUTF8String(const AtomicString& utf16)
+{
+ SkASSERT(sizeof(uint16_t) == sizeof(utf16.characters()[0]));
+ const uint16_t* uni = (uint16_t*)utf16.characters();
+
+ size_t bytes = SkUTF16_ToUTF8(uni, utf16.length(), NULL);
+ char* utf8 = (char*)sk_malloc_throw(bytes + 1);
+
+ (void)SkUTF16_ToUTF8(uni, utf16.length(), utf8);
+ utf8[bytes] = 0;
+ return utf8;
+}
+
+bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+{
+ ASSERT(0); // FIXME HACK unimplemented
+ return false;
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ char* storage = 0;
+ const char* name = 0;
+
+ if (family.length() == 0) {
+ static const struct {
+ FontDescription::GenericFamilyType mType;
+ const char* mName;
+ } gNames[] = {
+ { FontDescription::SerifFamily, "serif" },
+ { FontDescription::SansSerifFamily, "sans-serif" },
+ { FontDescription::MonospaceFamily, "monospace" },
+ { FontDescription::CursiveFamily, "cursive" },
+ { FontDescription::FantasyFamily, "fantasy" }
+ };
+
+ FontDescription::GenericFamilyType type = fontDescription.genericFamily();
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gNames); i++)
+ {
+ if (type == gNames[i].mType)
+ {
+ name = gNames[i].mName;
+ break;
+ }
+ }
+ // if we fall out of the loop, its ok for name to still be 0
+ }
+ else { // convert the name to utf8
+ storage = AtomicStringToUTF8String(family);
+ name = storage;
+ }
+
+ int style = SkTypeface::kNormal;
+ if (fontDescription.weight() >= cBoldWeight)
+ style |= SkTypeface::kBold;
+ if (fontDescription.italic())
+ style |= SkTypeface::kItalic;
+
+ SkTypeface* tf = SkTypeface::Create(name, (SkTypeface::Style)style);
+
+ FontPlatformData* result = new FontPlatformData(tf,
+ fontDescription.computedSize(),
+ (style & SkTypeface::kBold) && !tf->isBold(),
+ (style & SkTypeface::kItalic) && !tf->isItalic());
+ tf->unref();
+ sk_free(storage);
+ return result;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..eea5e36
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SkTypeface.h"
+#include "SkStream.h"
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::FontCustomPlatformData(SkTypeface* face)
+{
+ face->safeRef();
+ m_typeface = face;
+}
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ m_typeface->safeUnref();
+ // the unref is enough to release the font data...
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+{
+ // turn bold/italic into fakeBold/fakeItalic
+ if (m_typeface != NULL) {
+ if (m_typeface->isBold() == bold)
+ bold = false;
+ if (m_typeface->isItalic() == italic)
+ italic = false;
+ }
+ return FontPlatformData(m_typeface, size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ // pass true until we know how we can share the data, and not have to
+ // make a copy of it.
+ SkStream* stream = new SkMemoryStream(buffer->data(), buffer->size(), true);
+ SkTypeface* face = SkTypeface::CreateFromStream(stream);
+ if (NULL == face) {
+ SkDebugf("--------- SkTypeface::CreateFromBuffer failed %d\n",
+ buffer->size());
+ return NULL;
+ }
+
+ SkAutoUnref aur(face);
+
+ return new FontCustomPlatformData(face);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.h b/WebCore/platform/graphics/android/FontCustomPlatformData.h
new file mode 100644
index 0000000..f072b6f
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FontCustomPlatformData_h_
+#define FontCustomPlatformData_h_
+
+#include <wtf/Noncopyable.h>
+
+class SkTypeface;
+
+namespace WebCore {
+
+ class SharedBuffer;
+ class FontPlatformData;
+
+ class FontCustomPlatformData : Noncopyable {
+ public:
+ FontCustomPlatformData(SkTypeface* face);
+ ~FontCustomPlatformData();
+
+ SkTypeface* typeface() const { return m_typeface; }
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+
+ private:
+ SkTypeface* m_typeface;
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+} // namespace WebCore
+
+#endif // FontCustomPlatformData_h_
+
diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp
new file mode 100644
index 0000000..a90f536
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "SimpleFontData.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkTime.h"
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+
+ m_font.setupPaint(&paint);
+ (void)paint.getFontMetrics(&metrics);
+
+ // use ceil instead of round to favor descent, given a lot of accidental
+ // clipping of descenders (e.g. 14pt 'g') in textedit fields
+ int d = SkScalarCeil(metrics.fDescent);
+ int s = SkScalarRound(metrics.fDescent - metrics.fAscent);
+ int a = s - d;
+
+ m_ascent = a;
+ m_descent = d;
+ m_xHeight = SkScalarToFloat(-metrics.fAscent) * 0.56f; // hack I stole from the window's port
+ m_lineSpacing = a + d;
+ m_lineGap = SkScalarRound(metrics.fLeading);
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, fontDescription.computedSize() * 0.7f));
+ }
+ return m_smallCapsFontData;
+}
+
+#define kMaxBufferCount 64
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ SkPaint paint;
+ uint16_t glyphs[kMaxBufferCount];
+
+ m_font.setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ while (length > 0) {
+ int n = SkMin32(length, SK_ARRAY_COUNT(glyphs));
+
+ int count = paint.textToGlyphs(characters, n << 1, glyphs);
+ for (int i = 0; i < count; i++) {
+ if (0 == glyphs[i]) {
+ return false; // missing glyph
+ }
+ }
+
+ characters += n;
+ length -= n;
+ }
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = false;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ SkASSERT(sizeof(glyph) == 2); // compile-time assert
+
+ SkPaint paint;
+
+ m_font.setupPaint(&paint);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ SkScalar width = paint.measureText(&glyph, 2);
+
+ return SkScalarToFloat(width);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h
new file mode 100644
index 0000000..d6933d9
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontPlatformData.h
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef FontPlatformData_H
+#define FontPlatformData_H
+
+class SkPaint;
+class SkTypeface;
+
+namespace WebCore {
+
+class FontPlatformData
+{
+public:
+ static FontPlatformData Deleted()
+ {
+ return FontPlatformData(NULL, -1, false, false);
+ }
+
+ FontPlatformData();
+ FontPlatformData(const FontPlatformData&);
+ FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
+ FontPlatformData(const FontPlatformData& src, float textSize);
+ ~FontPlatformData();
+
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool operator==(const FontPlatformData& a) const;
+
+ void setupPaint(SkPaint*) const;
+ unsigned hash() const;
+
+private:
+ SkTypeface* mTypeface;
+ float mTextSize;
+ bool mFakeBold;
+ bool mFakeItalic;
+};
+
+#if 0 // windows port
+class FontPlatformData
+{
+public:
+ class Deleted {};
+
+ // Used for deleted values in the font cache's hash tables.
+ FontPlatformData(Deleted)
+ : m_font((HFONT)-1), m_fontFace(0), m_scaledFont(0), m_size(0)
+ {}
+
+ FontPlatformData()
+ : m_font(0), m_fontFace(0), m_scaledFont(0), m_size(0)
+ {}
+
+ FontPlatformData(HFONT, int size);
+ ~FontPlatformData();
+
+ HFONT hfont() const { return m_font; }
+ cairo_font_face_t* fontFace() const { return m_fontFace; }
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+
+ int size() const { return m_size; }
+
+ unsigned hash() const
+ {
+ return StringImpl::computeHash((UChar*)(&m_font), sizeof(HFONT) / sizeof(UChar));
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font && m_fontFace == other.m_fontFace &&
+ m_scaledFont == other.m_scaledFont && m_size == other.m_size;
+ }
+
+private:
+ HFONT m_font;
+ cairo_font_face_t* m_fontFace;
+ cairo_scaled_font_t* m_scaledFont;
+ int m_size;
+};
+#endif
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
new file mode 100644
index 0000000..4b4186a
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+
+//#define TRACE_FONTPLATFORMDATA_LIFE
+//#define COUNT_FONTPLATFORMDATA_LIFE
+
+#ifdef COUNT_FONTPLATFORMDATA_LIFE
+static int gCount;
+static int gMaxCount;
+
+static void inc_count()
+{
+ if (++gCount > gMaxCount)
+ {
+ gMaxCount = gCount;
+ SkDebugf("---------- FontPlatformData %d\n", gMaxCount);
+ }
+}
+
+static void dec_count() { --gCount; }
+#else
+ #define inc_count()
+ #define dec_count()
+#endif
+
+#ifdef TRACE_FONTPLATFORMDATA_LIFE
+ #define trace(num) SkDebugf("FontPlatformData%d %p %g %d %d\n", num, mTypeface, mTextSize, mFakeBold, mFakeItalic)
+#else
+ #define trace(num)
+#endif
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData()
+ : mTypeface(NULL), mTextSize(0), mFakeBold(false), mFakeItalic(false)
+{
+ inc_count();
+ trace(1);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src)
+{
+ src.mTypeface->safeRef();
+ mTypeface = src.mTypeface;
+
+ mTextSize = src.mTextSize;
+ mFakeBold = src.mFakeBold;
+ mFakeItalic = src.mFakeItalic;
+
+ inc_count();
+ trace(2);
+}
+
+FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic)
+ : mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic)
+{
+ mTypeface->safeRef();
+
+ inc_count();
+ trace(3);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
+ : mTypeface(src.mTypeface), mTextSize(textSize), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic)
+{
+ mTypeface->safeRef();
+
+ inc_count();
+ trace(4);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ dec_count();
+#ifdef TRACE_FONTPLATFORMDATA_LIFE
+ SkDebugf("----------- ~FontPlatformData\n");
+#endif
+
+ mTypeface->safeUnref();
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
+{
+ SkRefCnt_SafeAssign(mTypeface, src.mTypeface);
+
+ mTextSize = src.mTextSize;
+ mFakeBold = src.mFakeBold;
+ mFakeItalic = src.mFakeItalic;
+
+ return *this;
+}
+
+void FontPlatformData::setupPaint(SkPaint* paint) const
+{
+ float ts = mTextSize;
+ if (!(ts > 0))
+ ts = 12;
+
+ paint->setAntiAlias(true);
+ paint->setSubpixelText(true);
+ paint->setTextSize(SkFloatToScalar(ts));
+ paint->setTypeface(mTypeface);
+ paint->setFakeBoldText(mFakeBold);
+ paint->setTextSkewX(mFakeItalic ? -SK_Scalar1/4 : 0);
+ paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& a) const
+{
+ return SkTypeface::Equal(mTypeface, a.mTypeface) &&
+ mTextSize == a.mTextSize &&
+ mFakeBold == a.mFakeBold &&
+ mFakeItalic == a.mFakeItalic;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ unsigned h = SkTypeface::UniqueID(mTypeface);
+ h ^= 0x01010101 * (((int)mFakeBold << 1) | (int)mFakeItalic);
+ h ^= *(uint32_t*)&mTextSize;
+ return h;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/GlyphMapAndroid.cpp b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
new file mode 100644
index 0000000..9b77348
--- /dev/null
+++ b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+#include "SimpleFontData.h"
+
+#include "SkTemplates.h"
+#include "SkPaint.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+#define NO_BREAK_SPACE_UNICHAR 0xA0
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
+ SkDebugf("%s last char is high-surrogate", __FUNCTION__);
+ return false;
+ }
+
+ SkPaint paint;
+ fontData->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
+ uint16_t* glyphs = glyphStorage.get();
+ unsigned count = paint.textToGlyphs(buffer, bufferLength << 1, glyphs);
+ if (count != length) {
+ SkDebugf("%s count != length\n", __FUNCTION__);
+ return false;
+ }
+
+ unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
+ for (unsigned i = 0; i < length; i++) {
+ setGlyphDataForIndex(offset + i, glyphs[i], fontData);
+ allGlyphs |= glyphs[i];
+ }
+ return allGlyphs != 0;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
new file mode 100644
index 0000000..23ac51d
--- /dev/null
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -0,0 +1,1114 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "Path.h"
+
+#include "SkBlurDrawLooper.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDashPathEffect.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkPorterDuff.h"
+#include "WebCoreViewBridge.h"
+#include "PlatformGraphicsContext.h"
+#include "AffineTransform.h"
+
+#include "android_graphics.h"
+#include "SkGradientShader.h"
+#include "SkBitmapRef.h"
+#include "SkString.h"
+
+using namespace std;
+
+#define GC2Canvas(ctx) (ctx)->m_data->mPgc->mCanvas
+
+namespace WebCore {
+
+static int RoundToInt(float x)
+{
+ return (int)roundf(x);
+}
+
+/* TODO / questions
+
+ mAlpha: how does this interact with the alpha in Color? multiply them together?
+ mPorterDuffMode: do I always respect this? If so, then
+ the rgb() & 0xFF000000 check will abort drawing too often
+ Is Color premultiplied or not? If it is, then I can't blindly pass it to paint.setColor()
+*/
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContext* mCG; // back-ptr to our parent
+ PlatformGraphicsContext* mPgc;
+
+ struct State {
+ float mMiterLimit;
+ float mAlpha;
+ SkDrawLooper* mLooper;
+ SkPaint::Cap mLineCap;
+ SkPaint::Join mLineJoin;
+ SkPorterDuff::Mode mPorterDuffMode;
+ int mDashRatio; //ratio of the length of a dash to its width
+
+ State()
+ {
+ mMiterLimit = 4;
+ mAlpha = 1;
+ mLooper = NULL;
+ mLineCap = SkPaint::kDefault_Cap;
+ mLineJoin = SkPaint::kDefault_Join;
+ mPorterDuffMode = SkPorterDuff::kSrcOver_Mode;
+ mDashRatio = 3;
+ }
+
+ State(const State& other)
+ {
+ other.mLooper->safeRef();
+ memcpy(this, &other, sizeof(State));
+ }
+
+ ~State()
+ {
+ mLooper->safeUnref();
+ }
+
+ SkDrawLooper* setDrawLooper(SkDrawLooper* dl)
+ {
+ SkRefCnt_SafeAssign(mLooper, dl);
+ return dl;
+ }
+
+ SkColor applyAlpha(SkColor c) const
+ {
+ int s = RoundToInt(mAlpha * 256);
+ if (s >= 256)
+ return c;
+ if (s < 0)
+ return 0;
+
+ int a = SkAlphaMul(SkColorGetA(c), s);
+ return (c & 0x00FFFFFF) | (a << 24);
+ }
+ };
+
+ SkDeque mStateStack;
+ State* mState;
+
+ GraphicsContextPlatformPrivate(GraphicsContext* cg, PlatformGraphicsContext* pgc)
+ : mCG(cg)
+ , mPgc(pgc), mStateStack(sizeof(State))
+
+ {
+ State* state = (State*)mStateStack.push_back();
+ new (state) State();
+ mState = state;
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ if (mPgc && mPgc->deleteUs())
+ delete mPgc;
+
+ // we force restores so we don't leak any subobjects owned by our
+ // stack of State records.
+ while (mStateStack.count() > 0)
+ this->restore();
+ }
+
+ void save()
+ {
+ State* newState = (State*)mStateStack.push_back();
+ new (newState) State(*mState);
+ mState = newState;
+ }
+
+ void restore()
+ {
+ mState->~State();
+ mStateStack.pop_back();
+ mState = (State*)mStateStack.back();
+ }
+
+ void setup_paint_common(SkPaint* paint) const
+ {
+#ifdef SK_DEBUGx
+ {
+ SkPaint defaultPaint;
+
+ SkASSERT(*paint == defaultPaint);
+ }
+#endif
+
+ paint->setAntiAlias(true);
+ paint->setDither(true);
+ paint->setPorterDuffXfermode(mState->mPorterDuffMode);
+ paint->setLooper(mState->mLooper);
+ }
+
+ void setup_paint_fill(SkPaint* paint) const
+ {
+ this->setup_paint_common(paint);
+
+ paint->setColor(mState->applyAlpha(mCG->fillColor().rgb()));
+ }
+
+ /* sets up the paint for stroking. Returns true if the style is really
+ just a dash of squares (the size of the paint's stroke-width.
+ */
+ bool setup_paint_stroke(SkPaint* paint, SkRect* rect) {
+ this->setup_paint_common(paint);
+
+ float width = mCG->strokeThickness();
+
+ //this allows dashing and dotting to work properly for hairline strokes
+ if (0 == width) {
+ width = 1;
+ }
+
+ paint->setColor(mState->applyAlpha(mCG->strokeColor().rgb()));
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(SkFloatToScalar(width));
+ paint->setStrokeCap(mState->mLineCap);
+ paint->setStrokeJoin(mState->mLineJoin);
+ paint->setStrokeMiter(SkFloatToScalar(mState->mMiterLimit));
+
+ if (rect != NULL && (RoundToInt(width) & 1)) {
+ rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ }
+
+ switch (mCG->strokeStyle()) {
+ case NoStroke:
+ case SolidStroke:
+ width = 0;
+ break;
+ case DashedStroke:
+ width = mState->mDashRatio * width;
+ break;
+ /* no break */
+ case DottedStroke:
+ break;
+ }
+
+ if (width > 0) {
+ SkScalar intervals[] = { width, width };
+ SkPathEffect* pe = new SkDashPathEffect(intervals, 2, 0);
+ paint->setPathEffect(pe)->unref();
+ // return true if we're basically a dotted dash of squares
+ return RoundToInt(width) == RoundToInt(paint->getStrokeWidth());
+ }
+ return false;
+ }
+
+private:
+ // not supported yet
+ State& operator=(const State&);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
+{
+ PlatformGraphicsContext* pgc = new PlatformGraphicsContext();
+
+ SkBitmap bitmap;
+
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ pgc->mCanvas->setBitmapDevice(bitmap);
+
+ GraphicsContext* ctx = new GraphicsContext(pgc);
+//printf("-------- create offscreen <canvas> %p\n", ctx);
+ return ctx;
+}
+
+void GraphicsContext::drawOffscreenContext(GraphicsContext* ctx, const FloatRect* srcRect, const FloatRect& dstRect)
+{
+ const SkBitmap& bm = GC2Canvas(ctx)->getDevice()->accessBitmap(false);
+ SkIRect src;
+ SkRect dst;
+ SkPaint paint;
+
+ paint.setFilterBitmap(true);
+
+ GC2Canvas(this)->drawBitmapRect(bm,
+ srcRect ? android_setrect(&src, *srcRect) : NULL,
+ *android_setrect(&dst, dstRect),
+ &paint);
+}
+
+FloatRect GraphicsContext::getClipLocalBounds() const
+{
+ SkRect r;
+
+ if (!GC2Canvas(this)->getClipBounds(&r))
+ r.setEmpty();
+
+ return FloatRect(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext *gc)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(this, gc))
+{
+ setPaintingDisabled(NULL == gc || NULL == gc->mCanvas);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ delete m_data;
+ this->destroyGraphicsContextPrivate(m_common);
+}
+
+void GraphicsContext::savePlatformState()
+{
+ // save our private State
+ m_data->save();
+ // save our native canvas
+ GC2Canvas(this)->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ // restore our native canvas
+ GC2Canvas(this)->restore();
+ // restore our private State
+ m_data->restore();
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+
+ if (fillColor().alpha()) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+
+ if (strokeStyle() != NoStroke && strokeColor().alpha()) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, &r);
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ if (style == NoStroke)
+ return;
+
+ SkPaint paint;
+ SkCanvas* canvas = GC2Canvas(this);
+ const int idx = SkAbs32(point2.x() - point1.x());
+ const int idy = SkAbs32(point2.y() - point1.y());
+
+ // special-case horizontal and vertical lines that are really just dots
+ if (m_data->setup_paint_stroke(&paint, NULL) && (0 == idx || 0 == idy)) {
+ const SkScalar diameter = paint.getStrokeWidth();
+ const SkScalar radius = SkScalarHalf(diameter);
+ SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x()));
+ SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y()));
+ SkScalar dx, dy;
+ int count;
+ SkRect bounds;
+
+ if (0 == idy) { // horizontal
+ bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius);
+ x += radius;
+ dx = diameter * 2;
+ dy = 0;
+ count = idx;
+ } else { // vertical
+ bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy));
+ y += radius;
+ dx = 0;
+ dy = diameter * 2;
+ count = idy;
+ }
+
+ // the actual count is the number of ONs we hit alternating
+ // ON(diameter), OFF(diameter), ...
+ {
+ SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter);
+ // now computer the number of cells (ON and OFF)
+ count = SkScalarRound(width);
+ // now compute the number of ONs
+ count = (count + 1) >> 1;
+ }
+
+ SkAutoMalloc storage(count * sizeof(SkPoint));
+ SkPoint* verts = (SkPoint*)storage.get();
+ // now build the array of vertices to past to drawPoints
+ for (int i = 0; i < count; i++) {
+ verts[i].set(x, y);
+ x += dx;
+ y += dy;
+ }
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setPathEffect(NULL);
+
+ // clipping to bounds is not required for correctness, but it does
+ // allow us to reject the entire array of points if we are completely
+ // offscreen. This is common in a webpage for android, where most of
+ // the content is clipped out. If drawPoints took an (optional) bounds
+ // parameter, that might even be better, as we would *just* use it for
+ // culling, and not both wacking the canvas' save/restore stack.
+ canvas->save(SkCanvas::kClip_SaveFlag);
+ canvas->clipRect(bounds);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
+ canvas->restore();
+ } else {
+ SkPoint pts[2];
+ android_setpt(&pts[0], point1);
+ android_setpt(&pts[1], point2);
+ canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+ }
+}
+
+static void setrect_for_underline(SkRect* r, GraphicsContext* context, const IntPoint& point, int yOffset, int width)
+{
+ float lineThickness = context->strokeThickness();
+// if (lineThickness < 1) // do we really need/want this?
+// lineThickness = 1;
+
+ yOffset += 1; // we add 1 to have underlines appear below the text
+
+ r->fLeft = SkIntToScalar(point.x());
+ r->fTop = SkIntToScalar(point.y() + yOffset);
+ r->fRight = r->fLeft + SkIntToScalar(width);
+ r->fBottom = r->fTop + SkFloatToScalar(lineThickness);
+}
+
+void GraphicsContext::drawLineForText(IntPoint const& pt, int width, bool)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ setrect_for_underline(&r, this, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(this->strokeColor().rgb());
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ setrect_for_underline(&r, this, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorRED); // is this specified somewhere?
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect oval;
+
+ android_setrect(&oval, rect);
+
+ if (fillColor().rgb() & 0xFF000000) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawOval(oval, paint);
+ }
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, &oval);
+ GC2Canvas(this)->drawOval(oval, paint);
+ }
+}
+
+static inline int fast_mod(int value, int max)
+{
+ int sign = SkExtractSign(value);
+
+ value = SkApplySign(value, sign);
+ if (value >= max) {
+ value %= max;
+ }
+ return SkApplySign(value, sign);
+}
+
+void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPath path;
+ SkPaint paint;
+ SkRect oval;
+
+ android_setrect(&oval, r);
+
+ if (strokeStyle() == NoStroke) {
+ m_data->setup_paint_fill(&paint); // we want the fill color
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToScalar(this->strokeThickness()));
+ }
+ else {
+ m_data->setup_paint_stroke(&paint, NULL);
+ }
+
+ // we do this before converting to scalar, so we don't overflow SkFixed
+ startAngle = fast_mod(startAngle, 360);
+ angleSpan = fast_mod(angleSpan, 360);
+
+ path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ SkPaint paint;
+ SkPath path;
+
+ path.incReserve(numPoints);
+ path.moveTo(SkFloatToScalar(points[0].x()), SkFloatToScalar(points[0].y()));
+ for (size_t i = 1; i < numPoints; i++)
+ path.lineTo(SkFloatToScalar(points[i].x()), SkFloatToScalar(points[i].y()));
+
+ if (fillColor().rgb() & 0xFF000000) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawPath(path, paint);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, NULL);
+ GC2Canvas(this)->drawPath(path, paint);
+ }
+}
+
+#ifdef ANDROID_CANVAS_IMPL
+
+static void check_set_shader(SkPaint* paint, SkShader* s0, SkShader* s1)
+{
+ if (s0) {
+ paint->setShader(s0);
+ }
+ else if (s1) {
+ paint->setShader(s1);
+ }
+}
+
+void GraphicsContext::fillPath(const Path& webCorePath, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+
+ m_data->setup_paint_fill(&paint);
+ check_set_shader(&paint, grad, pat);
+
+ const SkPath& path = *webCorePath.platformPath();
+
+#if 0
+ SkDebugf("---- fillPath\n");
+ SkPath::Iter iter(path, false);
+ SkPoint pts[4];
+ for (;;) {
+ SkString str;
+ const SkPoint* p = &pts[1];
+ int n = 0;
+ const char* name = "";
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ name = " M";
+ p = &pts[0];
+ n = 1;
+ break;
+ case SkPath::kLine_Verb:
+ name = " L";
+ n = 1;
+ break;
+ case SkPath::kQuad_Verb:
+ name = " Q";
+ n = 2;
+ break;
+ case SkPath::kCubic_Verb:
+ name = " C";
+ n = 3;
+ break;
+ case SkPath::kClose_Verb:
+ name = " X";
+ n = 0;
+ break;
+ case SkPath::kDone_Verb:
+ goto DONE;
+ }
+ str.append(name);
+ for (int i = 0; i < n; i++) {
+ str.append(" ");
+ str.appendScalar(p[i].fX);
+ str.append(" ");
+ str.appendScalar(p[i].fY);
+ }
+ SkDebugf("\"%s\"\n", str.c_str());
+ }
+DONE:
+#endif
+
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::strokePath(const Path& webCorePath, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ check_set_shader(&paint, grad, pat);
+
+ GC2Canvas(this)->drawPath(*webCorePath.platformPath(), paint);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ SkPaint paint;
+
+ m_data->setup_paint_fill(&paint);
+ check_set_shader(&paint, grad, pat);
+
+ GC2Canvas(this)->drawRect(*android_setrect(&r, rect), paint);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkPath path;
+ SkScalar radii[8];
+ SkRect r;
+
+ radii[0] = SkIntToScalar(topLeft.width());
+ radii[1] = SkIntToScalar(topLeft.height());
+ radii[2] = SkIntToScalar(topRight.width());
+ radii[3] = SkIntToScalar(topRight.height());
+ radii[4] = SkIntToScalar(bottomRight.width());
+ radii[5] = SkIntToScalar(bottomRight.height());
+ radii[6] = SkIntToScalar(bottomLeft.width());
+ radii[7] = SkIntToScalar(bottomLeft.height());
+ path.addRoundRect(*android_setrect(&r, rect), radii);
+
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ SkPaint paint;
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ paint.setStrokeWidth(SkFloatToScalar(lineWidth));
+ check_set_shader(&paint, grad, pat);
+
+ GC2Canvas(this)->drawRect(*android_setrect(&r, rect), paint);
+}
+
+static U8CPU F2B(float x)
+{
+ return (int)(x * 255);
+}
+
+static SkColor make_color(float a, float r, float g, float b)
+{
+ return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b));
+}
+
+PlatformGradient* GraphicsContext::newPlatformLinearGradient(const FloatPoint& p0, const FloatPoint& p1,
+ const float stopData[5], int count)
+{
+ SkPoint pts[2];
+
+ android_setpt(&pts[0], p0);
+ android_setpt(&pts[1], p1);
+
+ SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + count);
+
+ for (int i = 0; i < count; i++)
+ {
+ pos[i] = SkFloatToScalar(stopData[0]);
+ colors[i] = make_color(stopData[4], stopData[1], stopData[2], stopData[3]);
+ stopData += 5;
+ }
+
+ return SkGradientShader::CreateLinear(pts, colors, pos, count,
+ SkShader::kClamp_TileMode);
+}
+
+PlatformGradient* GraphicsContext::newPlatformRadialGradient(const FloatPoint& p0, float r0,
+ const FloatPoint& p1, float r1,
+ const float stopData[5], int count)
+{
+ SkPoint center;
+
+ android_setpt(&center, p1);
+
+ SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + count);
+
+ for (int i = 0; i < count; i++)
+ {
+ pos[i] = SkFloatToScalar(stopData[0]);
+ colors[i] = make_color(stopData[4], stopData[1], stopData[2], stopData[3]);
+ stopData += 5;
+ }
+
+ return SkGradientShader::CreateRadial(center, SkFloatToScalar(r1),
+ colors, pos, count,
+ SkShader::kClamp_TileMode);
+}
+
+void GraphicsContext::freePlatformGradient(PlatformGradient* shader)
+{
+ shader->safeUnref();
+}
+
+PlatformPattern* GraphicsContext::newPlatformPattern(Image* image,
+ Image::TileRule hRule,
+ Image::TileRule vRule)
+{
+//printf("----------- Image %p, [%d %d] %d %d\n", image, image->width(), image->height(), hRule, vRule);
+ if (NULL == image)
+ return NULL;
+
+ SkBitmapRef* bm = image->nativeImageForCurrentFrame();
+ if (NULL == bm)
+ return NULL;
+
+ return SkShader::CreateBitmapShader(bm->bitmap(),
+ android_convert_TileRule(hRule),
+ android_convert_TileRule(vRule));
+}
+
+void GraphicsContext::freePlatformPattern(PlatformPattern* shader)
+{
+ shader->safeUnref();
+}
+
+#endif
+
+#if 0
+static int getBlendedColorComponent(int c, int a)
+{
+ // We use white.
+ float alpha = (float)(a) / 255;
+ int whiteBlend = 255 - a;
+ c -= whiteBlend;
+ return (int)(c/alpha);
+}
+#endif
+
+void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (color.rgb() & 0xFF000000) {
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_common(&paint);
+ paint.setColor(color.rgb());
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (color.rgb() & 0xFF000000) {
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_common(&paint);
+ paint.setColor(color.rgb());
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+void GraphicsContext::clip(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+
+ GC2Canvas(this)->clipRect(*android_setrect(&r, rect));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+// path.platformPath()->dump(false, "clip path");
+
+ GC2Canvas(this)->clipPath(*path.platformPath());
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+//printf("-------- addInnerRoundedRectClip: [%d %d %d %d] thickness=%d\n", rect.x(), rect.y(), rect.width(), rect.height(), thickness);
+
+ SkPath path;
+ SkRect r;
+ android_setrect(&r, rect);
+ path.addOval(r, SkPath::kCW_Direction);
+ // only perform the inset if we won't invert r
+ if (2*thickness < rect.width() && 2*thickness < rect.height())
+ {
+ r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness));
+ path.addOval(r, SkPath::kCCW_Direction);
+ }
+ GC2Canvas(this)->clipPath(path);
+}
+
+void GraphicsContext::clipOut(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect rect;
+
+ GC2Canvas(this)->clipRect(*android_setrect(&rect, r), SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect oval;
+ SkPath path;
+
+ path.addOval(*android_setrect(&oval, r), SkPath::kCCW_Direction);
+ GC2Canvas(this)->clipPath(path, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOut(const Path& p)
+{
+ if (paintingDisabled())
+ return;
+
+ GC2Canvas(this)->clipPath(*p.platformPath(), SkRegion::kDifference_Op);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if SVG_SUPPORT
+KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext()
+{
+ return new KRenderingDeviceContextQuartz(platformContext());
+}
+#endif
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ SkCanvas* canvas = GC2Canvas(this);
+
+ if (opacity < 1)
+ {
+ canvas->saveLayerAlpha(NULL, (int)(opacity * 255), SkCanvas::kHasAlphaLayer_SaveFlag);
+ }
+ else
+ canvas->save();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ GC2Canvas(this)->restore();
+}
+
+void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (blur > 0)
+ {
+ SkColor c;
+
+ if (color.isValid())
+ c = color.rgb();
+ else
+ c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" Apple shadow color
+
+ SkDrawLooper* dl = new SkBlurDrawLooper(SkIntToScalar(blur),
+ SkIntToScalar(size.width()),
+ SkIntToScalar(size.height()),
+ c);
+ m_data->mState->setDrawLooper(dl)->unref();
+ }
+ else
+ m_data->mState->setDrawLooper(NULL);
+}
+
+void GraphicsContext::clearShadow()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->mState->setDrawLooper(NULL);
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ // Do nothing, since we draw the focus ring independently.
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ return m_data->mPgc;
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ m_data->mState->mMiterLimit = limit;
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_data->mState->mAlpha = alpha;
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ m_data->mState->mPorterDuffMode = android_convert_compositeOp(op);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_fill(&paint);
+ paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ paint.setStrokeWidth(SkFloatToScalar(lineWidth));
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ switch (cap) {
+ case ButtCap:
+ m_data->mState->mLineCap = SkPaint::kButt_Cap;
+ break;
+ case RoundCap:
+ m_data->mState->mLineCap = SkPaint::kRound_Cap;
+ break;
+ case SquareCap:
+ m_data->mState->mLineCap = SkPaint::kSquare_Cap;
+ break;
+ default:
+ SkDEBUGF(("GraphicsContext::setLineCap: unknown LineCap %d\n", cap));
+ break;
+ }
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ switch (join) {
+ case MiterJoin:
+ m_data->mState->mLineJoin = SkPaint::kMiter_Join;
+ break;
+ case RoundJoin:
+ m_data->mState->mLineJoin = SkPaint::kRound_Join;
+ break;
+ case BevelJoin:
+ m_data->mState->mLineJoin = SkPaint::kBevel_Join;
+ break;
+ default:
+ SkDEBUGF(("GraphicsContext::setLineJoin: unknown LineJoin %d\n", join));
+ break;
+ }
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->scale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+void GraphicsContext::rotate(float angleInRadians)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->rotate(SkFloatToScalar(angleInRadians * (180.0f / 3.14159265f)));
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->translate(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& xform)
+{
+ if (paintingDisabled())
+ return;
+
+//printf("-------------- GraphicsContext::concatCTM\n");
+ GC2Canvas(this)->concat((SkMatrix) xform);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return FloatRect();
+
+ const SkMatrix& matrix = GC2Canvas(this)->getTotalMatrix();
+ SkRect r;
+ android_setrect(&r, rect);
+ matrix.mapRect(&r);
+ FloatRect result(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ // appears to be PDF specific, so we ignore it
+#if 0
+ if (paintingDisabled())
+ return;
+
+ CFURLRef urlRef = link.createCFURL();
+ if (urlRef) {
+ CGContextRef context = platformContext();
+
+ // Get the bounding box to handle clipping.
+ CGRect box = CGContextGetClipBoundingBox(context);
+
+ IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
+ IntRect rect = destRect;
+ rect.intersect(intBox);
+
+ CGPDFContextSetURLForRect(context, urlRef,
+ CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+
+ CFRelease(urlRef);
+ }
+#endif
+}
+
+// we don't need to push these down, since we query the current state and build our paint at draw-time
+
+void GraphicsContext::setPlatformStrokeColor(const Color&) {}
+void GraphicsContext::setPlatformStrokeThickness(float) {}
+void GraphicsContext::setPlatformFillColor(const Color&) {}
+
+
+// functions new to Feb-19 tip of tree merge:
+AffineTransform GraphicsContext::getCTM() const {
+ notImplemented();
+ return AffineTransform();
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp
new file mode 100644
index 0000000..00145af
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "Image.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformString.h"
+#include "SharedBuffer.h"
+
+#include "android_graphics.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkString.h"
+
+#include <utils/AssetManager.h>
+
+//#define TRACE_SUBSAMPLED_BITMAPS
+
+android::AssetManager* gGlobalAssetMgr;
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ if (m_frame) {
+ m_frame->unref();
+ m_frame = 0;
+ m_duration = 0.;
+ m_hasAlpha = true;
+ }
+}
+
+SkBitmapRef* BitmapImage::getBitmap()
+{
+ return m_bitmapRef;
+}
+
+void BitmapImage::initPlatformData()
+{
+ m_bitmapRef = NULL;
+ m_source.clearURL();
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ if (m_bitmapRef) {
+ m_bitmapRef->unref();
+ m_bitmapRef = NULL;
+ }
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ if (this->frameCount() > 1) {
+ if (!m_bitmapRef) {
+ return;
+ }
+
+ const SkBitmap& bm = m_bitmapRef->bitmap();
+
+ if (bm.width() == 1 && bm.height() == 1) {
+ SkAutoLockPixels alp(bm);
+ if (bm.getPixels() == NULL) {
+ return;
+ }
+
+ SkPMColor color;
+ switch (bm.getConfig()) {
+ case SkBitmap::kARGB_8888_Config:
+ color = *bm.getAddr32(0, 0);
+ break;
+ case SkBitmap::kRGB_565_Config:
+ color = SkPixel16ToPixel32(*bm.getAddr16(0, 0));
+ break;
+ case SkBitmap::kIndex8_Config: {
+ SkColorTable* ctable = bm.getColorTable();
+ if (!ctable) {
+ return;
+ }
+ color = (*ctable)[*bm.getAddr8(0, 0)];
+ break;
+ }
+ default: // don't check other configs
+ return;
+ }
+ m_isSolidColor = true;
+ m_solidColor = android_SkPMColorToWebCoreColor(color);
+ }
+ }
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
+ const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ SkBitmapRef* image = this->nativeImageForCurrentFrame();
+ if (!image) { // If it's too early we won't have an image yet.
+ return;
+ }
+
+ // in case we get called with an incomplete bitmap
+ const SkBitmap& bitmap = image->bitmap();
+ if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+ return;
+ }
+
+ SkIRect srcR;
+ SkRect dstR;
+ float invScaleX = (float)bitmap.width() / image->origWidth();
+ float invScaleY = (float)bitmap.height() / image->origHeight();
+
+ android_setrect(&dstR, dstRect);
+ android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
+ if (srcR.isEmpty() || dstR.isEmpty()) {
+ return;
+ }
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkPaint paint;
+
+ paint.setFilterBitmap(true);
+ paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
+
+ startAnimation();
+
+#ifdef TRACE_SUBSAMPLED_BITMAPS
+ if (bitmap.width() != image->origWidth() ||
+ bitmap.height() != image->origHeight()) {
+ SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
+ bitmap.width(), bitmap.height(),
+ image->origWidth(), image->origHeight());
+ }
+#endif
+}
+
+void BitmapImage::setURL(const String& str)
+{
+ m_source.setURL(str);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
+ const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator compositeOp,
+ const FloatRect& destRect)
+{
+ SkBitmapRef* image = this->nativeImageForCurrentFrame();
+ if (!image) { // If it's too early we won't have an image yet.
+ return;
+ }
+
+ // in case we get called with an incomplete bitmap
+ const SkBitmap& bitmap = image->bitmap();
+ if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+ return;
+ }
+
+ SkRect dstR;
+ android_setrect(&dstR, destRect);
+ if (dstR.isEmpty()) {
+ return;
+ }
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkPaint paint;
+
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint.setShader(shader)->unref();
+ // now paint is the only owner of shader
+ paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ paint.setFilterBitmap(true);
+
+ SkMatrix matrix(patternTransform);
+
+ float scaleX = (float)image->origWidth() / bitmap.width();
+ float scaleY = (float)image->origHeight() / bitmap.height();
+ matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
+
+ matrix.postTranslate(SkFloatToScalar(phase.x()),
+ SkFloatToScalar(phase.y()));
+ shader->setLocalMatrix(matrix);
+ canvas->drawRect(dstR, paint);
+
+#ifdef TRACE_SUBSAMPLED_BITMAPS
+ if (bitmap.width() != image->origWidth() ||
+ bitmap.height() != image->origHeight()) {
+ SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
+ bitmap.width(), bitmap.height(),
+ image->origWidth(), image->origHeight(),
+ SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height()));
+ }
+#endif
+}
+
+// missingImage, textAreaResizeCorner
+Image* Image::loadPlatformResource(const char *name)
+{
+ if (NULL == gGlobalAssetMgr) {
+ gGlobalAssetMgr = new android::AssetManager();
+ gGlobalAssetMgr->addDefaultAssets();
+ }
+
+ SkString path("webkit/");
+ path.append(name);
+ path.append(".png");
+
+ android::Asset* a = gGlobalAssetMgr->open(path.c_str(),
+ android::Asset::ACCESS_BUFFER);
+ if (a == NULL) {
+ SkDebugf("---------------- failed to open image asset %s\n", name);
+ return NULL;
+ }
+
+ Image* image = new BitmapImage;
+ RefPtr<SharedBuffer> buffer =
+ new SharedBuffer((const char*)a->getBuffer(false), a->getLength());
+ image->setData(buffer, true);
+ delete a;
+ return image;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
new file mode 100644
index 0000000..65fb7cd
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
@@ -0,0 +1,53 @@
+/* ImageBufferAndroid.cpp
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "GraphicsContext.h"
+
+using namespace std;
+
+namespace WebCore {
+
+auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale)
+{
+ // Ignore grayScale for now, since SkBitmap doesn't support it... yet
+
+ GraphicsContext* ctx = GraphicsContext::createOffscreenContext(size.width(), size.height());
+
+ auto_ptr<GraphicsContext> context(ctx);
+
+ return auto_ptr<ImageBuffer>(new ImageBuffer(size, context));
+}
+
+
+ImageBuffer::ImageBuffer(const IntSize& size, auto_ptr<GraphicsContext> context)
+ : m_data(NULL), m_size(size), m_context(context.release())
+{
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
new file mode 100644
index 0000000..144968d
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -0,0 +1,336 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ImageDecoder.h"
+#include "ImageSource.h"
+#include "IntSize.h"
+#include "SharedBuffer.h"
+#include "PlatformString.h"
+
+#include "JavaSharedClient.h"
+
+#include "SkBitmapRef.h"
+#include "SkImageRef.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
+
+//#define TRACE_SUBSAMPLE_BITMAPS
+//#define TRACE_RLE_BITMAPS
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkImageRef_ashmem.h"
+
+// made this up, so we don't waste a file-descriptor on small images, plus
+// we don't want to lose too much on the round-up to a page size (4K)
+#define MIN_ASHMEM_ALLOC_SIZE (32*1024)
+
+static bool should_use_ashmem(const SkBitmap& bm) {
+ return bm.getSize() >= MIN_ASHMEM_ALLOC_SIZE;
+}
+
+/* Images larger than this should be subsampled. Using ashmem, the decoded
+ pixels will be purged as needed, so this value can be pretty large. Making
+ it too small hurts image quality (e.g. abc.com background). 2Meg works for
+ the sites I've tested, but if we hit important sites that need more, we
+ should try increasing it and see if it has negative impact on performance
+ (i.e. we end up thrashing because we need to keep decoding images that have
+ been purged.
+
+ Perhaps this value should be some fraction of the available RAM...
+*/
+static size_t computeMaxBitmapSizeForCache() {
+ return 2*1024*1024;
+}
+
+/* 8bit images larger than this should be recompressed in RLE, to reduce
+ on the imageref cache.
+
+ Downside: performance, since we have to decode/encode
+ and then rle-decode when we draw.
+*/
+static bool shouldReencodeAsRLE(const SkBitmap& bm) {
+ const SkBitmap::Config c = bm.config();
+ return (SkBitmap::kIndex8_Config == c || SkBitmap::kA8_Config == c)
+ &&
+ bm.width() >= 64 // narrower than this won't compress well in RLE
+ &&
+ bm.getSize() > (250*1024);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class PrivateAndroidImageSourceRec : public SkBitmapRef {
+public:
+ PrivateAndroidImageSourceRec(const SkBitmap& bm, int origWidth,
+ int origHeight, int sampleSize)
+ : SkBitmapRef(bm), fSampleSize(sampleSize), fAllDataReceived(false) {
+ this->setOrigSize(origWidth, origHeight);
+ }
+
+ int fSampleSize;
+ bool fAllDataReceived;
+};
+
+namespace WebCore {
+
+class SharedBufferStream : public SkMemoryStream {
+public:
+ SharedBufferStream(SharedBuffer* buffer)
+ : SkMemoryStream(buffer->data(), buffer->size(), false) {
+ fBuffer = buffer;
+ buffer->ref();
+ }
+
+ virtual ~SharedBufferStream() {
+ // we can't necessarily call fBuffer->deref() here, as we may be
+ // in a different thread from webkit, and SharedBuffer is not
+ // threadsafe. Therefore we defer it until it can be executed in the
+ // webkit thread.
+// SkDebugf("-------- enqueue buffer %p for deref\n", fBuffer);
+ JavaSharedClient::EnqueueFunctionPtr(CallDeref, fBuffer);
+ }
+
+private:
+ // don't allow this to change our data. should not get called, but we
+ // override here just to be sure
+ virtual void setMemory(const void* data, size_t length, bool copyData) {
+ sk_throw();
+ }
+
+ // we share ownership of this with webkit
+ SharedBuffer* fBuffer;
+
+ // will be invoked in the webkit thread
+ static void CallDeref(void* buffer) {
+// SkDebugf("-------- call deref on buffer %p\n", buffer);
+ ((SharedBuffer*)buffer)->deref();
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+ImageSource::ImageSource() {
+ m_decoder.m_image = NULL;
+}
+
+ImageSource::~ImageSource() {
+ delete m_decoder.m_image;
+}
+
+bool ImageSource::initialized() const {
+ return m_decoder.m_image != NULL;
+}
+
+static int computeSampleSize(const SkBitmap& bitmap) {
+ const size_t maxSize = computeMaxBitmapSizeForCache();
+ size_t size = bitmap.getSize();
+ int sampleSize = 1;
+
+ while (size > maxSize) {
+ sampleSize <<= 1;
+ size >>= 2;
+ }
+
+#ifdef TRACE_SUBSAMPLE_BITMAPS
+ if (sampleSize > 1) {
+ SkDebugf("------- bitmap [%d %d] config=%d origSize=%d predictSize=%d sampleSize=%d\n",
+ bitmap.width(), bitmap.height(), bitmap.config(),
+ bitmap.getSize(), size, sampleSize);
+ }
+#endif
+ return sampleSize;
+}
+
+static SkPixelRef* convertToRLE(SkBitmap* bm, const void* data, size_t len) {
+ if (!shouldReencodeAsRLE(*bm)) {
+ return NULL;
+ }
+
+ SkBitmap tmp;
+
+ if (!SkImageDecoder::DecodeMemory(data, len, &tmp) || !tmp.getPixels()) {
+ return NULL;
+ }
+
+ SkPixelRef* ref = SkCreateRLEPixelRef(tmp);
+ if (NULL == ref) {
+ return NULL;
+ }
+
+#ifdef TRACE_RLE_BITMAPS
+ SkDebugf("---- reencode bitmap as RLE: [%d %d] encodeSize=%d\n",
+ tmp.width(), tmp.height(), len);
+#endif
+
+ bm->setConfig(SkBitmap::kRLE_Index8_Config, tmp.width(), tmp.height());
+ return ref;
+}
+
+void ImageSource::clearURL()
+{
+ m_decoder.m_url.reset();
+}
+
+void ImageSource::setURL(const String& url)
+{
+ if (url.startsWith("data:")) {
+ clearURL();
+ } else {
+ m_decoder.m_url.setUTF16(url.characters(), url.length());
+ }
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (NULL == m_decoder.m_image) {
+ SkBitmap tmp;
+
+ SkMemoryStream stream(data->data(), data->size(), false);
+ SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+ SkAutoTDelete<SkImageDecoder> ad(codec);
+
+ if (!codec || !codec->decode(&stream, &tmp, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return;
+ }
+
+ int origW = tmp.width();
+ int origH = tmp.height();
+ int sampleSize = computeSampleSize(tmp);
+ if (sampleSize > 1) {
+ codec->setSampleSize(sampleSize);
+ stream.rewind();
+ if (!codec->decode(&stream, &tmp, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return;
+ }
+ }
+
+ m_decoder.m_image = new PrivateAndroidImageSourceRec(tmp, origW, origH,
+ sampleSize);
+ }
+
+ PrivateAndroidImageSourceRec* decoder = m_decoder.m_image;
+ if (allDataReceived && !decoder->fAllDataReceived) {
+ decoder->fAllDataReceived = true;
+
+ SkBitmap* bm = &decoder->bitmap();
+ SkPixelRef* ref = convertToRLE(bm, data->data(), data->size());
+
+ if (NULL == ref) {
+ SkStream* strm = new SharedBufferStream(data);
+ // imageref now owns the stream object
+ if (should_use_ashmem(*bm)) {
+// SkDebugf("---- use ashmem for image [%d %d]\n", bm.width(), bm.height());
+ ref = new SkImageRef_ashmem(strm, bm->config(), decoder->fSampleSize);
+ } else {
+// SkDebugf("---- use globalpool for image [%d %d]\n", bm.width(), bm.height());
+ ref = new SkImageRef_GlobalPool(strm, bm->config(), decoder->fSampleSize);
+ }
+
+ // SkDebugf("----- allDataReceived [%d %d]\n", bm->width(), bm->height());
+ }
+
+ // we promise to never change the pixels (makes picture recording fast)
+ ref->setImmutable();
+ // give it the URL if we have one
+ ref->setURI(m_decoder.m_url);
+ // our bitmap is now the only owner of the imageref
+ bm->setPixelRef(ref)->unref();
+ }
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ return m_decoder.m_image != NULL;
+}
+
+IntSize ImageSource::size() const
+{
+ if (m_decoder.m_image) {
+ return IntSize(m_decoder.m_image->origWidth(), m_decoder.m_image->origHeight());
+ }
+ return IntSize(0, 0);
+}
+
+int ImageSource::repetitionCount()
+{
+ return 1;
+ // A property with value 0 means loop forever.
+}
+
+size_t ImageSource::frameCount() const
+{
+ // i.e. 0 frames if we're not decoded, or 1 frame if we are
+ return m_decoder.m_image != NULL;
+}
+
+SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
+{
+ SkASSERT(index == 0);
+ SkASSERT(m_decoder.m_image != NULL);
+ m_decoder.m_image->ref();
+ return m_decoder.m_image;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ SkASSERT(index == 0);
+ float duration = 0;
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
+ // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
+ // a duration of <= 10 ms. See gfxImageFrame::GetTimeout in Gecko or Radar 4051389 for more.
+ if (duration <= 0.010f)
+ duration = 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ SkASSERT(0 == index);
+
+ if (NULL == m_decoder.m_image)
+ return true; // if we're not sure, assume the worse-case
+ const PrivateAndroidImageSourceRec& decoder = *m_decoder.m_image;
+ // if we're 16bit, we know even without all the data available
+ if (decoder.bitmap().getConfig() == SkBitmap::kRGB_565_Config)
+ return false;
+
+ if (!decoder.fAllDataReceived)
+ return true; // if we're not sure, assume the worse-case
+
+ return !decoder.bitmap().isOpaque();
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ SkASSERT(0 == index);
+ return m_decoder.m_image && m_decoder.m_image->fAllDataReceived;
+}
+
+void ImageSource::clear()
+{
+ // do nothing, since the cache is managed elsewhere
+}
+
+}
diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp
new file mode 100644
index 0000000..68f4c0d
--- /dev/null
+++ b/WebCore/platform/graphics/android/PathAndroid.cpp
@@ -0,0 +1,231 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Path.h"
+#include "FloatRect.h"
+#include "AffineTransform.h"
+
+#include "SkPath.h"
+#include "SkRegion.h"
+
+#include "android_graphics.h"
+
+namespace WebCore {
+
+Path::Path()
+{
+ m_path = new SkPath;
+// m_path->setFlags(SkPath::kWinding_FillType);
+}
+
+Path::Path(const Path& other)
+{
+ m_path = new SkPath(*other.m_path);
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path& Path::operator=(const Path& other)
+{
+ *m_path = *other.m_path;
+ return *this;
+}
+
+bool Path::isEmpty() const
+{
+ return m_path->isEmpty();
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ SkRegion rgn, clip;
+
+ int x = (int)floorf(point.x());
+ int y = (int)floorf(point.y());
+ clip.setRect(x, y, x + 1, y + 1);
+
+ SkPath::FillType ft = m_path->getFillType(); // save
+ m_path->setFillType(rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
+
+ bool contains = rgn.setPath(*m_path, clip);
+
+ m_path->setFillType(ft); // restore
+ return contains;
+}
+
+void Path::translate(const FloatSize& size)
+{
+ m_path->offset(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+FloatRect Path::boundingRect() const
+{
+ SkRect r;
+
+ m_path->computeBounds(&r, SkPath::kExact_BoundsType);
+ return FloatRect( SkScalarToFloat(r.fLeft),
+ SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()),
+ SkScalarToFloat(r.height()));
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()));
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ m_path->lineTo(SkFloatToScalar(p.x()), SkFloatToScalar(p.y()));
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
+{
+ m_path->quadTo( SkFloatToScalar(cp.x()), SkFloatToScalar(cp.y()),
+ SkFloatToScalar(ep.x()), SkFloatToScalar(ep.y()));
+}
+
+void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
+{
+ m_path->cubicTo(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
+ SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()),
+ SkFloatToScalar(ep.x()), SkFloatToScalar(ep.y()));
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ m_path->arcTo(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
+ SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()),
+ SkFloatToScalar(radius));
+}
+
+void Path::closeSubpath()
+{
+ m_path->close();
+}
+
+static const float gPI = 3.1415926f;
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea,
+ bool clockwise) {
+ SkScalar cx = SkFloatToScalar(p.x());
+ SkScalar cy = SkFloatToScalar(p.y());
+ SkScalar radius = SkFloatToScalar(r);
+
+ SkRect oval;
+ oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
+
+ float sweep = ea - sa;
+ // check for a circle
+ if (sweep >= 2*gPI || sweep <= -2*gPI) {
+ m_path->addOval(oval);
+ } else {
+ SkScalar startDegrees = SkFloatToScalar(sa * 180 / gPI);
+ SkScalar sweepDegrees = SkFloatToScalar(sweep * 180 / gPI);
+
+ if (clockwise && sweepDegrees > 0) {
+ sweepDegrees -= SkIntToScalar(360);
+ } else if (!clockwise && sweepDegrees < 0) {
+ sweepDegrees = SkIntToScalar(360) - sweepDegrees;
+ }
+
+// SkDebugf("addArc sa=%g ea=%g cw=%d start=%g sweep=%g\n", sa, ea, clockwise,
+// SkScalarToFloat(startDegrees), SkScalarToFloat(sweepDegrees));
+
+ m_path->arcTo(oval, startDegrees, sweepDegrees, false);
+ }
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_path->addRect(r);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_path->addOval(r);
+}
+
+void Path::clear()
+{
+ m_path->reset();
+}
+
+static FloatPoint* setfpts(FloatPoint dst[], const SkPoint src[], int count)
+{
+ for (int i = 0; i < count; i++)
+ {
+ dst[i].setX(SkScalarToFloat(src[i].fX));
+ dst[i].setY(SkScalarToFloat(src[i].fY));
+ }
+ return dst;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ SkPath::Iter iter(*m_path, false);
+ SkPoint pts[4];
+
+ PathElement elem;
+ FloatPoint fpts[3];
+
+ for (;;)
+ {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ elem.type = PathElementMoveToPoint;
+ elem.points = setfpts(fpts, &pts[0], 1);
+ break;
+ case SkPath::kLine_Verb:
+ elem.type = PathElementAddLineToPoint;
+ elem.points = setfpts(fpts, &pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ elem.type = PathElementAddQuadCurveToPoint;
+ elem.points = setfpts(fpts, &pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ elem.type = PathElementAddCurveToPoint;
+ elem.points = setfpts(fpts, &pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ elem.type = PathElementCloseSubpath;
+ elem.points = NULL;
+ break;
+ case SkPath::kDone_Verb:
+ return;
+ }
+ function(info, &elem);
+ }
+}
+
+void Path::transform(const AffineTransform& xform)
+{
+ m_path->transform(xform);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/PlatformGraphics.h b/WebCore/platform/graphics/android/PlatformGraphics.h
new file mode 100644
index 0000000..6efdb43
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphics.h
@@ -0,0 +1,25 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef PlatformGraphics_d
+#define PlatformGraphics_d
+
+typedef class SkShader PlatformGradient;
+typedef class SkShader PlatformPattern;
+
+#endif
+
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
new file mode 100644
index 0000000..af443b8
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "Node.h"
+#include "PlatformGraphicsContext.h"
+#include "SkCanvas.h"
+
+namespace WebCore {
+
+PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas) : mCanvas(canvas), m_deleteCanvas(false)
+{
+ // This is useful only if this Canvas is part of an SkPicture object.
+ m_buttons = new SkTDArray<Container*>;
+}
+
+PlatformGraphicsContext::PlatformGraphicsContext() : m_deleteCanvas(true)
+{
+ mCanvas = new SkCanvas;
+ // Since this is our own private SkCanvas, and has no relation to a picture
+ // storing button references would be meaningless.
+ m_buttons = NULL;
+}
+
+PlatformGraphicsContext::~PlatformGraphicsContext()
+{
+ if (m_deleteCanvas) {
+// printf("-------------------- deleting offscreen canvas\n");
+ delete mCanvas;
+ }
+ if (m_buttons != NULL) {
+ m_buttons->deleteAll();
+ delete m_buttons;
+ }
+}
+
+SkTDArray<Container*>* PlatformGraphicsContext::getAndClearButtonInfo()
+{
+ // The caller is now responsible for deleting the array
+ SkTDArray<Container*>* buttons = m_buttons;
+ m_buttons = NULL;
+ return buttons;
+}
+
+void PlatformGraphicsContext::storeButtonInfo(Node* node, const IntRect& r)
+{
+ if (m_buttons == NULL)
+ return;
+ // Initialize all of the nodes to have disabled state, so that we guarantee
+ // that we paint all of them the first time.
+ RenderSkinAndroid::State state = RenderSkinAndroid::kDisabled;
+ Container* container = new Container(node, r, state);
+ // Place a reference to our subpicture in the Picture.
+ mCanvas->drawPicture(*(container->picture()));
+ // Keep track of the information about the button.
+ *m_buttons->append() = container;
+}
+
+} // WebCore
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
new file mode 100644
index 0000000..a2d7ebe
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef platform_graphics_context_h
+#define platform_graphics_context_h
+
+#include "IntRect.h"
+#include "RenderSkinAndroid.h"
+#include "RenderSkinButton.h"
+#include "SkCanvas.h"
+#include "SkPicture.h"
+#include "SkTDArray.h"
+
+class SkCanvas;
+class WebCore::Node;
+
+class Container {
+public:
+ Container(WebCore::Node* node, const WebCore::IntRect& r,
+ WebCore::RenderSkinAndroid::State is)
+ : m_node(node), m_rect(r), m_state(is)
+ {
+ m_picture = new SkPicture;
+ }
+
+ ~Container()
+ {
+ m_picture->unref();
+ }
+
+ bool matches(WebCore::Node* match) { return m_node == match; }
+
+ // Provide a pointer to our SkPicture.
+ SkPicture* picture() { return m_picture; }
+
+ // Update the focus state of this button, depending on whether it
+ // corresponds to the focused node passed in. If its state has changed,
+ // re-record to the subpicture, so the master picture will reflect the
+ // change.
+ void updateFocusState(WebCore::Node* focus)
+ {
+ WebCore::RenderSkinAndroid::State state = m_node == focus ?
+ WebCore::RenderSkinAndroid::kFocused : WebCore::RenderSkinAndroid::kNormal;
+ if (state == m_state)
+ return;
+ m_state = state;
+ SkCanvas* canvas = m_picture->beginRecording(m_rect.width(), m_rect.height());
+ WebCore::RenderSkinButton::Draw(canvas, m_rect, state);
+ m_picture->endRecording();
+ }
+private:
+ // Mark copy and assignment private so noone can use them.
+ Container& operator=(const Container& src) { return *this; }
+ Container(const Container& src) { }
+ // Only used for comparison, since after it is stored it will be transferred
+ // to the UI thread.
+ WebCore::Node* m_node;
+ // The rectangle representing the bounds of the button.
+ WebCore::IntRect m_rect;
+ // An SkPicture that, thanks to storeButtonInfo, is pointed to by the master
+ // picture, so that we can rerecord this button without rerecording the
+ // world.
+ SkPicture* m_picture;
+ // The state of the button - Currently kFocused or kNormal (and kDisabled
+ // as an initial value), but could be expanded to include other states.
+ WebCore::RenderSkinAndroid::State m_state;
+};
+
+namespace WebCore {
+
+class PlatformGraphicsContext {
+public:
+ PlatformGraphicsContext();
+ PlatformGraphicsContext(SkCanvas* canvas);
+ ~PlatformGraphicsContext();
+
+ SkCanvas* mCanvas;
+
+ bool deleteUs() const { return m_deleteCanvas; }
+ // If our graphicscontext has a button list, add a new container for the
+ // nod/rect, and record a new subpicture for this node/button in the current
+ // mCanvas
+ void storeButtonInfo(Node* node, const IntRect& r);
+ // Detaches button array (if any), returning it to the caller and setting our
+ // internal ptr to NULL
+ SkTDArray<Container*>* getAndClearButtonInfo();
+private:
+ bool m_deleteCanvas;
+ SkTDArray<Container*>* m_buttons;
+};
+
+}
+#endif
+
diff --git a/WebCore/platform/graphics/android/SkBitmapRef.h b/WebCore/platform/graphics/android/SkBitmapRef.h
new file mode 100644
index 0000000..77afcf3
--- /dev/null
+++ b/WebCore/platform/graphics/android/SkBitmapRef.h
@@ -0,0 +1,54 @@
+/* include/graphics/SkBitmapRef.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef SkBitmapRef_DEFINED
+#define SkBitmapRef_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkBitmap.h"
+
+class SkBitmapRef : public SkRefCnt {
+public:
+ SkBitmapRef() : fOrigWidth(0), fOrigHeight(0), fAccessed(false) {}
+ explicit SkBitmapRef(const SkBitmap& src)
+ : fBitmap(src),
+ fOrigWidth(src.width()),
+ fOrigHeight(src.height()),
+ fAccessed(false) {}
+
+ const SkBitmap& bitmap() const { return fBitmap; }
+ SkBitmap& bitmap() { return fBitmap; }
+
+ int origWidth() const { return fOrigWidth; }
+ int origHeight() const { return fOrigHeight; }
+
+ void setOrigSize(int width, int height) {
+ fOrigWidth = width;
+ fOrigHeight = height;
+ }
+ // return true if this is not the first access
+ // mark it true so all subsequent calls return true
+ bool accessed() { bool result = fAccessed;
+ fAccessed = true; return result; }
+
+private:
+ SkBitmap fBitmap;
+ int fOrigWidth, fOrigHeight;
+ bool fAccessed;
+};
+
+#endif
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
new file mode 100644
index 0000000..3964ee1
--- /dev/null
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "android_graphics.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src)
+{
+ dst->set(SkIntToScalar(src.x()), SkIntToScalar(src.y()));
+ return dst;
+}
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src)
+{
+ dst->set(SkFloatToScalar(src.x()), SkFloatToScalar(src.y()));
+ return dst;
+}
+
+SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src)
+{
+ dst->set(SkIntToScalar(src.x()),
+ SkIntToScalar(src.y()),
+ SkIntToScalar(src.x() + src.width()),
+ SkIntToScalar(src.y() + src.height()));
+ return dst;
+}
+
+SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src)
+{
+ dst->set(src.x(), src.y(),
+ src.x() + src.width(),
+ src.y() + src.height());
+ return dst;
+}
+
+SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkFloatToScalar(src.x()),
+ SkFloatToScalar(src.y()),
+ SkFloatToScalar(src.x() + src.width()),
+ SkFloatToScalar(src.y() + src.height()));
+ return dst;
+}
+
+SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x())),
+ SkScalarRound(SkFloatToScalar(src.y())),
+ SkScalarRound(SkFloatToScalar(src.x() + src.width())),
+ SkScalarRound(SkFloatToScalar(src.y() + src.height())));
+ return dst;
+}
+
+SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
+ SkScalarRound(SkFloatToScalar(src.y() * sy)),
+ SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
+ SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
+ return dst;
+}
+
+static const struct CompositOpToPorterDuffMode {
+ uint8_t mCompositOp;
+ uint8_t mPorterDuffMode;
+} gMapCompositOpsToPorterDuffModes[] = {
+ { WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
+ { WebCore::CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
+ { WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
+ { WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
+ { WebCore::CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
+ { WebCore::CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
+ { WebCore::CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
+ { WebCore::CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
+ { WebCore::CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
+ { WebCore::CompositeXOR, SkPorterDuff::kXor_Mode },
+ { WebCore::CompositePlusDarker, SkPorterDuff::kDarken_Mode },
+ { WebCore::CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositePlusLighter, SkPorterDuff::kLighten_Mode }
+};
+
+SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator op)
+{
+ const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
+
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
+ if (table[i].mCompositOp == op) {
+ return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
+ }
+ }
+
+ SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositOperator %d\n", op));
+ return SkPorterDuff::kSrcOver_Mode; // fall-back
+}
+
+SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule rule)
+{
+ // stretch == clamp
+ // repeat == repeat
+ // RoundTile???
+
+ return WebCore::Image::RepeatTile == rule ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
+{
+ SkASSERT(component == (uint8_t)component);
+ return (component * scale + 0x8000) >> 16;
+}
+
+// move this guy into SkColor.h
+static SkColor SkPMColorToColor(SkPMColor pm)
+{
+ if (0 == pm)
+ return 0;
+
+ unsigned a = SkGetPackedA32(pm);
+ uint32_t scale = (255 << 16) / a;
+
+ return SkColorSetARGB(a,
+ InvScaleByte(SkGetPackedR32(pm), scale),
+ InvScaleByte(SkGetPackedG32(pm), scale),
+ InvScaleByte(SkGetPackedB32(pm), scale));
+}
+
+WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
+{
+ SkColor c = SkPMColorToColor(pm);
+
+ return WebCore::Color(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), SkColorGetA(c));
+}
+
+const static SkColor focusOuterColors[] = {
+ SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal focus ring select
+ SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake focus ring select, for phone, email, text
+ SkColorSetARGB(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
+ SkColorSetARGB(0xff, 0xb0, 0x16, 0x00), // invalid focus ring color
+ SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal focus ring pressed
+ SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake focus ring pressed
+};
+
+const static SkColor focusInnerColors[] = {
+ SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal focus ring select
+ SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake focus ring select, for phone, email, text
+ SkColorSetARGB(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
+ SkColorSetARGB(0xff, 0xd9, 0x2c, 0x00), // invalid focus ring color
+ SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal focus ring pressed
+ SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake focus ring pressed
+};
+
+const static SkColor focusPressedColors[] = {
+ SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
+ SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00), // fake focus ring pressed
+ SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B) // button focus ring pressed
+};
+
+#define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
+#define FOCUS_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
+#define FOCUS_RING_OUTER_OUTSET 2 // used to inflate rects added to region
+
+void FocusRing::DrawRing(SkCanvas* canvas,
+ const Vector<WebCore::IntRect>& rects, Flavor flavor)
+{
+ unsigned rectCount = rects.size();
+ SkRegion rgn;
+ SkPath path;
+ for (unsigned i = 0; i < rectCount; i++)
+ {
+ SkIRect r;
+
+ android_setrect(&r, rects[i]);
+ r.inset(-FOCUS_RING_OUTER_OUTSET, -FOCUS_RING_OUTER_OUTSET);
+ rgn.op(r, SkRegion::kUnion_Op);
+ }
+ rgn.getBoundaryPath(&path);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setPathEffect(new SkCornerPathEffect(FOCUS_RING_ROUNDEDNESS))->unref();
+ if (flavor >= NORMAL_ANIMATING) { // pressed
+ paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
+ canvas->drawPath(path, paint);
+ }
+ if (flavor == BUTTON_ANIMATING)
+ return;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
+ paint.setColor(focusOuterColors[flavor]);
+ canvas->drawPath(path, paint);
+ paint.setStrokeWidth(FOCUS_RING_INNER_DIAMETER);
+ paint.setColor(focusInnerColors[flavor]);
+ canvas->drawPath(path, paint);
+}
+
+
diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h
new file mode 100644
index 0000000..91c56b7
--- /dev/null
+++ b/WebCore/platform/graphics/android/android_graphics.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_graphics_DEFINED
+#define android_graphics_DEFINED
+
+#include "Color.h"
+#include "Image.h"
+#include "wtf/Vector.h"
+
+#include "SkColor.h"
+#include "SkPorterDuff.h"
+#include "SkScalar.h"
+#include "SkShader.h"
+
+class SkCanvas;
+struct SkPoint;
+struct SKRect;
+
+namespace WebCore {
+ class FloatRect;
+ class IntPoint;
+ class IntRect;
+}
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src);
+SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src);
+SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src);
+SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src);
+SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src);
+SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src);
+SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy);
+
+SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator);
+SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule);
+
+WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm);
+
+// Data and methods for focus rings
+
+// used to inflate node cache entry
+#define FOCUS_RING_HIT_TEST_RADIUS SkIntToScalar(5)
+
+// used to inval rectangle enclosing pressed state of focus ring
+#define FOCUS_RING_OUTER_DIAMETER SkFixedToScalar(SkIntToFixed(13)>>2) // 13/4 == 3.25
+
+struct FocusRing {
+public:
+ enum Flavor {
+ NORMAL_FLAVOR,
+ FAKE_FLAVOR,
+ BUTTON_NO_RING,
+ INVALID_FLAVOR,
+ NORMAL_ANIMATING,
+ FAKE_ANIMATING,
+ BUTTON_ANIMATING,
+ ANIMATING_COUNT = 2
+ };
+
+ static void DrawRing(SkCanvas* ,
+ const Vector<WebCore::IntRect>& rects, Flavor );
+};
+
+#endif
+