Android 4.1 4.2 webkit开启默认缩放设置后meta中target-densitydpi配置会影响其他页面的解决方法
如前文中打开了默认的缩放设置后,当遇到网页内容那个中包含target-densitydpi键值时会导致后续访问的页面的dpi被更改。这是由于webkit在framework层中meta和设置dpi都是调用的updateDefaultDesity()方法导致。
进行追踪发现是mDefaultScale变量的值更改起到了关键作用。即使追踪到webkit底层实现部分,亦不能很好解决该问题,最终通过增加延时更改mDefaultScale值来解决该问题。
1.更改frameworks\base\core\java\android\webkit目录下的WebViewClassic.java文件,修改如下内容:
case UPDATE_ZOOM_DENSITY: {
final float density = (Float) msg.obj;
// Modified by xdtianyu [start]
//mZoomManager.updateDefaultZoomDensity(density);
mZoomManager.updateMetaZoomDensity(density);
// Modified by xdtianyu [end]
break;
}
final float density = (Float) msg.obj;
// Modified by xdtianyu [start]
//mZoomManager.updateDefaultZoomDensity(density);
mZoomManager.updateMetaZoomDensity(density);
// Modified by xdtianyu [end]
break;
}
2.如上所示,在ZoomManager中增加updateMetaZoomDensity()方法:
public void updateDefaultZoomDensity(float density) {
assert density > 0;
if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
// Remember the current zoom density before it gets changed.
final float originalDefault = mDefaultScale;
// set the new default density
mDisplayDensity = density;
setDefaultZoomScale(density);
float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
setZoomScale(mActualScale * scaleChange, true);
}
}
// Add by xdtianyu [start]
public void updateMetaZoomDensity(float density) {
assert density > 0;
if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
// Remember the current zoom density before it gets changed.
final float originalDefault = mDefaultScale;
// set the new default density
mDisplayDensity = density;
setMetaZoomScale(density);
float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
setZoomScale(mActualScale * scaleChange, true);
}
}
private void setMetaZoomScale(float defaultScale) {
final float originalDefault = mDefaultScale;
setDefaultZoomScale(defaultScale);
TimerTask task = new TimerTask() {
public void run() {
mDefaultScale = originalDefault;
}
}
Timer timer = new Timer();
timer.schedule(task, 500);
}
// Add by xdtianyu [end]
private void setDefaultZoomScale(float defaultScale) {
final float originalDefault = mDefaultScale;
mDefaultScale = defaultScale;
mInvDefaultScale = 1 / defaultScale;
mDefaultMaxZoomScale = defaultScale * DEFAULT_MAX_ZOOM_SCALE_FACTOR;
mDefaultMinZoomScale = defaultScale * DEFAULT_MIN_ZOOM_SCALE_FACTOR;
if (originalDefault > 0.0 && mMaxZoomScale > 0.0) {
// Keeps max zoom scale when zoom density changes.
mMaxZoomScale = defaultScale / originalDefault * mMaxZoomScale;
} else {
mMaxZoomScale = mDefaultMaxZoomScale;
}
if (originalDefault > 0.0 && mMinZoomScale > 0.0) {
// Keeps min zoom scale when zoom density changes.
mMinZoomScale = defaultScale / originalDefault * mMinZoomScale;
} else {
mMinZoomScale = mDefaultMinZoomScale;
}
if (!exceedsMinScaleIncrement(mMinZoomScale, mMaxZoomScale)) {
mMaxZoomScale = mMinZoomScale;
}
sanitizeMinMaxScales();
}
assert density > 0;
if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
// Remember the current zoom density before it gets changed.
final float originalDefault = mDefaultScale;
// set the new default density
mDisplayDensity = density;
setDefaultZoomScale(density);
float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
setZoomScale(mActualScale * scaleChange, true);
}
}
// Add by xdtianyu [start]
public void updateMetaZoomDensity(float density) {
assert density > 0;
if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
// Remember the current zoom density before it gets changed.
final float originalDefault = mDefaultScale;
// set the new default density
mDisplayDensity = density;
setMetaZoomScale(density);
float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
setZoomScale(mActualScale * scaleChange, true);
}
}
private void setMetaZoomScale(float defaultScale) {
final float originalDefault = mDefaultScale;
setDefaultZoomScale(defaultScale);
TimerTask task = new TimerTask() {
public void run() {
mDefaultScale = originalDefault;
}
}
Timer timer = new Timer();
timer.schedule(task, 500);
}
// Add by xdtianyu [end]
private void setDefaultZoomScale(float defaultScale) {
final float originalDefault = mDefaultScale;
mDefaultScale = defaultScale;
mInvDefaultScale = 1 / defaultScale;
mDefaultMaxZoomScale = defaultScale * DEFAULT_MAX_ZOOM_SCALE_FACTOR;
mDefaultMinZoomScale = defaultScale * DEFAULT_MIN_ZOOM_SCALE_FACTOR;
if (originalDefault > 0.0 && mMaxZoomScale > 0.0) {
// Keeps max zoom scale when zoom density changes.
mMaxZoomScale = defaultScale / originalDefault * mMaxZoomScale;
} else {
mMaxZoomScale = mDefaultMaxZoomScale;
}
if (originalDefault > 0.0 && mMinZoomScale > 0.0) {
// Keeps min zoom scale when zoom density changes.
mMinZoomScale = defaultScale / originalDefault * mMinZoomScale;
} else {
mMinZoomScale = mDefaultMinZoomScale;
}
if (!exceedsMinScaleIncrement(mMinZoomScale, mMaxZoomScale)) {
mMaxZoomScale = mMinZoomScale;
}
sanitizeMinMaxScales();
}
注意import timer包,至此修改完成。
关于meta在底层的处理则可以参考external\webkit\Source\WebCore\dom目录下的Document.cpp其中部分代码如下所示:
void Document::processArguments(const String& features, void* data, ArgumentsCallback callback)
{
// Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
int keyBegin, keyEnd;
int valueBegin, valueEnd;
int i = 0;
int length = features.length();
String buffer = features.lower();
while (i < length) {
// skip to first non-separator, but don't skip past the end of the string
while (isSeparator(buffer[i])) {
if (i >= length)
break;
i++;
}
keyBegin = i;
// skip to first separator
while (!isSeparator(buffer[i]))
i++;
keyEnd = i;
// skip to first '=', but don't skip past a ',' or the end of the string
while (buffer[i] != '=') {
if (buffer[i] == ',' || i >= length)
break;
i++;
}
// skip to first non-separator, but don't skip past a ',' or the end of the string
while (isSeparator(buffer[i])) {
if (buffer[i] == ',' || i >= length)
break;
i++;
}
valueBegin = i;
// skip to first separator
while (!isSeparator(buffer[i]))
i++;
valueEnd = i;
ASSERT(i <= length);
String keyString = buffer.substring(keyBegin, keyEnd - keyBegin);
String valueString = buffer.substring(valueBegin, valueEnd - valueBegin);
#ifdef ANDROID_META_SUPPORT
if (frame())
frame()->settings()->setMetadataSettings(keyString, valueString);
if (callback && data)
#endif
callback(keyString, valueString, this, data);
}
}
void Document::processViewport(const String& features)
{
ASSERT(!features.isNull());
m_viewportArguments = ViewportArguments();
processArguments(features, (void*)&m_viewportArguments, &setViewportFeature);
Frame* frame = this->frame();
if (!frame || !frame->page())
return;
frame->page()->updateViewportArguments();
}
{
// Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
int keyBegin, keyEnd;
int valueBegin, valueEnd;
int i = 0;
int length = features.length();
String buffer = features.lower();
while (i < length) {
// skip to first non-separator, but don't skip past the end of the string
while (isSeparator(buffer[i])) {
if (i >= length)
break;
i++;
}
keyBegin = i;
// skip to first separator
while (!isSeparator(buffer[i]))
i++;
keyEnd = i;
// skip to first '=', but don't skip past a ',' or the end of the string
while (buffer[i] != '=') {
if (buffer[i] == ',' || i >= length)
break;
i++;
}
// skip to first non-separator, but don't skip past a ',' or the end of the string
while (isSeparator(buffer[i])) {
if (buffer[i] == ',' || i >= length)
break;
i++;
}
valueBegin = i;
// skip to first separator
while (!isSeparator(buffer[i]))
i++;
valueEnd = i;
ASSERT(i <= length);
String keyString = buffer.substring(keyBegin, keyEnd - keyBegin);
String valueString = buffer.substring(valueBegin, valueEnd - valueBegin);
#ifdef ANDROID_META_SUPPORT
if (frame())
frame()->settings()->setMetadataSettings(keyString, valueString);
if (callback && data)
#endif
callback(keyString, valueString, this, data);
}
}
void Document::processViewport(const String& features)
{
ASSERT(!features.isNull());
m_viewportArguments = ViewportArguments();
processArguments(features, (void*)&m_viewportArguments, &setViewportFeature);
Frame* frame = this->frame();
if (!frame || !frame->page())
return;
frame->page()->updateViewportArguments();
}
发表评论