平方X 发表于 2017-9-30 18:24:37

Android 中查找 native 方法及虚线的实现



>本文由平方X发表于平方X网,转载请注明出处。[http://blog.pingfangx.com/2397.html](http://blog.pingfangx.com/2397.html)

在上一篇中简单提了一下(http://blog.pingfangx.com/2385.html)
```
android.graphics.drawable.GradientDrawable#inflate
android.graphics.drawable.GradientDrawable#inflateChildElements
android.graphics.drawable.GradientDrawable#updateGradientDrawableStroke
android.graphics.drawable.GradientDrawable#setStroke(int, android.content.res.ColorStateList, float, float)
android.graphics.drawable.GradientDrawable#setStrokeInternal

      DashPathEffect e = null;
      if (dashWidth > 0) {
            e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
      }
      mStrokePaint.setPathEffect(e);



public class DashPathEffect extends PathEffect {

    public DashPathEffect(float intervals[], float phase) {
      if (intervals.length < 2) {
            throw new ArrayIndexOutOfBoundsException();
      }
      native_instance = nativeCreate(intervals, phase);
    }

    private static native long nativeCreate(float intervals[], float phase);
}

public class PathEffect {

    protected void finalize() throws Throwable {
      nativeDestructor(native_instance);
      native_instance = 0;// Other finalizers can still call us.
    }

    private static native void nativeDestructor(long native_patheffect);
    long native_instance;
}



到了 native 不知道怎么继续了,于是今天查一下。

参考(http://blog.csdn.net/hp910315/article/details/51733410)
他转自(http://gityuan.com/2016/05/28/android-jni/)
方法名android.graphics.DashPathEffect#nativeCreate
转android_graphics_DashPathEffect#nativeCreate
在/framework/base/core/jni/中搜索DashPathEffect
定位到frameworks/base/core/jni/android/graphics/PathEffect.cpp

    android::RegisterMethodsOrDie(env, "android/graphics/DashPathEffect", gDashPathEffectMethods,
                                  NELEM(gDashPathEffectMethods));

然后是
    static const JNINativeMethod gDashPathEffectMethods[] = {
    { "nativeCreate", "([FF)J", (void*)SkPathEffectGlue::Dash_constructor }
};

然后是
frameworks/base/core/jni/android/graphics/PathEffect.cpp
class SkPathEffectGlue {
    ...
      static jlong Dash_constructor(JNIEnv* env, jobject,
                                    jfloatArray intervalArray, jfloat phase) {
      AutoJavaFloatArray autoInterval(env, intervalArray);
      int         count = autoInterval.length() & ~1;// even number
#ifdef SK_SCALAR_IS_FLOAT
      SkScalar*   intervals = autoInterval.ptr();
#else
      #error Need to convert float array to SkScalar array before calling the following function.
#endif
      SkPathEffect* effect = SkDashPathEffect::Make(intervals, count, phase).release();
      return reinterpret_cast<jlong>(effect);
    }
}

接下来Make方法
external/skia/src/effects/SkDashPathEffect.cpp
sk_sp<SkPathEffect> SkDashPathEffect::Make(const SkScalar intervals[], int count, SkScalar phase) {
    if (!SkDashPath::ValidDashPath(phase, intervals, count)) {
      return nullptr;
    }
    return sk_sp<SkPathEffect>(new SkDashPathEffect(intervals, count, phase));
}

构造函数
SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase)
      : fPhase(0)
      , fInitialDashLength(-1)
      , fInitialDashIndex(0)
      , fIntervalLength(0) {
    SkASSERT(intervals);
    SkASSERT(count > 1 && SkIsAlign2(count));

    fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
    fCount = count;
    for (int i = 0; i < count; i++) {
      fIntervals = intervals;
    }

    // set the internal data members
    SkDashPath::CalcDashParameters(phase, fIntervals, fCount,
            &fInitialDashLength, &fInitialDashIndex, &fIntervalLength, &fPhase);
}

CalcDashParameters
external/skia/src/utils/SkDashPath.cpp

void SkDashPath::CalcDashParameters(SkScalar phase, const SkScalar intervals[], int32_t count,
                                    SkScalar* initialDashLength, int32_t* initialDashIndex,
                                    SkScalar* intervalLength, SkScalar* adjustedPhase) {
    SkScalar len = 0;
    for (int i = 0; i < count; i++) {
      len += intervals;
    }
    *intervalLength = len;
    // Adjust phase to be between 0 and len, "flipping" phase if negative.
    // e.g., if len is 100, then phase of -20 (or -120) is equivalent to 80
    if (adjustedPhase) {
      if (phase < 0) {
            phase = -phase;
            if (phase > len) {
                phase = SkScalarMod(phase, len);
            }
            phase = len - phase;

            // Due to finite precision, it's possible that phase == len,
            // even after the subtract (if len >>> phase), so fix that here.
            // This fixes http://crbug.com/124652 .
            SkASSERT(phase <= len);
            if (phase == len) {
                phase = 0;
            }
      } else if (phase >= len) {
            phase = SkScalarMod(phase, len);
      }
      *adjustedPhase = phase;
    }
    SkASSERT(phase >= 0 && phase < len);

    *initialDashLength = find_first_interval(intervals, phase,
                                          initialDashIndex, count);

    SkASSERT(*initialDashLength >= 0);
    SkASSERT(*initialDashIndex >= 0 && *initialDashIndex < count);
}


static SkScalar find_first_interval(const SkScalar intervals[], SkScalar phase,
                                    int32_t* index, int count) {
    for (int i = 0; i < count; ++i) {
      SkScalar gap = intervals;
      if (phase > gap || (phase == gap && gap)) {
            phase -= gap;
      } else {
            *index = i;
            return gap - phase;
      }
    }
    // If we get here, phase "appears" to be larger than our length. This
    // shouldn't happen with perfect precision, but we can accumulate errors
    // during the initial length computation (rounding can make our sum be too
    // big or too small. In that event, we just have to eat the error here.
    *index = 0;
    return intervals;
}


```

好了,到此,我们应该能找到是怎么创建 DashPathEffect 的了,但是问题来了,自己对底层这一块不熟悉,还是不知道怎么画出来的。
所以,还是需要下一篇(也许多年后吧)……




页: [1]
查看完整版本: Android 中查找 native 方法及虚线的实现