Skip to content

Commit

Permalink
webkit: Color Inversion for power saving and eye strain relief
Browse files Browse the repository at this point in the history
This patch allows to set an 'inversion flag' on the Web View to
render the content (but not images) inverting the color. The typical
usage is when rendering some black text on white page: using color
inversion you get a more readable text and you save power at the
same time.

This patch is based on ec1ce8d8eac4a768b5888fe956a3defc7d457f6f.

Change-Id: I0693426589bd5f8c83457a5b8899fe5b85285120
  • Loading branch information
Enrico Ros authored and hyperb1iss committed Aug 14, 2010
1 parent 087e8ba commit 7d65dc4
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 9 deletions.
68 changes: 61 additions & 7 deletions WebKit/android/jni/PictureSet.cpp
Expand Up @@ -37,12 +37,12 @@
#include "SkRect.h"
#include "SkRegion.h"
#include "SkStream.h"
#include "SyncProxyCanvas.h"
#include "TimeCounter.h"

#ifdef CACHED_IMAGE_DECODE
#include <wtf/PassOwnPtr.h>
#include "SkPixelRef.h"
#include "SyncProxyCanvas.h"
#endif

#define MAX_DRAW_TIME 100
Expand Down Expand Up @@ -247,8 +247,9 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
public:
static WTF::PassOwnPtr<BitmapProxyCanvas> create(SkCanvas* canvas,
WTF::Vector<const SkBitmap*>* pBitmaps,
WTF::Vector<SkRect>* pBitmapRects) {
return new BitmapProxyCanvas(canvas, pBitmaps, pBitmapRects);
WTF::Vector<SkRect>* pBitmapRects,
bool invert) {
return new BitmapProxyCanvas(canvas, pBitmaps, pBitmapRects, invert);
}

virtual void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
Expand All @@ -265,6 +266,16 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
appendBitmap(bitmap, fastBounds);
} else {
target->drawBitmap(bitmap, x, y, paint);
if (invertBitmaps) {
target->save();
SkRect inversionRect;
inversionRect.set(x, y,
x + SkIntToScalar(bitmap.width()),
y + SkIntToScalar(bitmap.height()));
target->clipRect(inversionRect);
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
target->restore();
}
}
}

Expand All @@ -278,6 +289,12 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
appendBitmap(bitmap, dst);
} else {
target->drawBitmapRect(bitmap, src, dst, paint);
if (invertBitmaps) {
target->save();
target->clipRect(dst);
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
target->restore();
}
}
}

Expand All @@ -290,13 +307,16 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable

WTF::Vector<const SkBitmap*> *pBitmapsForDecoding;
WTF::Vector<SkRect> *pBitmapRectsForDecoding;
bool invertBitmaps;

BitmapProxyCanvas(SkCanvas* canvas,
WTF::Vector<const SkBitmap*> *pBitmaps,
WTF::Vector<SkRect> *pBitmapRects)
WTF::Vector<SkRect> *pBitmapRects,
bool invert)
: SyncProxyCanvas(canvas)
, pBitmapsForDecoding(pBitmaps)
, pBitmapRectsForDecoding(pBitmapRects)
, invertBitmaps(invert)
{
}

Expand Down Expand Up @@ -342,9 +362,38 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
}
};

#else
class ImageInverter: public SyncProxyCanvas
{
public:

ImageInverter(SkCanvas* canvas): SyncProxyCanvas(canvas) {}

void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
const SkPaint* paint) {
target->drawBitmap(bitmap, x, y, paint);
target->save();
SkRect inversionRect;
inversionRect.set(x, y,
x + SkIntToScalar(bitmap.width()),
y + SkIntToScalar(bitmap.height()));
target->clipRect(inversionRect);
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
target->restore();
}

void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
const SkRect& dst, const SkPaint* paint) {
target->drawBitmapRect(bitmap, src, dst, paint);
target->save();
target->clipRect(dst);
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
target->restore();
}
};
#endif

bool PictureSet::draw(SkCanvas* canvas)
bool PictureSet::draw(SkCanvas* canvas, bool invertColor)
{
validate(__FUNCTION__);
Pictures* first = mPictures.begin();
Expand Down Expand Up @@ -405,11 +454,14 @@ bool PictureSet::draw(SkCanvas* canvas)
uint32_t startTime = getThreadMsec();
#ifdef CACHED_IMAGE_DECODE
{
WTF::OwnPtr<BitmapProxyCanvas> proxyCanvas = BitmapProxyCanvas::create(canvas, &mBitmapsForDecoding, &mBitmapRectsForDecoding);
WTF::OwnPtr<BitmapProxyCanvas> proxyCanvas = BitmapProxyCanvas::create(canvas, &mBitmapsForDecoding, &mBitmapRectsForDecoding, invertColor);
proxyCanvas->drawPicture(*working->mPicture);
}
#else
canvas->drawPicture(*working->mPicture);
SkCanvas* painter = invertColor ? new ImageInverter(canvas) : canvas;
painter->drawPicture(*working->mPicture);
if (invertColor)
delete painter;
#endif
size_t elapsed = working->mElapsed = getThreadMsec() - startTime;
working->mWroteElapsed = true;
Expand Down Expand Up @@ -441,6 +493,8 @@ bool PictureSet::draw(SkCanvas* canvas)
working->mElapsed, working->mBase ? "true" : "false");
}
// dump(__FUNCTION__);
if (invertColor)
canvas->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
return maxElapsed >= MAX_DRAW_TIME;
}

Expand Down
2 changes: 1 addition & 1 deletion WebKit/android/jni/PictureSet.h
Expand Up @@ -70,7 +70,7 @@ namespace android {
// Update mWidth/mHeight, and adds any additional inval region
void checkDimensions(int width, int height, SkRegion* inval);
void clear();
bool draw(SkCanvas* );
bool draw(SkCanvas* , bool invertColor = false);
static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
int height() const { return mHeight; }
bool isEmpty() const; // returns true if empty or only trivial content
Expand Down
24 changes: 23 additions & 1 deletion WebKit/android/jni/WebViewCore.cpp
Expand Up @@ -302,6 +302,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_forwardingTouchEvents = false;
#endif
m_isPaused = false;
m_invertColor = false;

LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");

Expand Down Expand Up @@ -791,7 +792,7 @@ bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
canvas->clipRect(clip, SkRegion::kDifference_Op);
canvas->drawColor(color);
canvas->restoreToCount(sc);
bool tookTooLong = copyContent.draw(canvas);
bool tookTooLong = copyContent.draw(canvas, m_invertColor);
m_contentMutex.lock();
m_content.setDrawTimes(copyContent);
m_contentMutex.unlock();
Expand Down Expand Up @@ -2448,6 +2449,17 @@ void WebViewCore::setBackgroundColor(SkColor c)
view->setTransparent(true);
}

void WebViewCore::setColorInversion(bool invert)
{
if (m_invertColor != invert) {
m_invertColor = invert;
if (invert)
DBG_SET_LOG("color invert active");
else
DBG_SET_LOG("no color invert");
}
}

jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
Expand Down Expand Up @@ -2969,6 +2981,14 @@ static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
viewImpl->setBackgroundColor((SkColor) color);
}

static void SetColorInversion(JNIEnv *env, jobject obj, jboolean invert)
{
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);

viewImpl->setColorInversion(invert);
}

static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
{
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
Expand Down Expand Up @@ -3248,6 +3268,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) SplitContent },
{ "nativeSetBackgroundColor", "(I)V",
(void*) SetBackgroundColor },
{ "nativeSetColorInversion", "(Z)V",
(void*) SetColorInversion },
{ "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
(void*) RegisterURLSchemeAsLocal },
{ "nativeDumpDomTree", "(Z)V",
Expand Down
2 changes: 2 additions & 0 deletions WebKit/android/jni/WebViewCore.h
Expand Up @@ -362,6 +362,7 @@ namespace android {
jobject getWebViewJavaObject();

void setBackgroundColor(SkColor c);
void setColorInversion(bool invert);
void updateFrameCache();
void updateCacheOnNodeChange();
void dumpDomTree(bool);
Expand Down Expand Up @@ -546,6 +547,7 @@ namespace android {
bool m_check_domtree_version;
PageGroup* m_groupForVisitedLinks;
bool m_isPaused;
bool m_invertColor;

SkTDArray<PluginWidgetAndroid*> m_plugins;
WebCore::Timer<WebViewCore> m_pluginInvalTimer;
Expand Down

0 comments on commit 7d65dc4

Please sign in to comment.